@voyant-travel/auth 0.129.0 → 0.131.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +14 -0
  2. package/dist/cloud-broker/members.d.ts +9 -0
  3. package/dist/cloud-broker/members.js +10 -0
  4. package/dist/cloud-broker/members.js.map +1 -1
  5. package/dist/cloud-broker.d.ts +1 -1
  6. package/dist/cloud-broker.js +1 -1
  7. package/dist/cloud-broker.js.map +1 -1
  8. package/dist/identity-access-graph-runtime.js +2 -1
  9. package/dist/identity-access-graph-runtime.js.map +1 -1
  10. package/dist/invitations-routes.js +4 -0
  11. package/dist/invitations-routes.js.map +1 -1
  12. package/dist/local-member-access.d.ts +15 -0
  13. package/dist/local-member-access.js +119 -0
  14. package/dist/local-member-access.js.map +1 -0
  15. package/dist/mcp-runtime.d.ts +9 -0
  16. package/dist/mcp-runtime.js +38 -0
  17. package/dist/mcp-runtime.js.map +1 -0
  18. package/dist/runtime-contributor.js +18 -1
  19. package/dist/runtime-contributor.js.map +1 -1
  20. package/dist/server.d.ts +10 -6
  21. package/dist/server.js +6 -3
  22. package/dist/server.js.map +1 -1
  23. package/dist/team-management-cloud-adapter.d.ts +7 -0
  24. package/dist/team-management-cloud-adapter.js +146 -0
  25. package/dist/team-management-cloud-adapter.js.map +1 -0
  26. package/dist/team-management-local-adapter.d.ts +8 -0
  27. package/dist/team-management-local-adapter.js +285 -0
  28. package/dist/team-management-local-adapter.js.map +1 -0
  29. package/dist/team-management-policy.d.ts +27 -0
  30. package/dist/team-management-policy.js +109 -0
  31. package/dist/team-management-policy.js.map +1 -0
  32. package/dist/team-management-runtime-port.d.ts +60 -0
  33. package/dist/team-management-runtime-port.js +25 -0
  34. package/dist/team-management-runtime-port.js.map +1 -0
  35. package/dist/team-routes.d.ts +3 -3
  36. package/dist/team-routes.js +89 -138
  37. package/dist/team-routes.js.map +1 -1
  38. package/dist/tools.d.ts +58 -0
  39. package/dist/tools.js +226 -0
  40. package/dist/tools.js.map +1 -0
  41. package/dist/voyant.js +262 -7
  42. package/dist/voyant.js.map +1 -1
  43. package/openapi/admin/team.json +42 -74
  44. package/package.json +15 -4
package/dist/server.d.ts CHANGED
@@ -4,6 +4,7 @@ import { type BetterAuthOptions } from "better-auth";
4
4
  import { emailOTP } from "better-auth/plugins";
5
5
  import type { BetterAuthPlugin } from "better-auth/types";
6
6
  import type { AnyPgTable } from "drizzle-orm/pg-core";
7
+ import { createLocalMemberAccessPlugin } from "./local-member-access.js";
7
8
  export declare function getAuthSecret(): string;
8
9
  export type { AccountProfileUpdateHandler, ApiTokenRotationStore, BetterAuthApiTokenManagement, HandleAccountProfileRequestOptions, HandleApiTokenManagementRequestOptions, HandleOrganizationMembersRequestOptions, OrganizationMemberRecord, OrganizationMembersListHandler, OrganizationMembersListInput, } from "./auth-facades.js";
9
10
  export { handleAccountProfileRequest, handleApiTokenManagementRequest, handleOrganizationMembersRequest, } from "./auth-facades.js";
@@ -22,7 +23,11 @@ type ResolvedBetterAuthChangeEmail<UserOptions extends BetterAuthOptions["user"]
22
23
  type ResolvedBetterAuthUserOptions<UserOptions extends BetterAuthOptions["user"]> = Omit<DefinedBetterAuthUserOptions<UserOptions>, "changeEmail"> & {
23
24
  changeEmail: ResolvedBetterAuthChangeEmail<UserOptions>;
24
25
  };
25
- type VoyantBetterAuthPlugins = [ReturnType<typeof apiKey>, ReturnType<typeof emailOTP>];
26
+ type VoyantBetterAuthPlugins = [
27
+ ReturnType<typeof apiKey>,
28
+ ReturnType<typeof emailOTP>,
29
+ ReturnType<typeof createLocalMemberAccessPlugin>
30
+ ];
26
31
  type ResolvedBetterAuthPlugins<Plugins extends BetterAuthPlugin[] | undefined> = Plugins extends BetterAuthPlugin[] ? [...VoyantBetterAuthPlugins, ...Plugins] : VoyantBetterAuthPlugins;
27
32
  export interface DisableSignupWhenUsersExistOptions {
28
33
  /**
@@ -85,11 +90,10 @@ export interface CreateBetterAuthOptions<UserOptions extends BetterAuthOptions["
85
90
  }) => Promise<void>;
86
91
  /**
87
92
  * Better Auth session cookie cache: session data rides in a short-lived
88
- * signed cookie so `getSession` skips the Postgres lookup on most
89
- * requests. Enabled by default with a 5-minute TTL the trade-off is
90
- * that a revoked/expired session can stay usable for up to `maxAge`
91
- * seconds. Pass `false` for revocation-sensitive deployments, or tune
92
- * `maxAge` (seconds).
93
+ * signed cookie. Enabled by default with a 5-minute TTL. Voyant still
94
+ * validates local membership and session existence against Postgres so a
95
+ * deleted session cannot be revived from the cookie cache. Pass `false` to
96
+ * disable payload caching, or tune `maxAge` (seconds).
93
97
  */
94
98
  sessionCookieCache?: false | {
95
99
  maxAge?: number;
package/dist/server.js CHANGED
@@ -5,6 +5,7 @@ import { betterAuth } from "better-auth";
5
5
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
6
6
  import { emailOTP } from "better-auth/plugins";
7
7
  import { sql } from "drizzle-orm";
8
+ import { createLocalMemberAccessPlugin, isLocalMemberDeactivated, isLocalMemberEmailDeactivated, isLocalMemberSessionActive, } from "./local-member-access.js";
8
9
  import { expandTrustedOrigins, getTrustedOrigins } from "./trusted-origins.js";
9
10
  import { isFirstAuthUser, provisionCurrentUserProfile } from "./workspace.js";
10
11
  export function getAuthSecret() {
@@ -122,9 +123,6 @@ export function createBetterAuth(options = {}) {
122
123
  session: {
123
124
  cookieCache: {
124
125
  enabled: true,
125
- // Caps how long a revoked session stays usable from the
126
- // cookie alone; within the window getSession answers from
127
- // the signed cookie with zero DB roundtrips.
128
126
  maxAge: options.sessionCookieCache?.maxAge ?? 300,
129
127
  },
130
128
  },
@@ -182,6 +180,11 @@ export function createBetterAuth(options = {}) {
182
180
  enabled: true,
183
181
  },
184
182
  }),
183
+ createLocalMemberAccessPlugin({
184
+ isEmailDeactivated: (email) => isLocalMemberEmailDeactivated(db, email),
185
+ isSessionActive: (sessionId, userId) => isLocalMemberSessionActive(db, sessionId, userId),
186
+ isUserDeactivated: (userId) => isLocalMemberDeactivated(db, userId),
187
+ }),
185
188
  ...extraPlugins,
186
189
  ],
187
190
  databaseHooks: {
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { apiKey } from \"@better-auth/api-key\"\nimport { getDb } from \"@voyant-travel/db\"\nimport {\n apikeyTable,\n authAccount,\n authSession,\n authUser,\n authVerification,\n} from \"@voyant-travel/db/schema/iam\"\nimport { type BetterAuthOptions, betterAuth } from \"better-auth\"\nimport { drizzleAdapter } from \"better-auth/adapters/drizzle\"\nimport { emailOTP } from \"better-auth/plugins\"\nimport type { BetterAuthPlugin } from \"better-auth/types\"\nimport { sql } from \"drizzle-orm\"\nimport type { AnyPgTable } from \"drizzle-orm/pg-core\"\n\nimport { expandTrustedOrigins, getTrustedOrigins } from \"./trusted-origins.js\"\nimport { isFirstAuthUser, provisionCurrentUserProfile } from \"./workspace.js\"\n\nexport function getAuthSecret(): string {\n const secret = process.env.BETTER_AUTH_SECRET || \"\"\n\n if (!secret || secret.length < 32) {\n throw new Error(\"Missing BETTER_AUTH_SECRET with at least 32 characters\")\n }\n\n return secret\n}\n\nexport type {\n AccountProfileUpdateHandler,\n ApiTokenRotationStore,\n BetterAuthApiTokenManagement,\n HandleAccountProfileRequestOptions,\n HandleApiTokenManagementRequestOptions,\n HandleOrganizationMembersRequestOptions,\n OrganizationMemberRecord,\n OrganizationMembersListHandler,\n OrganizationMembersListInput,\n} from \"./auth-facades.js\"\nexport {\n handleAccountProfileRequest,\n handleApiTokenManagementRequest,\n handleOrganizationMembersRequest,\n} from \"./auth-facades.js\"\n\ntype DefinedBetterAuthUserOptions<UserOptions extends BetterAuthOptions[\"user\"]> =\n UserOptions extends undefined ? Record<PropertyKey, never> : NonNullable<UserOptions>\n\ntype ResolvedBetterAuthChangeEmail<UserOptions extends BetterAuthOptions[\"user\"]> =\n DefinedBetterAuthUserOptions<UserOptions> extends { changeEmail?: infer ChangeEmail }\n ? ChangeEmail extends { enabled: infer Enabled }\n ? Omit<ChangeEmail, \"enabled\"> & { enabled: Enabled }\n : NonNullable<ChangeEmail> & { enabled: true }\n : { enabled: true }\n\ntype ResolvedBetterAuthUserOptions<UserOptions extends BetterAuthOptions[\"user\"]> = Omit<\n DefinedBetterAuthUserOptions<UserOptions>,\n \"changeEmail\"\n> & {\n changeEmail: ResolvedBetterAuthChangeEmail<UserOptions>\n}\n\ntype VoyantBetterAuthPlugins = [ReturnType<typeof apiKey>, ReturnType<typeof emailOTP>]\n\ntype ResolvedBetterAuthPlugins<Plugins extends BetterAuthPlugin[] | undefined> =\n Plugins extends BetterAuthPlugin[]\n ? [...VoyantBetterAuthPlugins, ...Plugins]\n : VoyantBetterAuthPlugins\n\nconst DEFAULT_SIGNUP_BLOCK_SURFACES = [\"admin\"] as const\nconst CUSTOMER_SIGNUP_ENDPOINT_SUFFIXES = [\n \"/sign-up/email\",\n \"/phone-number/verify\",\n \"/sign-in/email-otp\",\n] as const\n\nexport interface DisableSignupWhenUsersExistOptions {\n /**\n * Set to false when the consuming app owns all signup admission checks.\n *\n * Defaults to true.\n */\n enabled?: boolean\n /**\n * User surfaces that should keep the single-tenant signup guard. New users\n * with only other explicit surfaces can still be created by customer-facing\n * auth plugins such as phone OTP.\n *\n * Defaults to [\"admin\"]. Users without an explicit surfaces array are\n * treated as admin users for backward compatibility.\n */\n surfaces?: readonly string[]\n}\n\ntype BetterAuthCreateBeforeResult =\n | boolean\n | undefined\n | {\n data: Record<string, unknown>\n }\n\ntype SignupBlockUserPayload = {\n surfaces?: unknown\n}\n\ntype BetterAuthHookContext = {\n path?: string\n}\n\nfunction normalizeSignupBlockSurfaces(\n options: DisableSignupWhenUsersExistOptions | undefined,\n): readonly string[] {\n return options?.surfaces ?? DEFAULT_SIGNUP_BLOCK_SURFACES\n}\n\nfunction isSignupBlockEnabled(options: DisableSignupWhenUsersExistOptions | undefined): boolean {\n return options?.enabled !== false\n}\n\nfunction normalizeSurfaceList(surfaces: readonly string[] | undefined): readonly string[] {\n if (!surfaces) return []\n\n const normalized = new Set<string>()\n for (const surface of surfaces) {\n const trimmed = surface.trim()\n if (trimmed.length > 0) {\n normalized.add(trimmed)\n }\n }\n return Array.from(normalized)\n}\n\nfunction signupBlockAppliesToUser(\n user: SignupBlockUserPayload | undefined,\n blockedSurfaces: readonly string[],\n): boolean {\n if (blockedSurfaces.length === 0) return false\n\n const surfaces = user?.surfaces\n if (Array.isArray(surfaces)) {\n const explicitSurfaces = surfaces.filter(\n (surface): surface is string => typeof surface === \"string\" && surface.trim().length > 0,\n )\n if (explicitSurfaces.length > 0) {\n return explicitSurfaces.some((surface) => blockedSurfaces.includes(surface.trim()))\n }\n }\n\n if (typeof surfaces === \"string\" && surfaces.trim().length > 0) {\n return blockedSurfaces.includes(surfaces.trim())\n }\n\n return blockedSurfaces.includes(\"admin\")\n}\n\nfunction isCustomerSignupCreate(context: BetterAuthHookContext | null | undefined): boolean {\n const path = context?.path\n if (!path) return false\n\n return CUSTOMER_SIGNUP_ENDPOINT_SUFFIXES.some((suffix) => path.endsWith(suffix))\n}\n\nfunction stampCustomerSignupSurfaces(\n user: SignupBlockUserPayload | undefined,\n context: BetterAuthHookContext | null | undefined,\n surfaces: readonly string[],\n): SignupBlockUserPayload | undefined {\n if (surfaces.length === 0 || !isCustomerSignupCreate(context)) {\n return user\n }\n\n return {\n ...(user ?? {}),\n surfaces,\n }\n}\n\ntype ResolvedCreateBetterAuthOptions<\n UserOptions extends BetterAuthOptions[\"user\"],\n Plugins extends BetterAuthPlugin[] | undefined,\n> = Omit<BetterAuthOptions, \"plugins\" | \"user\"> & {\n plugins: ResolvedBetterAuthPlugins<Plugins>\n user: ResolvedBetterAuthUserOptions<UserOptions>\n}\n\nexport type BetterAuthDrizzleSchema = Record<string, AnyPgTable>\n\nexport interface CreateBetterAuthOptions<\n UserOptions extends BetterAuthOptions[\"user\"] = BetterAuthOptions[\"user\"],\n Plugins extends BetterAuthPlugin[] | undefined = BetterAuthPlugin[] | undefined,\n> {\n db?: ReturnType<typeof getDb>\n secret?: string\n baseURL?: string\n basePath?: string\n trustedOrigins?: string[]\n /**\n * Additional Drizzle tables for Better Auth plugins. The consuming app owns\n * matching migrations for every table passed here.\n */\n extraSchema?: BetterAuthDrizzleSchema\n plugins?: Plugins\n user?: UserOptions\n /**\n * Surfaces stamped on Better Auth customer self-signups before the bundled\n * single-tenant signup guard evaluates the new user. Applies to Better\n * Auth OTP signup endpoints that create a user as part of verification.\n *\n * Leave undefined to preserve Better Auth's raw user payload.\n */\n customerSignupSurfaces?: readonly string[]\n disableSignupWhenUsersExist?: DisableSignupWhenUsersExistOptions\n /** Called when a user requests a password reset. If not provided, logs to console. */\n sendResetPassword?: (data: {\n user: { email: string; name: string }\n url: string\n token: string\n }) => Promise<void>\n /** Called to send a verification OTP. If not provided, logs to console. */\n sendVerificationOTP?: (data: { email: string; otp: string; type: string }) => Promise<void>\n /**\n * Better Auth session cookie cache: session data rides in a short-lived\n * signed cookie so `getSession` skips the Postgres lookup on most\n * requests. Enabled by default with a 5-minute TTL — the trade-off is\n * that a revoked/expired session can stay usable for up to `maxAge`\n * seconds. Pass `false` for revocation-sensitive deployments, or tune\n * `maxAge` (seconds).\n */\n sessionCookieCache?: false | { maxAge?: number }\n /** Better Auth secondary storage, typically Redis/KV, used for distributed rate limits. */\n secondaryStorage?: BetterAuthOptions[\"secondaryStorage\"]\n /** Better Auth rate-limit config. Defaults to secondary storage when present. */\n rateLimit?: BetterAuthOptions[\"rateLimit\"]\n /**\n * Additional Better Auth advanced options. Voyant supplies secure cookies\n * by default except in explicit local development. Set\n * `advanced.useSecureCookies` to override that default.\n */\n advanced?: BetterAuthOptions[\"advanced\"]\n}\n\n/**\n * Framework-agnostic Better Auth factory.\n *\n * Accepts optional overrides for db, secret, baseURL, trustedOrigins.\n * Does NOT depend on Next.js — safe to use in Hono workers, TanStack Start, etc.\n */\nexport function createBetterAuth<\n const UserOptions extends BetterAuthOptions[\"user\"] = undefined,\n const Plugins extends BetterAuthPlugin[] | undefined = undefined,\n>(options: CreateBetterAuthOptions<UserOptions, Plugins> = {}) {\n const db = options.db ?? getDb(\"edge\")\n const secret = options.secret ?? getAuthSecret()\n const baseURL =\n options.baseURL ??\n process.env.BETTER_AUTH_URL ??\n process.env.APP_URL ??\n process.env.NEXT_PUBLIC_APP_URL ??\n \"http://localhost:3000\"\n const trustedOrigins = expandTrustedOrigins(\n options.trustedOrigins ?? getTrustedOrigins(),\n baseURL,\n )\n const extraPlugins = options.plugins ?? []\n const signupBlockSurfaces = normalizeSignupBlockSurfaces(options.disableSignupWhenUsersExist)\n const signupBlockEnabled = isSignupBlockEnabled(options.disableSignupWhenUsersExist)\n const customerSignupSurfaces = normalizeSurfaceList(options.customerSignupSurfaces)\n const schema = {\n user: authUser,\n session: authSession,\n account: authAccount,\n verification: authVerification,\n apikey: apikeyTable,\n ...(options.extraSchema ?? {}),\n } satisfies BetterAuthDrizzleSchema\n const rateLimit =\n options.rateLimit ??\n (options.secondaryStorage\n ? ({\n enabled: true,\n window: 60,\n max: 100,\n storage: \"secondary-storage\",\n } as BetterAuthOptions[\"rateLimit\"])\n : undefined)\n\n const authOptions = {\n appName: \"Voyant\",\n baseURL,\n ...(options.basePath ? { basePath: options.basePath } : {}),\n secret,\n database: drizzleAdapter(db, {\n provider: \"pg\",\n schema,\n }),\n ...(options.secondaryStorage ? { secondaryStorage: options.secondaryStorage } : {}),\n ...(rateLimit ? { rateLimit } : {}),\n ...(options.sessionCookieCache === false\n ? {}\n : {\n session: {\n cookieCache: {\n enabled: true,\n // Caps how long a revoked session stays usable from the\n // cookie alone; within the window getSession answers from\n // the signed cookie with zero DB roundtrips.\n maxAge: options.sessionCookieCache?.maxAge ?? 300,\n },\n },\n }),\n emailAndPassword: {\n enabled: true,\n minPasswordLength: 8,\n maxPasswordLength: 128,\n requireEmailVerification: true,\n revokeSessionsOnPasswordReset: true,\n // eslint-disable-next-line @typescript-eslint/require-await -- owner: auth; existing suppression is intentional pending typed cleanup.\n sendResetPassword:\n options.sendResetPassword ??\n (async ({ user, url }) => {\n console.warn(\n `[Auth] No email provider configured — password reset for ${user.email}: ${url}`,\n )\n }),\n },\n emailVerification: {\n sendOnSignUp: false, // OTP plugin handles this\n autoSignInAfterVerification: true,\n },\n user: {\n ...options.user,\n changeEmail: {\n enabled: true,\n ...options.user?.changeEmail,\n },\n } as ResolvedBetterAuthUserOptions<UserOptions>,\n socialProviders: {\n google: {\n clientId: process.env.GOOGLE_CLIENT_ID || \"\",\n clientSecret: process.env.GOOGLE_CLIENT_SECRET || \"\",\n enabled: Boolean(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET),\n },\n },\n trustedOrigins,\n plugins: [\n apiKey({\n defaultPrefix: \"voy_\",\n apiKeyHeaders: [\"authorization\"],\n requireName: true,\n keyExpiration: {\n defaultExpiresIn: null,\n },\n }),\n emailOTP({\n // eslint-disable-next-line @typescript-eslint/require-await -- owner: auth; existing suppression is intentional pending typed cleanup.\n sendVerificationOTP:\n options.sendVerificationOTP ??\n (async ({ email, otp, type }) => {\n console.warn(`[Auth] OTP for ${email}: ${otp} (${type})`)\n }),\n otpLength: 6,\n expiresIn: 600,\n sendVerificationOnSignUp: true,\n changeEmail: {\n enabled: true,\n },\n }),\n ...extraPlugins,\n ] as ResolvedBetterAuthPlugins<Plugins>,\n databaseHooks: {\n user: {\n create: {\n // Single-tenant: once a user exists, reject any new-user creation.\n // Covers email sign-up AND social-provider sign-up (Google would\n // otherwise auto-create a user on first OAuth callback). Existing\n // social sign-ins still work because this hook only fires on CREATE.\n // Seed scripts do raw drizzle inserts, so they bypass this hook —\n // which is intentional.\n before: async (user, context): Promise<BetterAuthCreateBeforeResult> => {\n const normalizedUser = stampCustomerSignupSurfaces(\n user as SignupBlockUserPayload,\n context as BetterAuthHookContext | null,\n customerSignupSurfaces,\n )\n\n if (\n !signupBlockEnabled ||\n !signupBlockAppliesToUser(normalizedUser, signupBlockSurfaces)\n ) {\n if (normalizedUser === user) {\n return\n }\n return { data: normalizedUser as Record<string, unknown> }\n }\n\n const [row] = await db.select({ count: sql<number>`count(*)::int` }).from(authUser)\n if ((row?.count ?? 0) > 0) {\n throw new Error(\"Sign-up is disabled. Ask an admin to invite you.\")\n }\n\n if (normalizedUser !== user) {\n return { data: normalizedUser as Record<string, unknown> }\n }\n },\n after: async (user, context) => {\n if (\n customerSignupSurfaces.length > 0 &&\n isCustomerSignupCreate(context as BetterAuthHookContext | null)\n ) {\n return\n }\n\n // Single-tenant bootstrap: the very first user to register becomes\n // the super-admin. Runs atomically after the `user` row is\n // inserted, so a simple COUNT(*) = 1 check identifies them.\n await provisionCurrentUserProfile(db, {\n userId: user.id,\n name: user.name,\n image: user.image,\n isSuperAdmin: await isFirstAuthUser(db),\n })\n },\n },\n },\n },\n advanced: {\n ...options.advanced,\n useSecureCookies:\n options.advanced?.useSecureCookies ?? process.env.NODE_ENV !== \"development\",\n },\n } as ResolvedCreateBetterAuthOptions<UserOptions, Plugins>\n\n return betterAuth<ResolvedCreateBetterAuthOptions<UserOptions, Plugins>>(authOptions)\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { apiKey } from \"@better-auth/api-key\"\nimport { getDb } from \"@voyant-travel/db\"\nimport {\n apikeyTable,\n authAccount,\n authSession,\n authUser,\n authVerification,\n} from \"@voyant-travel/db/schema/iam\"\nimport { type BetterAuthOptions, betterAuth } from \"better-auth\"\nimport { drizzleAdapter } from \"better-auth/adapters/drizzle\"\nimport { emailOTP } from \"better-auth/plugins\"\nimport type { BetterAuthPlugin } from \"better-auth/types\"\nimport { sql } from \"drizzle-orm\"\nimport type { AnyPgTable } from \"drizzle-orm/pg-core\"\n\nimport {\n createLocalMemberAccessPlugin,\n isLocalMemberDeactivated,\n isLocalMemberEmailDeactivated,\n isLocalMemberSessionActive,\n} from \"./local-member-access.js\"\nimport { expandTrustedOrigins, getTrustedOrigins } from \"./trusted-origins.js\"\nimport { isFirstAuthUser, provisionCurrentUserProfile } from \"./workspace.js\"\n\nexport function getAuthSecret(): string {\n const secret = process.env.BETTER_AUTH_SECRET || \"\"\n\n if (!secret || secret.length < 32) {\n throw new Error(\"Missing BETTER_AUTH_SECRET with at least 32 characters\")\n }\n\n return secret\n}\n\nexport type {\n AccountProfileUpdateHandler,\n ApiTokenRotationStore,\n BetterAuthApiTokenManagement,\n HandleAccountProfileRequestOptions,\n HandleApiTokenManagementRequestOptions,\n HandleOrganizationMembersRequestOptions,\n OrganizationMemberRecord,\n OrganizationMembersListHandler,\n OrganizationMembersListInput,\n} from \"./auth-facades.js\"\nexport {\n handleAccountProfileRequest,\n handleApiTokenManagementRequest,\n handleOrganizationMembersRequest,\n} from \"./auth-facades.js\"\n\ntype DefinedBetterAuthUserOptions<UserOptions extends BetterAuthOptions[\"user\"]> =\n UserOptions extends undefined ? Record<PropertyKey, never> : NonNullable<UserOptions>\n\ntype ResolvedBetterAuthChangeEmail<UserOptions extends BetterAuthOptions[\"user\"]> =\n DefinedBetterAuthUserOptions<UserOptions> extends { changeEmail?: infer ChangeEmail }\n ? ChangeEmail extends { enabled: infer Enabled }\n ? Omit<ChangeEmail, \"enabled\"> & { enabled: Enabled }\n : NonNullable<ChangeEmail> & { enabled: true }\n : { enabled: true }\n\ntype ResolvedBetterAuthUserOptions<UserOptions extends BetterAuthOptions[\"user\"]> = Omit<\n DefinedBetterAuthUserOptions<UserOptions>,\n \"changeEmail\"\n> & {\n changeEmail: ResolvedBetterAuthChangeEmail<UserOptions>\n}\n\ntype VoyantBetterAuthPlugins = [\n ReturnType<typeof apiKey>,\n ReturnType<typeof emailOTP>,\n ReturnType<typeof createLocalMemberAccessPlugin>,\n]\n\ntype ResolvedBetterAuthPlugins<Plugins extends BetterAuthPlugin[] | undefined> =\n Plugins extends BetterAuthPlugin[]\n ? [...VoyantBetterAuthPlugins, ...Plugins]\n : VoyantBetterAuthPlugins\n\nconst DEFAULT_SIGNUP_BLOCK_SURFACES = [\"admin\"] as const\nconst CUSTOMER_SIGNUP_ENDPOINT_SUFFIXES = [\n \"/sign-up/email\",\n \"/phone-number/verify\",\n \"/sign-in/email-otp\",\n] as const\n\nexport interface DisableSignupWhenUsersExistOptions {\n /**\n * Set to false when the consuming app owns all signup admission checks.\n *\n * Defaults to true.\n */\n enabled?: boolean\n /**\n * User surfaces that should keep the single-tenant signup guard. New users\n * with only other explicit surfaces can still be created by customer-facing\n * auth plugins such as phone OTP.\n *\n * Defaults to [\"admin\"]. Users without an explicit surfaces array are\n * treated as admin users for backward compatibility.\n */\n surfaces?: readonly string[]\n}\n\ntype BetterAuthCreateBeforeResult =\n | boolean\n | undefined\n | {\n data: Record<string, unknown>\n }\n\ntype SignupBlockUserPayload = {\n surfaces?: unknown\n}\n\ntype BetterAuthHookContext = {\n path?: string\n}\n\nfunction normalizeSignupBlockSurfaces(\n options: DisableSignupWhenUsersExistOptions | undefined,\n): readonly string[] {\n return options?.surfaces ?? DEFAULT_SIGNUP_BLOCK_SURFACES\n}\n\nfunction isSignupBlockEnabled(options: DisableSignupWhenUsersExistOptions | undefined): boolean {\n return options?.enabled !== false\n}\n\nfunction normalizeSurfaceList(surfaces: readonly string[] | undefined): readonly string[] {\n if (!surfaces) return []\n\n const normalized = new Set<string>()\n for (const surface of surfaces) {\n const trimmed = surface.trim()\n if (trimmed.length > 0) {\n normalized.add(trimmed)\n }\n }\n return Array.from(normalized)\n}\n\nfunction signupBlockAppliesToUser(\n user: SignupBlockUserPayload | undefined,\n blockedSurfaces: readonly string[],\n): boolean {\n if (blockedSurfaces.length === 0) return false\n\n const surfaces = user?.surfaces\n if (Array.isArray(surfaces)) {\n const explicitSurfaces = surfaces.filter(\n (surface): surface is string => typeof surface === \"string\" && surface.trim().length > 0,\n )\n if (explicitSurfaces.length > 0) {\n return explicitSurfaces.some((surface) => blockedSurfaces.includes(surface.trim()))\n }\n }\n\n if (typeof surfaces === \"string\" && surfaces.trim().length > 0) {\n return blockedSurfaces.includes(surfaces.trim())\n }\n\n return blockedSurfaces.includes(\"admin\")\n}\n\nfunction isCustomerSignupCreate(context: BetterAuthHookContext | null | undefined): boolean {\n const path = context?.path\n if (!path) return false\n\n return CUSTOMER_SIGNUP_ENDPOINT_SUFFIXES.some((suffix) => path.endsWith(suffix))\n}\n\nfunction stampCustomerSignupSurfaces(\n user: SignupBlockUserPayload | undefined,\n context: BetterAuthHookContext | null | undefined,\n surfaces: readonly string[],\n): SignupBlockUserPayload | undefined {\n if (surfaces.length === 0 || !isCustomerSignupCreate(context)) {\n return user\n }\n\n return {\n ...(user ?? {}),\n surfaces,\n }\n}\n\ntype ResolvedCreateBetterAuthOptions<\n UserOptions extends BetterAuthOptions[\"user\"],\n Plugins extends BetterAuthPlugin[] | undefined,\n> = Omit<BetterAuthOptions, \"plugins\" | \"user\"> & {\n plugins: ResolvedBetterAuthPlugins<Plugins>\n user: ResolvedBetterAuthUserOptions<UserOptions>\n}\n\nexport type BetterAuthDrizzleSchema = Record<string, AnyPgTable>\n\nexport interface CreateBetterAuthOptions<\n UserOptions extends BetterAuthOptions[\"user\"] = BetterAuthOptions[\"user\"],\n Plugins extends BetterAuthPlugin[] | undefined = BetterAuthPlugin[] | undefined,\n> {\n db?: ReturnType<typeof getDb>\n secret?: string\n baseURL?: string\n basePath?: string\n trustedOrigins?: string[]\n /**\n * Additional Drizzle tables for Better Auth plugins. The consuming app owns\n * matching migrations for every table passed here.\n */\n extraSchema?: BetterAuthDrizzleSchema\n plugins?: Plugins\n user?: UserOptions\n /**\n * Surfaces stamped on Better Auth customer self-signups before the bundled\n * single-tenant signup guard evaluates the new user. Applies to Better\n * Auth OTP signup endpoints that create a user as part of verification.\n *\n * Leave undefined to preserve Better Auth's raw user payload.\n */\n customerSignupSurfaces?: readonly string[]\n disableSignupWhenUsersExist?: DisableSignupWhenUsersExistOptions\n /** Called when a user requests a password reset. If not provided, logs to console. */\n sendResetPassword?: (data: {\n user: { email: string; name: string }\n url: string\n token: string\n }) => Promise<void>\n /** Called to send a verification OTP. If not provided, logs to console. */\n sendVerificationOTP?: (data: { email: string; otp: string; type: string }) => Promise<void>\n /**\n * Better Auth session cookie cache: session data rides in a short-lived\n * signed cookie. Enabled by default with a 5-minute TTL. Voyant still\n * validates local membership and session existence against Postgres so a\n * deleted session cannot be revived from the cookie cache. Pass `false` to\n * disable payload caching, or tune `maxAge` (seconds).\n */\n sessionCookieCache?: false | { maxAge?: number }\n /** Better Auth secondary storage, typically Redis/KV, used for distributed rate limits. */\n secondaryStorage?: BetterAuthOptions[\"secondaryStorage\"]\n /** Better Auth rate-limit config. Defaults to secondary storage when present. */\n rateLimit?: BetterAuthOptions[\"rateLimit\"]\n /**\n * Additional Better Auth advanced options. Voyant supplies secure cookies\n * by default except in explicit local development. Set\n * `advanced.useSecureCookies` to override that default.\n */\n advanced?: BetterAuthOptions[\"advanced\"]\n}\n\n/**\n * Framework-agnostic Better Auth factory.\n *\n * Accepts optional overrides for db, secret, baseURL, trustedOrigins.\n * Does NOT depend on Next.js — safe to use in Hono workers, TanStack Start, etc.\n */\nexport function createBetterAuth<\n const UserOptions extends BetterAuthOptions[\"user\"] = undefined,\n const Plugins extends BetterAuthPlugin[] | undefined = undefined,\n>(options: CreateBetterAuthOptions<UserOptions, Plugins> = {}) {\n const db = options.db ?? getDb(\"edge\")\n const secret = options.secret ?? getAuthSecret()\n const baseURL =\n options.baseURL ??\n process.env.BETTER_AUTH_URL ??\n process.env.APP_URL ??\n process.env.NEXT_PUBLIC_APP_URL ??\n \"http://localhost:3000\"\n const trustedOrigins = expandTrustedOrigins(\n options.trustedOrigins ?? getTrustedOrigins(),\n baseURL,\n )\n const extraPlugins = options.plugins ?? []\n const signupBlockSurfaces = normalizeSignupBlockSurfaces(options.disableSignupWhenUsersExist)\n const signupBlockEnabled = isSignupBlockEnabled(options.disableSignupWhenUsersExist)\n const customerSignupSurfaces = normalizeSurfaceList(options.customerSignupSurfaces)\n const schema = {\n user: authUser,\n session: authSession,\n account: authAccount,\n verification: authVerification,\n apikey: apikeyTable,\n ...(options.extraSchema ?? {}),\n } satisfies BetterAuthDrizzleSchema\n const rateLimit =\n options.rateLimit ??\n (options.secondaryStorage\n ? ({\n enabled: true,\n window: 60,\n max: 100,\n storage: \"secondary-storage\",\n } as BetterAuthOptions[\"rateLimit\"])\n : undefined)\n\n const authOptions = {\n appName: \"Voyant\",\n baseURL,\n ...(options.basePath ? { basePath: options.basePath } : {}),\n secret,\n database: drizzleAdapter(db, {\n provider: \"pg\",\n schema,\n }),\n ...(options.secondaryStorage ? { secondaryStorage: options.secondaryStorage } : {}),\n ...(rateLimit ? { rateLimit } : {}),\n ...(options.sessionCookieCache === false\n ? {}\n : {\n session: {\n cookieCache: {\n enabled: true,\n maxAge: options.sessionCookieCache?.maxAge ?? 300,\n },\n },\n }),\n emailAndPassword: {\n enabled: true,\n minPasswordLength: 8,\n maxPasswordLength: 128,\n requireEmailVerification: true,\n revokeSessionsOnPasswordReset: true,\n // eslint-disable-next-line @typescript-eslint/require-await -- owner: auth; existing suppression is intentional pending typed cleanup.\n sendResetPassword:\n options.sendResetPassword ??\n (async ({ user, url }) => {\n console.warn(\n `[Auth] No email provider configured — password reset for ${user.email}: ${url}`,\n )\n }),\n },\n emailVerification: {\n sendOnSignUp: false, // OTP plugin handles this\n autoSignInAfterVerification: true,\n },\n user: {\n ...options.user,\n changeEmail: {\n enabled: true,\n ...options.user?.changeEmail,\n },\n } as ResolvedBetterAuthUserOptions<UserOptions>,\n socialProviders: {\n google: {\n clientId: process.env.GOOGLE_CLIENT_ID || \"\",\n clientSecret: process.env.GOOGLE_CLIENT_SECRET || \"\",\n enabled: Boolean(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET),\n },\n },\n trustedOrigins,\n plugins: [\n apiKey({\n defaultPrefix: \"voy_\",\n apiKeyHeaders: [\"authorization\"],\n requireName: true,\n keyExpiration: {\n defaultExpiresIn: null,\n },\n }),\n emailOTP({\n // eslint-disable-next-line @typescript-eslint/require-await -- owner: auth; existing suppression is intentional pending typed cleanup.\n sendVerificationOTP:\n options.sendVerificationOTP ??\n (async ({ email, otp, type }) => {\n console.warn(`[Auth] OTP for ${email}: ${otp} (${type})`)\n }),\n otpLength: 6,\n expiresIn: 600,\n sendVerificationOnSignUp: true,\n changeEmail: {\n enabled: true,\n },\n }),\n createLocalMemberAccessPlugin({\n isEmailDeactivated: (email) => isLocalMemberEmailDeactivated(db, email),\n isSessionActive: (sessionId, userId) => isLocalMemberSessionActive(db, sessionId, userId),\n isUserDeactivated: (userId) => isLocalMemberDeactivated(db, userId),\n }),\n ...extraPlugins,\n ] as ResolvedBetterAuthPlugins<Plugins>,\n databaseHooks: {\n user: {\n create: {\n // Single-tenant: once a user exists, reject any new-user creation.\n // Covers email sign-up AND social-provider sign-up (Google would\n // otherwise auto-create a user on first OAuth callback). Existing\n // social sign-ins still work because this hook only fires on CREATE.\n // Seed scripts do raw drizzle inserts, so they bypass this hook —\n // which is intentional.\n before: async (user, context): Promise<BetterAuthCreateBeforeResult> => {\n const normalizedUser = stampCustomerSignupSurfaces(\n user as SignupBlockUserPayload,\n context as BetterAuthHookContext | null,\n customerSignupSurfaces,\n )\n\n if (\n !signupBlockEnabled ||\n !signupBlockAppliesToUser(normalizedUser, signupBlockSurfaces)\n ) {\n if (normalizedUser === user) {\n return\n }\n return { data: normalizedUser as Record<string, unknown> }\n }\n\n const [row] = await db.select({ count: sql<number>`count(*)::int` }).from(authUser)\n if ((row?.count ?? 0) > 0) {\n throw new Error(\"Sign-up is disabled. Ask an admin to invite you.\")\n }\n\n if (normalizedUser !== user) {\n return { data: normalizedUser as Record<string, unknown> }\n }\n },\n after: async (user, context) => {\n if (\n customerSignupSurfaces.length > 0 &&\n isCustomerSignupCreate(context as BetterAuthHookContext | null)\n ) {\n return\n }\n\n // Single-tenant bootstrap: the very first user to register becomes\n // the super-admin. Runs atomically after the `user` row is\n // inserted, so a simple COUNT(*) = 1 check identifies them.\n await provisionCurrentUserProfile(db, {\n userId: user.id,\n name: user.name,\n image: user.image,\n isSuperAdmin: await isFirstAuthUser(db),\n })\n },\n },\n },\n },\n advanced: {\n ...options.advanced,\n useSecureCookies:\n options.advanced?.useSecureCookies ?? process.env.NODE_ENV !== \"development\",\n },\n } as ResolvedCreateBetterAuthOptions<UserOptions, Plugins>\n\n return betterAuth<ResolvedCreateBetterAuthOptions<UserOptions, Plugins>>(authOptions)\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { type CloudAdminInvitation, type CloudAdminMember } from "./cloud-broker.js";
2
+ import type { IdentityAccessRuntimeProvider } from "./identity-access-runtime-port.js";
3
+ import { type TeamManagementAdapter } from "./team-management-policy.js";
4
+ import type { TeamInvitationDto, TeamMemberDto } from "./team-management-runtime-port.js";
5
+ export declare function cloudTeamMemberDto(member: CloudAdminMember): TeamMemberDto;
6
+ export declare function cloudTeamInvitationDto(invitation: CloudAdminInvitation): TeamInvitationDto;
7
+ export declare function createCloudTeamManagementAdapter(identityAccess: IdentityAccessRuntimeProvider): TeamManagementAdapter;
@@ -0,0 +1,146 @@
1
+ import { cloudAuthUserLinks } from "@voyant-travel/db/schema/iam";
2
+ import { eq } from "drizzle-orm";
3
+ import { inviteCloudAdminMember, listCloudAdminInvitations, listCloudAdminMemberRoles, listCloudAdminMembers, revokeCloudAdminInvitation, setCloudAdminMemberAccess, setCloudAdminMemberRole, } from "./cloud-broker.js";
4
+ import { TeamManagementError } from "./team-management-policy.js";
5
+ function roleLevel(roleId) {
6
+ switch (roleId.trim().toLowerCase()) {
7
+ case "owner":
8
+ return 40;
9
+ case "admin":
10
+ return 30;
11
+ case "editor":
12
+ case "member":
13
+ return 20;
14
+ case "viewer":
15
+ case "guest":
16
+ return 10;
17
+ default:
18
+ return 0;
19
+ }
20
+ }
21
+ export function cloudTeamMemberDto(member) {
22
+ const roleId = member.roleSlug ?? "member";
23
+ return {
24
+ id: member.membershipId,
25
+ email: member.email,
26
+ name: member.name ?? null,
27
+ roleId,
28
+ roleName: member.roleName ?? roleId,
29
+ status: member.hasDeploymentAccess && member.status.toLowerCase() === "active"
30
+ ? "active"
31
+ : "deactivated",
32
+ joinedAt: member.createdAt ?? null,
33
+ lastActivityAt: member.lastActivityAt ?? null,
34
+ };
35
+ }
36
+ export function cloudTeamInvitationDto(invitation) {
37
+ const roleId = invitation.roleSlug ?? "member";
38
+ return {
39
+ id: invitation.id,
40
+ email: invitation.email,
41
+ roleId,
42
+ roleName: invitation.roleName ?? roleId,
43
+ status: invitation.state,
44
+ createdAt: invitation.createdAt,
45
+ expiresAt: invitation.expiresAt,
46
+ };
47
+ }
48
+ function createdInvitationDto(invitation) {
49
+ return {
50
+ ...cloudTeamInvitationDto(invitation),
51
+ acceptUrl: invitation.acceptInvitationUrl || null,
52
+ };
53
+ }
54
+ async function resolveCloudRequest(identityAccess, context) {
55
+ const deployment = identityAccess.resolveDeployment(context.bindings);
56
+ if (!deployment.cloudAdminMembers) {
57
+ throw new TeamManagementError("not_configured", "Voyant Cloud team management is not configured.", 501);
58
+ }
59
+ const [link] = await context.db
60
+ .select({ providerAccountId: cloudAuthUserLinks.providerAccountId })
61
+ .from(cloudAuthUserLinks)
62
+ .where(eq(cloudAuthUserLinks.userId, context.userId))
63
+ .limit(1);
64
+ if (!link?.providerAccountId) {
65
+ throw new TeamManagementError("forbidden", "No Cloud identity is linked to this session.");
66
+ }
67
+ return {
68
+ config: deployment.cloudAdminMembers,
69
+ actingWorkosUserId: link.providerAccountId,
70
+ actingExternalUserId: link.providerAccountId,
71
+ };
72
+ }
73
+ export function createCloudTeamManagementAdapter(identityAccess) {
74
+ return {
75
+ async getActor(context) {
76
+ const request = await resolveCloudRequest(identityAccess, context);
77
+ const actor = (await listCloudAdminMembers(request)).find((member) => member.externalUserId === request.actingExternalUserId);
78
+ if (!actor?.hasDeploymentAccess) {
79
+ throw new TeamManagementError("forbidden", "The current user cannot manage this team.");
80
+ }
81
+ return { memberId: actor.membershipId, roleId: actor.roleSlug ?? "member" };
82
+ },
83
+ async getCapabilities(_context, actor) {
84
+ const canManage = actor.roleId === "owner" || actor.roleId === "admin";
85
+ return {
86
+ viewRoster: true,
87
+ inviteMembers: canManage,
88
+ manageRoles: canManage,
89
+ activateMembers: canManage,
90
+ deactivateMembers: canManage,
91
+ revokeInvitations: canManage,
92
+ };
93
+ },
94
+ async listMembers(context) {
95
+ return (await listCloudAdminMembers(await resolveCloudRequest(identityAccess, context))).map(cloudTeamMemberDto);
96
+ },
97
+ async listRoles(context) {
98
+ return (await listCloudAdminMemberRoles(await resolveCloudRequest(identityAccess, context))).map((role) => ({ id: role.slug, name: role.name, description: role.description }));
99
+ },
100
+ async listInvitations(context) {
101
+ return (await listCloudAdminInvitations(await resolveCloudRequest(identityAccess, context))).map(cloudTeamInvitationDto);
102
+ },
103
+ async inviteMember(context, input) {
104
+ return createdInvitationDto(await inviteCloudAdminMember({
105
+ ...(await resolveCloudRequest(identityAccess, context)),
106
+ input: {
107
+ email: input.email,
108
+ roleSlug: input.roleId,
109
+ expiresInDays: input.expiresInDays,
110
+ },
111
+ }));
112
+ },
113
+ async revokeInvitation(context, invitationId) {
114
+ await revokeCloudAdminInvitation({
115
+ ...(await resolveCloudRequest(identityAccess, context)),
116
+ invitationId,
117
+ });
118
+ },
119
+ async updateMemberRole(context, memberId, roleId) {
120
+ return cloudTeamMemberDto(await setCloudAdminMemberRole({
121
+ ...(await resolveCloudRequest(identityAccess, context)),
122
+ membershipId: memberId,
123
+ roleSlug: roleId,
124
+ }));
125
+ },
126
+ async deactivateMember(context, memberId) {
127
+ return cloudTeamMemberDto(await setCloudAdminMemberAccess({
128
+ ...(await resolveCloudRequest(identityAccess, context)),
129
+ membershipId: memberId,
130
+ hasAccess: false,
131
+ }));
132
+ },
133
+ async activateMember(context, memberId) {
134
+ return cloudTeamMemberDto(await setCloudAdminMemberAccess({
135
+ ...(await resolveCloudRequest(identityAccess, context)),
136
+ membershipId: memberId,
137
+ hasAccess: true,
138
+ }));
139
+ },
140
+ roleLevel,
141
+ isOwnerRole(roleId) {
142
+ return roleId === "owner";
143
+ },
144
+ };
145
+ }
146
+ //# sourceMappingURL=team-management-cloud-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-management-cloud-adapter.js","sourceRoot":"","sources":["../src/team-management-cloud-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { cloudAuthUserLinks } from \"@voyant-travel/db/schema/iam\"\nimport { eq } from \"drizzle-orm\"\n\nimport {\n type CloudAdminInvitation,\n type CloudAdminMember,\n type CloudAdminMembersRequest,\n inviteCloudAdminMember,\n listCloudAdminInvitations,\n listCloudAdminMemberRoles,\n listCloudAdminMembers,\n revokeCloudAdminInvitation,\n setCloudAdminMemberAccess,\n setCloudAdminMemberRole,\n} from \"./cloud-broker.js\"\nimport type { IdentityAccessRuntimeProvider } from \"./identity-access-runtime-port.js\"\nimport { type TeamManagementAdapter, TeamManagementError } from \"./team-management-policy.js\"\nimport type {\n CreatedTeamInvitationDto,\n TeamInvitationDto,\n TeamManagementCapabilitiesDto,\n TeamManagementRequestContext,\n TeamMemberDto,\n} from \"./team-management-runtime-port.js\"\n\nfunction roleLevel(roleId: string): number {\n switch (roleId.trim().toLowerCase()) {\n case \"owner\":\n return 40\n case \"admin\":\n return 30\n case \"editor\":\n case \"member\":\n return 20\n case \"viewer\":\n case \"guest\":\n return 10\n default:\n return 0\n }\n}\n\nexport function cloudTeamMemberDto(member: CloudAdminMember): TeamMemberDto {\n const roleId = member.roleSlug ?? \"member\"\n return {\n id: member.membershipId,\n email: member.email,\n name: member.name ?? null,\n roleId,\n roleName: member.roleName ?? roleId,\n status:\n member.hasDeploymentAccess && member.status.toLowerCase() === \"active\"\n ? \"active\"\n : \"deactivated\",\n joinedAt: member.createdAt ?? null,\n lastActivityAt: member.lastActivityAt ?? null,\n }\n}\n\nexport function cloudTeamInvitationDto(invitation: CloudAdminInvitation): TeamInvitationDto {\n const roleId = invitation.roleSlug ?? \"member\"\n return {\n id: invitation.id,\n email: invitation.email,\n roleId,\n roleName: invitation.roleName ?? roleId,\n status: invitation.state,\n createdAt: invitation.createdAt,\n expiresAt: invitation.expiresAt,\n }\n}\n\nfunction createdInvitationDto(invitation: CloudAdminInvitation): CreatedTeamInvitationDto {\n return {\n ...cloudTeamInvitationDto(invitation),\n acceptUrl: invitation.acceptInvitationUrl || null,\n }\n}\n\nasync function resolveCloudRequest(\n identityAccess: IdentityAccessRuntimeProvider,\n context: TeamManagementRequestContext,\n): Promise<CloudAdminMembersRequest & { actingExternalUserId: string }> {\n const deployment = identityAccess.resolveDeployment(context.bindings)\n if (!deployment.cloudAdminMembers) {\n throw new TeamManagementError(\n \"not_configured\",\n \"Voyant Cloud team management is not configured.\",\n 501,\n )\n }\n const [link] = await context.db\n .select({ providerAccountId: cloudAuthUserLinks.providerAccountId })\n .from(cloudAuthUserLinks)\n .where(eq(cloudAuthUserLinks.userId, context.userId))\n .limit(1)\n if (!link?.providerAccountId) {\n throw new TeamManagementError(\"forbidden\", \"No Cloud identity is linked to this session.\")\n }\n return {\n config: deployment.cloudAdminMembers,\n actingWorkosUserId: link.providerAccountId,\n actingExternalUserId: link.providerAccountId,\n }\n}\n\nexport function createCloudTeamManagementAdapter(\n identityAccess: IdentityAccessRuntimeProvider,\n): TeamManagementAdapter {\n return {\n async getActor(context) {\n const request = await resolveCloudRequest(identityAccess, context)\n const actor = (await listCloudAdminMembers(request)).find(\n (member) => member.externalUserId === request.actingExternalUserId,\n )\n if (!actor?.hasDeploymentAccess) {\n throw new TeamManagementError(\"forbidden\", \"The current user cannot manage this team.\")\n }\n return { memberId: actor.membershipId, roleId: actor.roleSlug ?? \"member\" }\n },\n async getCapabilities(_context, actor): Promise<TeamManagementCapabilitiesDto> {\n const canManage = actor.roleId === \"owner\" || actor.roleId === \"admin\"\n return {\n viewRoster: true,\n inviteMembers: canManage,\n manageRoles: canManage,\n activateMembers: canManage,\n deactivateMembers: canManage,\n revokeInvitations: canManage,\n }\n },\n async listMembers(context) {\n return (await listCloudAdminMembers(await resolveCloudRequest(identityAccess, context))).map(\n cloudTeamMemberDto,\n )\n },\n async listRoles(context) {\n return (\n await listCloudAdminMemberRoles(await resolveCloudRequest(identityAccess, context))\n ).map((role) => ({ id: role.slug, name: role.name, description: role.description }))\n },\n async listInvitations(context) {\n return (\n await listCloudAdminInvitations(await resolveCloudRequest(identityAccess, context))\n ).map(cloudTeamInvitationDto)\n },\n async inviteMember(context, input) {\n return createdInvitationDto(\n await inviteCloudAdminMember({\n ...(await resolveCloudRequest(identityAccess, context)),\n input: {\n email: input.email,\n roleSlug: input.roleId,\n expiresInDays: input.expiresInDays,\n },\n }),\n )\n },\n async revokeInvitation(context, invitationId) {\n await revokeCloudAdminInvitation({\n ...(await resolveCloudRequest(identityAccess, context)),\n invitationId,\n })\n },\n async updateMemberRole(context, memberId, roleId) {\n return cloudTeamMemberDto(\n await setCloudAdminMemberRole({\n ...(await resolveCloudRequest(identityAccess, context)),\n membershipId: memberId,\n roleSlug: roleId,\n }),\n )\n },\n async deactivateMember(context, memberId) {\n return cloudTeamMemberDto(\n await setCloudAdminMemberAccess({\n ...(await resolveCloudRequest(identityAccess, context)),\n membershipId: memberId,\n hasAccess: false,\n }),\n )\n },\n async activateMember(context, memberId) {\n return cloudTeamMemberDto(\n await setCloudAdminMemberAccess({\n ...(await resolveCloudRequest(identityAccess, context)),\n membershipId: memberId,\n hasAccess: true,\n }),\n )\n },\n roleLevel,\n isOwnerRole(roleId) {\n return roleId === \"owner\"\n },\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { IdentityAccessRuntimeProvider } from "./identity-access-runtime-port.js";
2
+ import { type TeamManagementAdapter } from "./team-management-policy.js";
3
+ export { localProviderIdForStatus } from "./local-member-access.js";
4
+ export declare function createLocalTeamManagementAdapter(identityAccess: IdentityAccessRuntimeProvider): TeamManagementAdapter;
5
+ export declare function localRoleForRedeemedInvitation(metadata: Record<string, unknown> | null): {
6
+ isSuperAdmin: boolean;
7
+ permissions: string[];
8
+ };