Add pre-configured procedures and use them throughout codebase
- Add authedProcedure, superuserProcedure, loginRequestProcedure, orgMemberProcedure in base.ts - Create procedures/me/_base.ts with meRoute = authedProcedure.me - Update all me procedures to use meRoute.X.handler() - Update auth/logout and auth/resend-verification to use authedProcedure - Update all admin procedures to use superuserProcedure - Update all orgs procedures to use authedProcedure This reduces boilerplate and makes middleware usage consistent. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminAuthCompleteLogin = os.admin.auth.completeLogin
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminAuthCompleteLogin =
|
||||
superuserProcedure.admin.auth.completeLogin.handler(
|
||||
async ({ input, context }) => {
|
||||
const email = input.email.toLowerCase();
|
||||
|
||||
// First check if any login request exists for this email
|
||||
@@ -47,4 +47,5 @@ export const adminAuthCompleteLogin = os.admin.auth.completeLogin
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminOrgsCreate = os.admin.orgs.create
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsCreate = superuserProcedure.admin.orgs.create.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, displayName, ownerEmail } = input;
|
||||
|
||||
// Find owner user by email (outside transaction - read-only)
|
||||
@@ -54,4 +53,5 @@ export const adminOrgsCreate = os.admin.orgs.create
|
||||
});
|
||||
|
||||
return { slug };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminOrgsDelete = os.admin.orgs.delete
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsDelete = superuserProcedure.admin.orgs.delete.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Delete org and related records in transaction
|
||||
@@ -34,4 +33,5 @@ export const adminOrgsDelete = os.admin.orgs.delete
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
import { toOrgResponse } from "../helpers.js";
|
||||
|
||||
export const adminOrgsGet = os.admin.orgs.get
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsGet = superuserProcedure.admin.orgs.get.handler(
|
||||
async ({ input, context }) => {
|
||||
const org = await context.db
|
||||
.selectFrom("orgs")
|
||||
.where("slug", "=", input.slug)
|
||||
@@ -18,4 +17,5 @@ export const adminOrgsGet = os.admin.orgs.get
|
||||
throw new ORPCError("NOT_FOUND", { message: "Organization not found" });
|
||||
}
|
||||
return toOrgResponse(org);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
* admin.orgs.list - List all organizations
|
||||
*/
|
||||
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
import { toOrgResponse } from "../helpers.js";
|
||||
|
||||
export const adminOrgsList = os.admin.orgs.list
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const adminOrgsList = superuserProcedure.admin.orgs.list.handler(
|
||||
async ({ context }) => {
|
||||
const orgs = await context.db.selectFrom("orgs").selectAll().execute();
|
||||
return orgs.map(toOrgResponse);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
import { toSiteResponse } from "../helpers.js";
|
||||
|
||||
export const adminOrgsListSites = os.admin.orgs.listSites
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsListSites =
|
||||
superuserProcedure.admin.orgs.listSites.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
const org = await context.db
|
||||
@@ -28,11 +28,11 @@ export const adminOrgsListSites = os.admin.orgs.listSites
|
||||
.execute();
|
||||
|
||||
return sites.map(toSiteResponse);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export const adminOrgsAddSite = os.admin.orgs.addSite
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsAddSite = superuserProcedure.admin.orgs.addSite.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, domain } = input;
|
||||
|
||||
// Use transaction to prevent race condition on site creation
|
||||
@@ -68,11 +68,12 @@ export const adminOrgsAddSite = os.admin.orgs.addSite
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export const adminOrgsRemoveSite = os.admin.orgs.removeSite
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsRemoveSite =
|
||||
superuserProcedure.admin.orgs.removeSite.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, domain } = input;
|
||||
|
||||
const org = await context.db
|
||||
@@ -95,4 +96,5 @@ export const adminOrgsRemoveSite = os.admin.orgs.removeSite
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminOrgsUpdate = os.admin.orgs.update
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminOrgsUpdate = superuserProcedure.admin.orgs.update.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, displayName, logoUrl } = input;
|
||||
|
||||
// Check if there are actual updates to make
|
||||
@@ -48,4 +47,5 @@ export const adminOrgsUpdate = os.admin.orgs.update
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminUsersConfirmEmail = os.admin.users.confirmEmail
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminUsersConfirmEmail =
|
||||
superuserProcedure.admin.users.confirmEmail.handler(
|
||||
async ({ input, context }) => {
|
||||
const result = await context.db
|
||||
.updateTable("users")
|
||||
.set({
|
||||
@@ -22,4 +22,5 @@ export const adminUsersConfirmEmail = os.admin.users.confirmEmail
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminUsersCreate = os.admin.users.create
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminUsersCreate = superuserProcedure.admin.users.create.handler(
|
||||
async ({ input, context }) => {
|
||||
const { email, name, orgSlug, orgRole } = input;
|
||||
const normalizedEmail = email.toLowerCase();
|
||||
|
||||
@@ -61,4 +60,5 @@ export const adminUsersCreate = os.admin.users.create
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
import { toUserResponse } from "../helpers.js";
|
||||
|
||||
export const adminUsersGet = os.admin.users.get
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminUsersGet = superuserProcedure.admin.users.get.handler(
|
||||
async ({ input, context }) => {
|
||||
const user = await context.db
|
||||
.selectFrom("users")
|
||||
.where("email", "=", input.email.toLowerCase())
|
||||
@@ -18,4 +17,5 @@ export const adminUsersGet = os.admin.users.get
|
||||
throw new ORPCError("NOT_FOUND", { message: "User not found" });
|
||||
}
|
||||
return toUserResponse(user);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
* admin.users.list - List all users
|
||||
*/
|
||||
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
import { toUserResponse } from "../helpers.js";
|
||||
|
||||
export const adminUsersList = os.admin.users.list
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const adminUsersList = superuserProcedure.admin.users.list.handler(
|
||||
async ({ context }) => {
|
||||
const users = await context.db.selectFrom("users").selectAll().execute();
|
||||
return users.map(toUserResponse);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { os, superuserMiddleware } from "../../base.js";
|
||||
import { superuserProcedure } from "../../base.js";
|
||||
|
||||
export const adminUsersUpdate = os.admin.users.update
|
||||
.use(superuserMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const adminUsersUpdate = superuserProcedure.admin.users.update.handler(
|
||||
async ({ input, context }) => {
|
||||
const { email, isSuperuser } = input;
|
||||
const normalizedEmail = email.toLowerCase();
|
||||
|
||||
@@ -46,4 +45,5 @@ export const adminUsersUpdate = os.admin.users.update
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { COOKIE_NAMES, deleteCookie } from "../../utils/cookies.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
|
||||
/**
|
||||
* Logout handler
|
||||
@@ -11,9 +11,8 @@ import { authMiddleware, os } from "../base.js";
|
||||
* - Revokes the current session by setting revoked_at to now()
|
||||
* - Clears the session cookie from the response
|
||||
*/
|
||||
export const logout = os.auth.logout
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const logout = authedProcedure.auth.logout.handler(
|
||||
async ({ context }) => {
|
||||
// Revoke the current session
|
||||
await context.db
|
||||
.updateTable("sessions")
|
||||
@@ -25,4 +24,5 @@ export const logout = os.auth.logout
|
||||
deleteCookie(context.resHeaders, COOKIE_NAMES.SESSION_TOKEN);
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -16,11 +16,10 @@ import {
|
||||
generateExpiry,
|
||||
generateSecureBase58Token,
|
||||
} from "../../utils/crypto.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
|
||||
export const resendVerificationEmail = os.auth.resendVerificationEmail
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const resendVerificationEmail =
|
||||
authedProcedure.auth.resendVerificationEmail.handler(async ({ context }) => {
|
||||
// Check if email is already verified
|
||||
if (context.user.emailVerifiedAt !== null) {
|
||||
// Email already verified, return early
|
||||
|
||||
@@ -11,9 +11,7 @@ import type {
|
||||
LoginRequestContext,
|
||||
OrgMemberContext,
|
||||
} from "../context.js";
|
||||
|
||||
// Re-export middlewares and os from the middlewares folder
|
||||
export {
|
||||
import {
|
||||
authMiddleware,
|
||||
loginRequestMiddleware,
|
||||
orgMemberMiddleware,
|
||||
@@ -21,6 +19,21 @@ export {
|
||||
superuserMiddleware,
|
||||
} from "../middlewares/index.js";
|
||||
|
||||
// Re-export middlewares and os
|
||||
export {
|
||||
authMiddleware,
|
||||
loginRequestMiddleware,
|
||||
orgMemberMiddleware,
|
||||
os,
|
||||
superuserMiddleware,
|
||||
};
|
||||
|
||||
// Pre-configured procedures with middleware applied
|
||||
export const authedProcedure = os.use(authMiddleware);
|
||||
export const superuserProcedure = os.use(superuserMiddleware);
|
||||
export const loginRequestProcedure = os.use(loginRequestMiddleware);
|
||||
export const orgMemberProcedure = os.use(orgMemberMiddleware);
|
||||
|
||||
// Type exports for use in procedure files
|
||||
export type {
|
||||
APIContext,
|
||||
|
||||
7
apps/api-server/src/procedures/me/_base.ts
Normal file
7
apps/api-server/src/procedures/me/_base.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Base route for me procedures with auth middleware applied
|
||||
*/
|
||||
|
||||
import { authedProcedure } from "../base.js";
|
||||
|
||||
export const meRoute = authedProcedure.me;
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
hashToken,
|
||||
TOKEN_PREFIX,
|
||||
} from "../../utils/crypto.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/** Token expiration: 365 days */
|
||||
const TOKEN_EXPIRATION_DAYS = 365;
|
||||
@@ -18,9 +18,8 @@ const TOKEN_EXPIRATION_DAYS = 365;
|
||||
* List all API tokens for the current user
|
||||
* Returns token metadata (not the actual token values)
|
||||
*/
|
||||
export const listApiTokens = os.me.apiTokens.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const listApiTokens = meRoute.apiTokens.list.handler(
|
||||
async ({ context }) => {
|
||||
const tokens = await context.db
|
||||
.selectFrom("api_tokens")
|
||||
.select(["id", "name", "last_used_at", "created_at", "expires_at"])
|
||||
@@ -35,15 +34,15 @@ export const listApiTokens = os.me.apiTokens.list
|
||||
createdAt: token.created_at.toISOString(),
|
||||
expiresAt: token.expires_at.toISOString(),
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new API token
|
||||
* Requires superuser status and trusted session
|
||||
*/
|
||||
export const createApiToken = os.me.apiTokens.create
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const createApiToken = meRoute.apiTokens.create.handler(
|
||||
async ({ input, context }) => {
|
||||
// Require superuser status
|
||||
if (!context.user.isSuperuser) {
|
||||
throw new ORPCError("FORBIDDEN", {
|
||||
@@ -85,14 +84,14 @@ export const createApiToken = os.me.apiTokens.create
|
||||
token,
|
||||
expiresAt: expiresAt.toISOString(),
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete an API token
|
||||
*/
|
||||
export const deleteApiToken = os.me.apiTokens.delete
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const deleteApiToken = meRoute.apiTokens.delete.handler(
|
||||
async ({ input, context }) => {
|
||||
const result = await context.db
|
||||
.deleteFrom("api_tokens")
|
||||
.where("id", "=", input.tokenId.toString())
|
||||
@@ -106,4 +105,5 @@ export const deleteApiToken = os.me.apiTokens.delete
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
* Get current user auth status
|
||||
*/
|
||||
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
export const meAuthStatus = os.me.authStatus
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const meAuthStatus = meRoute.authStatus.handler(async ({ context }) => {
|
||||
const user = await context.db
|
||||
.selectFrom("users")
|
||||
.select([
|
||||
@@ -38,4 +36,4 @@ export const meAuthStatus = os.me.authStatus
|
||||
},
|
||||
auth: context.auth,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { COOKIE_NAMES, deleteCookie } from "../../utils/cookies.js";
|
||||
import { verifyPassword } from "../../utils/password.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* Delete account handler
|
||||
@@ -14,9 +14,7 @@ import { authMiddleware, os } from "../base.js";
|
||||
* - Deletes user record (cascades to sessions, devices, passkeys, etc.)
|
||||
* - Clears session cookie
|
||||
*/
|
||||
export const meDelete = os.me.delete
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const meDelete = meRoute.delete.handler(async ({ input, context }) => {
|
||||
const { password } = input;
|
||||
|
||||
// Fetch user with password hash
|
||||
@@ -49,4 +47,4 @@ export const meDelete = os.me.delete
|
||||
deleteCookie(context.resHeaders, COOKIE_NAMES.SESSION_TOKEN);
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
import { defaultDeviceName, requireDeviceFingerprint } from "./helpers.js";
|
||||
|
||||
/**
|
||||
@@ -13,9 +13,8 @@ import { defaultDeviceName, requireDeviceFingerprint } from "./helpers.js";
|
||||
* @throws BAD_REQUEST if no device fingerprint found
|
||||
* @throws NOT_FOUND if device doesn't exist
|
||||
*/
|
||||
export const getDeviceInfo = os.me.devices.getInfo
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const getDeviceInfo = meRoute.devices.getInfo.handler(
|
||||
async ({ context }) => {
|
||||
const fingerprint = requireDeviceFingerprint(context.reqHeaders);
|
||||
|
||||
const device = await context.db
|
||||
@@ -39,7 +38,8 @@ export const getDeviceInfo = os.me.devices.getInfo
|
||||
lastUsedAt: device.last_used_at,
|
||||
isTrusted: device.is_trusted,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Trust device handler
|
||||
@@ -48,9 +48,8 @@ export const getDeviceInfo = os.me.devices.getInfo
|
||||
* @throws BAD_REQUEST if no device fingerprint found
|
||||
* @throws NOT_FOUND if device doesn't exist
|
||||
*/
|
||||
export const trustDevice = os.me.devices.trust
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const trustDevice = meRoute.devices.trust.handler(
|
||||
async ({ input, context }) => {
|
||||
const { name } = input;
|
||||
const fingerprint = requireDeviceFingerprint(context.reqHeaders);
|
||||
|
||||
@@ -66,16 +65,16 @@ export const trustDevice = os.me.devices.trust
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* List trusted devices handler
|
||||
* - Requires authentication
|
||||
* - Returns all trusted devices for the current user
|
||||
*/
|
||||
export const listTrustedDevices = os.me.devices.listTrusted
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const listTrustedDevices = meRoute.devices.listTrusted.handler(
|
||||
async ({ context }) => {
|
||||
const devices = await context.db
|
||||
.selectFrom("user_devices")
|
||||
.selectAll()
|
||||
@@ -94,7 +93,8 @@ export const listTrustedDevices = os.me.devices.listTrusted
|
||||
lastUsedAt: d.last_used_at,
|
||||
isTrusted: d.is_trusted,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Untrust device handler
|
||||
@@ -102,9 +102,8 @@ export const listTrustedDevices = os.me.devices.listTrusted
|
||||
* - Marks device as untrusted by ID
|
||||
* @throws NOT_FOUND if device doesn't exist
|
||||
*/
|
||||
export const untrustDevice = os.me.devices.untrust
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const untrustDevice = meRoute.devices.untrust.handler(
|
||||
async ({ input, context }) => {
|
||||
const result = await context.db
|
||||
.updateTable("user_devices")
|
||||
.set({ is_trusted: false })
|
||||
@@ -117,16 +116,16 @@ export const untrustDevice = os.me.devices.untrust
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke all trusted devices handler
|
||||
* - Requires authentication
|
||||
* - Marks all devices as untrusted
|
||||
*/
|
||||
export const revokeAllTrustedDevices = os.me.devices.revokeAll
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const revokeAllTrustedDevices = meRoute.devices.revokeAll.handler(
|
||||
async ({ context }) => {
|
||||
await context.db
|
||||
.updateTable("user_devices")
|
||||
.set({ is_trusted: false })
|
||||
@@ -134,4 +133,5 @@ export const revokeAllTrustedDevices = os.me.devices.revokeAll
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
* Get current user profile
|
||||
*/
|
||||
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
export const meGet = os.me.get
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const meGet = meRoute.get.handler(async ({ context }) => {
|
||||
const user = await context.db
|
||||
.selectFrom("users")
|
||||
.select([
|
||||
@@ -35,4 +33,4 @@ export const meGet = os.me.get
|
||||
isSuperuser: user.is_superuser,
|
||||
hasPassword: user.password_hash !== null,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* List pending invites for the current user
|
||||
* Only returns invites where the user's email matches and email is verified
|
||||
*/
|
||||
export const listInvites = os.me.invites.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const listInvites = meRoute.invites.list.handler(async ({ context }) => {
|
||||
// Only show invites if email is verified
|
||||
if (!context.user.emailVerifiedAt) {
|
||||
return [];
|
||||
@@ -52,15 +50,14 @@ export const listInvites = os.me.invites.list
|
||||
createdAt: i.created_at,
|
||||
expiresAt: i.expires_at,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a specific invite by ID
|
||||
* Only returns if the invite belongs to the current user's email
|
||||
*/
|
||||
export const getInvite = os.me.invites.get
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const getInvite = meRoute.invites.get.handler(
|
||||
async ({ input, context }) => {
|
||||
const { inviteId } = input;
|
||||
|
||||
// Only show invite if email is verified
|
||||
@@ -111,15 +108,15 @@ export const getInvite = os.me.invites.get
|
||||
createdAt: invite.created_at,
|
||||
expiresAt: invite.expires_at,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Accept an invite by ID
|
||||
* Adds user to org and deletes the invite
|
||||
*/
|
||||
export const acceptInvite = os.me.invites.accept
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const acceptInvite = meRoute.invites.accept.handler(
|
||||
async ({ input, context }) => {
|
||||
const { inviteId } = input;
|
||||
|
||||
// Only allow accepting if email is verified
|
||||
@@ -183,15 +180,15 @@ export const acceptInvite = os.me.invites.accept
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Decline an invite
|
||||
* Deletes the invite if it belongs to the current user's email
|
||||
*/
|
||||
export const declineInvite = os.me.invites.decline
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const declineInvite = meRoute.invites.decline.handler(
|
||||
async ({ input, context }) => {
|
||||
const { inviteId } = input;
|
||||
|
||||
// Delete the invite only if it matches user's email
|
||||
@@ -208,4 +205,5 @@ export const declineInvite = os.me.invites.decline
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { getUserPasskeys } from "../../utils/webauthn.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* List passkeys handler
|
||||
* - Requires authentication
|
||||
* - Returns all passkeys for the current user
|
||||
*/
|
||||
export const listPasskeys = os.me.passkeys.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const listPasskeys = meRoute.passkeys.list.handler(
|
||||
async ({ context }) => {
|
||||
const passkeys = await getUserPasskeys(context.db, context.user.id);
|
||||
|
||||
return passkeys.map((p) => ({
|
||||
@@ -22,7 +21,8 @@ export const listPasskeys = os.me.passkeys.list
|
||||
createdAt: p.createdAt,
|
||||
lastUsedAt: p.lastUsedAt,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Rename passkey handler
|
||||
@@ -30,9 +30,8 @@ export const listPasskeys = os.me.passkeys.list
|
||||
* - Updates passkey name
|
||||
* @throws NOT_FOUND if passkey doesn't exist
|
||||
*/
|
||||
export const renamePasskey = os.me.passkeys.rename
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const renamePasskey = meRoute.passkeys.rename.handler(
|
||||
async ({ input, context }) => {
|
||||
const { passkeyId, name } = input;
|
||||
|
||||
const result = await context.db
|
||||
@@ -47,7 +46,8 @@ export const renamePasskey = os.me.passkeys.rename
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete passkey handler
|
||||
@@ -57,9 +57,8 @@ export const renamePasskey = os.me.passkeys.rename
|
||||
* @throws NOT_FOUND if passkey doesn't exist
|
||||
* @throws BAD_REQUEST if trying to delete last passkey without password
|
||||
*/
|
||||
export const deletePasskey = os.me.passkeys.delete
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const deletePasskey = meRoute.passkeys.delete.handler(
|
||||
async ({ input, context }) => {
|
||||
const { passkeyId } = input;
|
||||
|
||||
// Use transaction to prevent race condition when checking last passkey
|
||||
@@ -96,4 +95,5 @@ export const deletePasskey = os.me.passkeys.delete
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* List sessions handler
|
||||
@@ -11,9 +11,8 @@ import { authMiddleware, os } from "../base.js";
|
||||
* - Returns all sessions for the current user
|
||||
* - Includes isCurrent flag to identify active session
|
||||
*/
|
||||
export const listSessions = os.me.sessions.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const listSessions = meRoute.sessions.list.handler(
|
||||
async ({ context }) => {
|
||||
const sessions = await context.db
|
||||
.selectFrom("sessions")
|
||||
.selectAll()
|
||||
@@ -33,7 +32,8 @@ export const listSessions = os.me.sessions.list
|
||||
isCurrent: s.id === context.session.id,
|
||||
revokedAt: s.revoked_at,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke session handler
|
||||
@@ -42,9 +42,8 @@ export const listSessions = os.me.sessions.list
|
||||
* @throws NOT_FOUND if session doesn't exist
|
||||
* @throws BAD_REQUEST if trying to revoke current session
|
||||
*/
|
||||
export const revokeSession = os.me.sessions.revoke
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const revokeSession = meRoute.sessions.revoke.handler(
|
||||
async ({ input, context }) => {
|
||||
const { sessionId } = input;
|
||||
|
||||
// Prevent revoking current session (use logout instead)
|
||||
@@ -67,16 +66,16 @@ export const revokeSession = os.me.sessions.revoke
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke all sessions handler
|
||||
* - Requires authentication
|
||||
* - Revokes all sessions except current
|
||||
*/
|
||||
export const revokeAllSessions = os.me.sessions.revokeAll
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const revokeAllSessions = meRoute.sessions.revokeAll.handler(
|
||||
async ({ context }) => {
|
||||
// Revoke all sessions except current
|
||||
await context.db
|
||||
.updateTable("sessions")
|
||||
@@ -87,4 +86,5 @@ export const revokeAllSessions = os.me.sessions.revokeAll
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
validatePassword,
|
||||
verifyPassword,
|
||||
} from "../../utils/password.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* Set password handler
|
||||
@@ -16,9 +16,8 @@ import { authMiddleware, os } from "../base.js";
|
||||
* - If user has existing password, currentPassword is required
|
||||
* - Validates new password strength using zxcvbn
|
||||
*/
|
||||
export const setPassword = os.me.setPassword
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const setPassword = meRoute.setPassword.handler(
|
||||
async ({ input, context }) => {
|
||||
const { currentPassword, newPassword } = input;
|
||||
|
||||
// Fetch current password hash
|
||||
@@ -60,4 +59,5 @@ export const setPassword = os.me.setPassword
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
* Setup user profile (initial setup after signup)
|
||||
*/
|
||||
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
export const setupProfile = os.me.setupProfile
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const setupProfile = meRoute.setupProfile.handler(
|
||||
async ({ input, context }) => {
|
||||
const { displayName, fullName, phoneNumber } = input;
|
||||
|
||||
await context.db
|
||||
@@ -21,4 +20,5 @@ export const setupProfile = os.me.setupProfile
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { ProfileUpdate } from "./helpers.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { meRoute } from "./_base.js";
|
||||
|
||||
/**
|
||||
* Update profile handler
|
||||
@@ -11,9 +11,8 @@ import { authMiddleware, os } from "../base.js";
|
||||
* - Allows partial updates to display_name, full_name, phone_number, avatar_url
|
||||
* - Automatically sets updated_at timestamp
|
||||
*/
|
||||
export const updateProfile = os.me.updateProfile
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const updateProfile = meRoute.updateProfile.handler(
|
||||
async ({ input, context }) => {
|
||||
const updates: Partial<ProfileUpdate> = {};
|
||||
if (input.displayName !== undefined) {
|
||||
updates.display_name = input.displayName;
|
||||
@@ -38,4 +37,5 @@ export const updateProfile = os.me.updateProfile
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
import { getMembership, lookupOrgBySlug } from "./helpers.js";
|
||||
|
||||
/**
|
||||
* List all orgs the current user is a member of
|
||||
*/
|
||||
export const orgsList = os.orgs.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
export const orgsList = authedProcedure.orgs.list.handler(
|
||||
async ({ context }) => {
|
||||
const orgs = await context.db
|
||||
.selectFrom("org_members")
|
||||
.innerJoin("orgs", "orgs.id", "org_members.org_id")
|
||||
@@ -33,15 +32,15 @@ export const orgsList = os.orgs.list
|
||||
logoUrl: o.logo_url,
|
||||
createdAt: o.created_at,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new org
|
||||
* The creating user becomes the owner
|
||||
*/
|
||||
export const orgsCreate = os.orgs.create
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const orgsCreate = authedProcedure.orgs.create.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, displayName } = input;
|
||||
|
||||
try {
|
||||
@@ -75,15 +74,15 @@ export const orgsCreate = os.orgs.create
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a single org by slug
|
||||
* Requires membership
|
||||
*/
|
||||
export const orgsGet = os.orgs.get
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const orgsGet = authedProcedure.orgs.get.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and verify membership
|
||||
@@ -97,4 +96,5 @@ export const orgsGet = os.orgs.get
|
||||
logoUrl: org.logoUrl,
|
||||
createdAt: org.createdAt,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -9,16 +9,15 @@ import {
|
||||
generateExpiry,
|
||||
generateSecureBase58Token,
|
||||
} from "../../utils/crypto.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
import { getMembership, lookupOrgBySlug, requireRole } from "./helpers.js";
|
||||
|
||||
/**
|
||||
* List pending invites for an org
|
||||
* Requires admin or owner role
|
||||
*/
|
||||
export const invitesList = os.orgs.invites.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const invitesList = authedProcedure.orgs.invites.list.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and verify admin+ role
|
||||
@@ -52,16 +51,16 @@ export const invitesList = os.orgs.invites.list
|
||||
createdAt: i.created_at,
|
||||
expiresAt: i.expires_at,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Create an invite for a new member
|
||||
* Requires admin or owner role
|
||||
* Only owners can invite new owners (privilege escalation prevention)
|
||||
*/
|
||||
export const invitesCreate = os.orgs.invites.create
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const invitesCreate = authedProcedure.orgs.invites.create.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, email: rawEmail, role } = input;
|
||||
const email = rawEmail.toLowerCase();
|
||||
|
||||
@@ -135,15 +134,15 @@ export const invitesCreate = os.orgs.invites.create
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Cancel a pending invite
|
||||
* Requires admin or owner role
|
||||
*/
|
||||
export const invitesCancel = os.orgs.invites.cancel
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const invitesCancel = authedProcedure.orgs.invites.cancel.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, inviteId } = input;
|
||||
|
||||
// Lookup org and verify admin+ role
|
||||
@@ -163,16 +162,16 @@ export const invitesCancel = os.orgs.invites.cancel
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Accept an invitation
|
||||
* Token-based lookup, requires auth but no org membership
|
||||
* Handles race condition if user is already a member
|
||||
*/
|
||||
export const invitesAccept = os.orgs.invites.accept
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const invitesAccept = authedProcedure.orgs.invites.accept.handler(
|
||||
async ({ input, context }) => {
|
||||
const { token } = input;
|
||||
|
||||
// Find the invite by token (must not be expired)
|
||||
@@ -235,4 +234,5 @@ export const invitesAccept = os.orgs.invites.accept
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
import {
|
||||
countOwners,
|
||||
getMembership,
|
||||
@@ -15,9 +15,8 @@ import {
|
||||
* Update org details
|
||||
* Requires admin or owner role
|
||||
*/
|
||||
export const orgsUpdate = os.orgs.update
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const orgsUpdate = authedProcedure.orgs.update.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, displayName, logoUrl } = input;
|
||||
|
||||
// Lookup org and verify membership with admin+ role
|
||||
@@ -41,16 +40,16 @@ export const orgsUpdate = os.orgs.update
|
||||
.execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete an org
|
||||
* Requires owner role
|
||||
* FK CASCADE handles deleting members, invites, and sites
|
||||
*/
|
||||
export const orgsDelete = os.orgs.delete
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const orgsDelete = authedProcedure.orgs.delete.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and verify ownership
|
||||
@@ -61,16 +60,16 @@ export const orgsDelete = os.orgs.delete
|
||||
await context.db.deleteFrom("orgs").where("id", "=", org.id).execute();
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Leave an org
|
||||
* Cannot leave if you're the only owner
|
||||
* Uses transaction to prevent race condition where multiple owners leave simultaneously
|
||||
*/
|
||||
export const orgsLeave = os.orgs.leave
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const orgsLeave = authedProcedure.orgs.leave.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and get membership
|
||||
@@ -98,4 +97,5 @@ export const orgsLeave = os.orgs.leave
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
import {
|
||||
countOwners,
|
||||
getMembership,
|
||||
@@ -15,9 +15,8 @@ import {
|
||||
* List all members of an org
|
||||
* Any member can view the member list
|
||||
*/
|
||||
export const membersList = os.orgs.members.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const membersList = authedProcedure.orgs.members.list.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and verify membership
|
||||
@@ -48,21 +47,26 @@ export const membersList = os.orgs.members.list
|
||||
role: m.role,
|
||||
createdAt: m.created_at,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Update a member's role
|
||||
* Only owners can change roles
|
||||
* Uses transaction to prevent race condition when demoting owners
|
||||
*/
|
||||
export const membersUpdateRole = os.orgs.members.updateRole
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const membersUpdateRole =
|
||||
authedProcedure.orgs.members.updateRole.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, userId, role: newRole } = input;
|
||||
|
||||
// Lookup org and verify ownership
|
||||
const org = await lookupOrgBySlug(context.db, slug);
|
||||
const membership = await getMembership(context.db, org.id, context.user.id);
|
||||
const membership = await getMembership(
|
||||
context.db,
|
||||
org.id,
|
||||
context.user.id,
|
||||
);
|
||||
requireRole(membership, "owner");
|
||||
|
||||
await context.db.transaction().execute(async (trx) => {
|
||||
@@ -97,16 +101,16 @@ export const membersUpdateRole = os.orgs.members.updateRole
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Remove a member from an org
|
||||
* Owners can remove anyone, admins can only remove members
|
||||
* Uses transaction to prevent race condition when removing owners
|
||||
*/
|
||||
export const membersRemove = os.orgs.members.remove
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const membersRemove = authedProcedure.orgs.members.remove.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug, userId } = input;
|
||||
|
||||
// Lookup org and verify membership
|
||||
@@ -159,4 +163,5 @@ export const membersRemove = os.orgs.members.remove
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
* Org sites procedures - list
|
||||
*/
|
||||
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
import { authedProcedure } from "../base.js";
|
||||
import { getMembership, lookupOrgBySlug } from "./helpers.js";
|
||||
|
||||
/**
|
||||
* List all sites for an org
|
||||
* Any member can view the site list
|
||||
*/
|
||||
export const sitesList = os.orgs.sites.list
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
export const sitesList = authedProcedure.orgs.sites.list.handler(
|
||||
async ({ input, context }) => {
|
||||
const { slug } = input;
|
||||
|
||||
// Lookup org and verify membership
|
||||
@@ -31,4 +30,5 @@ export const sitesList = os.orgs.sites.list
|
||||
domain: s.domain,
|
||||
createdAt: s.created_at,
|
||||
}));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user