@voyant-travel/auth 0.128.3 → 0.130.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 (42) 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/node-runtime.d.ts +1 -0
  16. package/dist/node-runtime.js +2 -7
  17. package/dist/node-runtime.js.map +1 -1
  18. package/dist/runtime-contributor.js +23 -2
  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/voyant.js +67 -3
  39. package/dist/voyant.js.map +1 -1
  40. package/openapi/admin/team.json +42 -74
  41. package/package.json +10 -5
  42. package/dist/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -0,0 +1,109 @@
1
+ export class TeamManagementError extends Error {
2
+ code;
3
+ status;
4
+ constructor(code, message, status = 403) {
5
+ super(message);
6
+ this.code = code;
7
+ this.status = status;
8
+ this.name = "TeamManagementError";
9
+ }
10
+ }
11
+ function requireCapability(capabilities, capability) {
12
+ if (!capabilities[capability]) {
13
+ throw new TeamManagementError("forbidden", "This team-management action is not allowed.");
14
+ }
15
+ }
16
+ async function authorize(adapter, context, capability) {
17
+ const actor = await adapter.getActor(context);
18
+ const capabilities = await adapter.getCapabilities(context, actor);
19
+ requireCapability(capabilities, capability);
20
+ return { actor, capabilities };
21
+ }
22
+ async function mutationState(adapter, context, capability, memberId) {
23
+ const { actor } = await authorize(adapter, context, capability);
24
+ const members = await adapter.listMembers(context);
25
+ const target = members.find((member) => member.id === memberId);
26
+ if (!target) {
27
+ throw new TeamManagementError("member_not_found", "Team member not found.", 404);
28
+ }
29
+ if (target.id === actor.memberId) {
30
+ throw new TeamManagementError("self_change_forbidden", "You cannot change your own role or access.", 409);
31
+ }
32
+ if (adapter.roleLevel(target.roleId) > adapter.roleLevel(actor.roleId)) {
33
+ throw new TeamManagementError("privilege_escalation", "You cannot manage a member with a more privileged role.");
34
+ }
35
+ return { actor, members, target };
36
+ }
37
+ function assertAssignableRole(adapter, actor, roles, roleId) {
38
+ if (!roles.some((role) => role.id === roleId)) {
39
+ throw new TeamManagementError("role_not_found", "Team role not found.", 404);
40
+ }
41
+ if (adapter.roleLevel(roleId) > adapter.roleLevel(actor.roleId)) {
42
+ throw new TeamManagementError("privilege_escalation", "You cannot assign a role above your own privilege level.");
43
+ }
44
+ }
45
+ function assertOwnerRemains(adapter, members, target) {
46
+ if (!adapter.isOwnerRole(target.roleId))
47
+ return;
48
+ const activeOwners = members.filter((member) => member.status === "active" && adapter.isOwnerRole(member.roleId));
49
+ if (activeOwners.length <= 1) {
50
+ throw new TeamManagementError("last_owner", "The last active owner cannot be demoted or deactivated.", 409);
51
+ }
52
+ }
53
+ /** Applies provider-neutral authorization and invariants before invoking an adapter. */
54
+ export function createGuardedTeamManagementProvider(resolveAdapter) {
55
+ return {
56
+ async getCapabilities(context) {
57
+ const adapter = resolveAdapter(context);
58
+ const actor = await adapter.getActor(context);
59
+ return adapter.getCapabilities(context, actor);
60
+ },
61
+ async listMembers(context) {
62
+ const adapter = resolveAdapter(context);
63
+ await authorize(adapter, context, "viewRoster");
64
+ return adapter.listMembers(context);
65
+ },
66
+ async listRoles(context) {
67
+ const adapter = resolveAdapter(context);
68
+ await authorize(adapter, context, "viewRoster");
69
+ return adapter.listRoles(context);
70
+ },
71
+ async listInvitations(context) {
72
+ const adapter = resolveAdapter(context);
73
+ await authorize(adapter, context, "viewRoster");
74
+ return adapter.listInvitations(context);
75
+ },
76
+ async inviteMember(context, input) {
77
+ const adapter = resolveAdapter(context);
78
+ const { actor } = await authorize(adapter, context, "inviteMembers");
79
+ assertAssignableRole(adapter, actor, await adapter.listRoles(context), input.roleId);
80
+ return adapter.inviteMember(context, input);
81
+ },
82
+ async revokeInvitation(context, invitationId) {
83
+ const adapter = resolveAdapter(context);
84
+ await authorize(adapter, context, "revokeInvitations");
85
+ return adapter.revokeInvitation(context, invitationId);
86
+ },
87
+ async updateMemberRole(context, memberId, roleId) {
88
+ const adapter = resolveAdapter(context);
89
+ const { actor, members, target } = await mutationState(adapter, context, "manageRoles", memberId);
90
+ assertAssignableRole(adapter, actor, await adapter.listRoles(context), roleId);
91
+ if (adapter.isOwnerRole(target.roleId) && !adapter.isOwnerRole(roleId)) {
92
+ assertOwnerRemains(adapter, members, target);
93
+ }
94
+ return adapter.updateMemberRole(context, memberId, roleId);
95
+ },
96
+ async deactivateMember(context, memberId) {
97
+ const adapter = resolveAdapter(context);
98
+ const { members, target } = await mutationState(adapter, context, "deactivateMembers", memberId);
99
+ assertOwnerRemains(adapter, members, target);
100
+ return adapter.deactivateMember(context, memberId);
101
+ },
102
+ async activateMember(context, memberId) {
103
+ const adapter = resolveAdapter(context);
104
+ await mutationState(adapter, context, "activateMembers", memberId);
105
+ return adapter.activateMember(context, memberId);
106
+ },
107
+ };
108
+ }
109
+ //# sourceMappingURL=team-management-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-management-policy.js","sourceRoot":"","sources":["../src/team-management-policy.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreatedTeamInvitationDto,\n InviteTeamMemberInput,\n TeamInvitationDto,\n TeamManagementCapabilitiesDto,\n TeamManagementRequestContext,\n TeamManagementRuntimeProvider,\n TeamMemberDto,\n TeamRoleDto,\n} from \"./team-management-runtime-port.js\"\n\nexport type TeamManagementErrorCode =\n | \"forbidden\"\n | \"member_not_found\"\n | \"role_not_found\"\n | \"self_change_forbidden\"\n | \"privilege_escalation\"\n | \"last_owner\"\n | \"activation_unavailable\"\n | \"not_configured\"\n\nexport class TeamManagementError extends Error {\n constructor(\n readonly code: TeamManagementErrorCode,\n message: string,\n readonly status: 400 | 403 | 404 | 409 | 501 = 403,\n ) {\n super(message)\n this.name = \"TeamManagementError\"\n }\n}\n\nexport interface TeamManagementActor {\n memberId: string\n roleId: string\n}\n\nexport interface TeamManagementAdapter {\n getActor(context: TeamManagementRequestContext): Promise<TeamManagementActor>\n getCapabilities(\n context: TeamManagementRequestContext,\n actor: TeamManagementActor,\n ): Promise<TeamManagementCapabilitiesDto>\n listMembers(context: TeamManagementRequestContext): Promise<TeamMemberDto[]>\n listRoles(context: TeamManagementRequestContext): Promise<TeamRoleDto[]>\n listInvitations(context: TeamManagementRequestContext): Promise<TeamInvitationDto[]>\n inviteMember(\n context: TeamManagementRequestContext,\n input: InviteTeamMemberInput,\n ): Promise<CreatedTeamInvitationDto>\n revokeInvitation(context: TeamManagementRequestContext, invitationId: string): Promise<void>\n updateMemberRole(\n context: TeamManagementRequestContext,\n memberId: string,\n roleId: string,\n ): Promise<TeamMemberDto>\n activateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>\n deactivateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>\n roleLevel(roleId: string): number\n isOwnerRole(roleId: string): boolean\n}\n\ntype Capability = keyof TeamManagementCapabilitiesDto\n\nfunction requireCapability(capabilities: TeamManagementCapabilitiesDto, capability: Capability) {\n if (!capabilities[capability]) {\n throw new TeamManagementError(\"forbidden\", \"This team-management action is not allowed.\")\n }\n}\n\nasync function authorize(\n adapter: TeamManagementAdapter,\n context: TeamManagementRequestContext,\n capability: Capability,\n) {\n const actor = await adapter.getActor(context)\n const capabilities = await adapter.getCapabilities(context, actor)\n requireCapability(capabilities, capability)\n return { actor, capabilities }\n}\n\nasync function mutationState(\n adapter: TeamManagementAdapter,\n context: TeamManagementRequestContext,\n capability: Capability,\n memberId: string,\n) {\n const { actor } = await authorize(adapter, context, capability)\n const members = await adapter.listMembers(context)\n const target = members.find((member) => member.id === memberId)\n if (!target) {\n throw new TeamManagementError(\"member_not_found\", \"Team member not found.\", 404)\n }\n if (target.id === actor.memberId) {\n throw new TeamManagementError(\n \"self_change_forbidden\",\n \"You cannot change your own role or access.\",\n 409,\n )\n }\n if (adapter.roleLevel(target.roleId) > adapter.roleLevel(actor.roleId)) {\n throw new TeamManagementError(\n \"privilege_escalation\",\n \"You cannot manage a member with a more privileged role.\",\n )\n }\n return { actor, members, target }\n}\n\nfunction assertAssignableRole(\n adapter: TeamManagementAdapter,\n actor: TeamManagementActor,\n roles: TeamRoleDto[],\n roleId: string,\n) {\n if (!roles.some((role) => role.id === roleId)) {\n throw new TeamManagementError(\"role_not_found\", \"Team role not found.\", 404)\n }\n if (adapter.roleLevel(roleId) > adapter.roleLevel(actor.roleId)) {\n throw new TeamManagementError(\n \"privilege_escalation\",\n \"You cannot assign a role above your own privilege level.\",\n )\n }\n}\n\nfunction assertOwnerRemains(\n adapter: TeamManagementAdapter,\n members: TeamMemberDto[],\n target: TeamMemberDto,\n) {\n if (!adapter.isOwnerRole(target.roleId)) return\n const activeOwners = members.filter(\n (member) => member.status === \"active\" && adapter.isOwnerRole(member.roleId),\n )\n if (activeOwners.length <= 1) {\n throw new TeamManagementError(\n \"last_owner\",\n \"The last active owner cannot be demoted or deactivated.\",\n 409,\n )\n }\n}\n\n/** Applies provider-neutral authorization and invariants before invoking an adapter. */\nexport function createGuardedTeamManagementProvider(\n resolveAdapter: (context: TeamManagementRequestContext) => TeamManagementAdapter,\n): TeamManagementRuntimeProvider {\n return {\n async getCapabilities(context) {\n const adapter = resolveAdapter(context)\n const actor = await adapter.getActor(context)\n return adapter.getCapabilities(context, actor)\n },\n async listMembers(context) {\n const adapter = resolveAdapter(context)\n await authorize(adapter, context, \"viewRoster\")\n return adapter.listMembers(context)\n },\n async listRoles(context) {\n const adapter = resolveAdapter(context)\n await authorize(adapter, context, \"viewRoster\")\n return adapter.listRoles(context)\n },\n async listInvitations(context) {\n const adapter = resolveAdapter(context)\n await authorize(adapter, context, \"viewRoster\")\n return adapter.listInvitations(context)\n },\n async inviteMember(context, input) {\n const adapter = resolveAdapter(context)\n const { actor } = await authorize(adapter, context, \"inviteMembers\")\n assertAssignableRole(adapter, actor, await adapter.listRoles(context), input.roleId)\n return adapter.inviteMember(context, input)\n },\n async revokeInvitation(context, invitationId) {\n const adapter = resolveAdapter(context)\n await authorize(adapter, context, \"revokeInvitations\")\n return adapter.revokeInvitation(context, invitationId)\n },\n async updateMemberRole(context, memberId, roleId) {\n const adapter = resolveAdapter(context)\n const { actor, members, target } = await mutationState(\n adapter,\n context,\n \"manageRoles\",\n memberId,\n )\n assertAssignableRole(adapter, actor, await adapter.listRoles(context), roleId)\n if (adapter.isOwnerRole(target.roleId) && !adapter.isOwnerRole(roleId)) {\n assertOwnerRemains(adapter, members, target)\n }\n return adapter.updateMemberRole(context, memberId, roleId)\n },\n async deactivateMember(context, memberId) {\n const adapter = resolveAdapter(context)\n const { members, target } = await mutationState(\n adapter,\n context,\n \"deactivateMembers\",\n memberId,\n )\n assertOwnerRemains(adapter, members, target)\n return adapter.deactivateMember(context, memberId)\n },\n async activateMember(context, memberId) {\n const adapter = resolveAdapter(context)\n await mutationState(adapter, context, \"activateMembers\", memberId)\n return adapter.activateMember(context, memberId)\n },\n }\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import type { VoyantDb } from "@voyant-travel/hono";
2
+ export type TeamMemberStatus = "active" | "deactivated";
3
+ export type TeamInvitationStatus = "pending" | "accepted" | "expired" | "revoked";
4
+ export interface TeamMemberDto {
5
+ id: string;
6
+ email: string | null;
7
+ name: string | null;
8
+ roleId: string;
9
+ roleName: string;
10
+ status: TeamMemberStatus;
11
+ joinedAt: string | null;
12
+ lastActivityAt: string | null;
13
+ }
14
+ export interface TeamRoleDto {
15
+ id: string;
16
+ name: string;
17
+ description: string | null;
18
+ }
19
+ export interface TeamInvitationDto {
20
+ id: string;
21
+ email: string;
22
+ roleId: string;
23
+ roleName: string;
24
+ status: TeamInvitationStatus;
25
+ createdAt: string;
26
+ expiresAt: string;
27
+ }
28
+ export interface CreatedTeamInvitationDto extends TeamInvitationDto {
29
+ acceptUrl: string | null;
30
+ }
31
+ export interface TeamManagementCapabilitiesDto {
32
+ viewRoster: boolean;
33
+ inviteMembers: boolean;
34
+ manageRoles: boolean;
35
+ activateMembers: boolean;
36
+ deactivateMembers: boolean;
37
+ revokeInvitations: boolean;
38
+ }
39
+ export interface TeamManagementRequestContext {
40
+ bindings: Record<string, unknown>;
41
+ db: VoyantDb;
42
+ userId: string;
43
+ }
44
+ export interface InviteTeamMemberInput {
45
+ email: string;
46
+ roleId: string;
47
+ expiresInDays?: number;
48
+ }
49
+ export interface TeamManagementRuntimeProvider {
50
+ getCapabilities(context: TeamManagementRequestContext): Promise<TeamManagementCapabilitiesDto>;
51
+ listMembers(context: TeamManagementRequestContext): Promise<TeamMemberDto[]>;
52
+ listRoles(context: TeamManagementRequestContext): Promise<TeamRoleDto[]>;
53
+ listInvitations(context: TeamManagementRequestContext): Promise<TeamInvitationDto[]>;
54
+ inviteMember(context: TeamManagementRequestContext, input: InviteTeamMemberInput): Promise<CreatedTeamInvitationDto>;
55
+ revokeInvitation(context: TeamManagementRequestContext, invitationId: string): Promise<void>;
56
+ updateMemberRole(context: TeamManagementRequestContext, memberId: string, roleId: string): Promise<TeamMemberDto>;
57
+ activateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>;
58
+ deactivateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>;
59
+ }
60
+ export declare const teamManagementRuntimePort: import("@voyant-travel/core/project").VoyantPort<TeamManagementRuntimeProvider>;
@@ -0,0 +1,25 @@
1
+ import { definePort } from "@voyant-travel/core/project";
2
+ export const teamManagementRuntimePort = definePort({
3
+ id: "auth.team-management-runtime",
4
+ test(provider) {
5
+ if (provider === null || typeof provider !== "object") {
6
+ throw new Error("auth.team-management-runtime provider must be an object.");
7
+ }
8
+ for (const method of [
9
+ "getCapabilities",
10
+ "listMembers",
11
+ "listRoles",
12
+ "listInvitations",
13
+ "inviteMember",
14
+ "revokeInvitation",
15
+ "updateMemberRole",
16
+ "activateMember",
17
+ "deactivateMember",
18
+ ]) {
19
+ if (typeof provider[method] !== "function") {
20
+ throw new Error(`auth.team-management-runtime provider must implement ${method}().`);
21
+ }
22
+ }
23
+ },
24
+ });
25
+ //# sourceMappingURL=team-management-runtime-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-management-runtime-port.js","sourceRoot":"","sources":["../src/team-management-runtime-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AA6ExD,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAgC;IACjF,EAAE,EAAE,8BAA8B;IAClC,IAAI,CAAC,QAAQ;QACX,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;QAC7E,CAAC;QACD,KAAK,MAAM,MAAM,IAAI;YACnB,iBAAiB;YACjB,aAAa;YACb,WAAW;YACX,iBAAiB;YACjB,cAAc;YACd,kBAAkB;YAClB,kBAAkB;YAClB,gBAAgB;YAChB,kBAAkB;SACV,EAAE,CAAC;YACX,IAAI,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,IAAI,KAAK,CAAC,wDAAwD,MAAM,KAAK,CAAC,CAAA;YACtF,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC,CAAA","sourcesContent":["import { definePort } from \"@voyant-travel/core/project\"\nimport type { VoyantDb } from \"@voyant-travel/hono\"\n\nexport type TeamMemberStatus = \"active\" | \"deactivated\"\nexport type TeamInvitationStatus = \"pending\" | \"accepted\" | \"expired\" | \"revoked\"\n\nexport interface TeamMemberDto {\n id: string\n email: string | null\n name: string | null\n roleId: string\n roleName: string\n status: TeamMemberStatus\n joinedAt: string | null\n lastActivityAt: string | null\n}\n\nexport interface TeamRoleDto {\n id: string\n name: string\n description: string | null\n}\n\nexport interface TeamInvitationDto {\n id: string\n email: string\n roleId: string\n roleName: string\n status: TeamInvitationStatus\n createdAt: string\n expiresAt: string\n}\n\nexport interface CreatedTeamInvitationDto extends TeamInvitationDto {\n acceptUrl: string | null\n}\n\nexport interface TeamManagementCapabilitiesDto {\n viewRoster: boolean\n inviteMembers: boolean\n manageRoles: boolean\n activateMembers: boolean\n deactivateMembers: boolean\n revokeInvitations: boolean\n}\n\nexport interface TeamManagementRequestContext {\n bindings: Record<string, unknown>\n db: VoyantDb\n userId: string\n}\n\nexport interface InviteTeamMemberInput {\n email: string\n roleId: string\n expiresInDays?: number\n}\n\nexport interface TeamManagementRuntimeProvider {\n getCapabilities(context: TeamManagementRequestContext): Promise<TeamManagementCapabilitiesDto>\n listMembers(context: TeamManagementRequestContext): Promise<TeamMemberDto[]>\n listRoles(context: TeamManagementRequestContext): Promise<TeamRoleDto[]>\n listInvitations(context: TeamManagementRequestContext): Promise<TeamInvitationDto[]>\n inviteMember(\n context: TeamManagementRequestContext,\n input: InviteTeamMemberInput,\n ): Promise<CreatedTeamInvitationDto>\n revokeInvitation(context: TeamManagementRequestContext, invitationId: string): Promise<void>\n updateMemberRole(\n context: TeamManagementRequestContext,\n memberId: string,\n roleId: string,\n ): Promise<TeamMemberDto>\n activateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>\n deactivateMember(context: TeamManagementRequestContext, memberId: string): Promise<TeamMemberDto>\n}\n\nexport const teamManagementRuntimePort = definePort<TeamManagementRuntimeProvider>({\n id: \"auth.team-management-runtime\",\n test(provider) {\n if (provider === null || typeof provider !== \"object\") {\n throw new Error(\"auth.team-management-runtime provider must be an object.\")\n }\n for (const method of [\n \"getCapabilities\",\n \"listMembers\",\n \"listRoles\",\n \"listInvitations\",\n \"inviteMember\",\n \"revokeInvitation\",\n \"updateMemberRole\",\n \"activateMember\",\n \"deactivateMember\",\n ] as const) {\n if (typeof provider[method] !== \"function\") {\n throw new Error(`auth.team-management-runtime provider must implement ${method}().`)\n }\n }\n },\n})\n"]}
@@ -1,12 +1,12 @@
1
1
  import { OpenAPIHono } from "@hono/zod-openapi";
2
2
  import { type VoyantDb } from "@voyant-travel/hono";
3
- import type { IdentityAccessRuntimeProvider } from "./identity-access-runtime-port.js";
4
- type IdentityAccessEnv = {
3
+ import type { TeamManagementRuntimeProvider } from "./team-management-runtime-port.js";
4
+ type TeamEnv = {
5
5
  Bindings: Record<string, unknown>;
6
6
  Variables: {
7
7
  userId?: string;
8
8
  db: VoyantDb;
9
9
  };
10
10
  };
11
- export declare function createTeamAdminRoutes(runtime: IdentityAccessRuntimeProvider): OpenAPIHono<IdentityAccessEnv, {}, "/">;
11
+ export declare function createTeamAdminRoutes(runtime: TeamManagementRuntimeProvider): OpenAPIHono<TeamEnv, {}, "/">;
12
12
  export {};
@@ -1,17 +1,12 @@
1
1
  import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
2
- import { cloudAuthUserLinks } from "@voyant-travel/db/schema/iam";
3
2
  import { openApiValidationHook, parseJsonBody } from "@voyant-travel/hono";
4
- import { eq } from "drizzle-orm";
5
- import { CloudAdminMembersError, inviteCloudAdminMember, listCloudAdminInvitations, listCloudAdminMemberRoles, listCloudAdminMembers, revokeCloudAdminInvitation, setCloudAdminMemberAccess, setCloudAdminMemberPermissions, } from "./cloud-broker.js";
3
+ import { TeamManagementError } from "./team-management-policy.js";
6
4
  const inviteSchema = z.object({
7
5
  email: z.string().email(),
8
- roleSlug: z.string().trim().min(1).max(120).optional().nullable(),
6
+ roleId: z.string().trim().min(1).max(120),
9
7
  expiresInDays: z.number().int().min(1).max(30).optional(),
10
8
  });
11
- const accessSchema = z.object({ hasAccess: z.boolean() });
12
- const permissionsSchema = z.object({
13
- permissions: z.array(z.string().trim().min(1).max(120)).max(200),
14
- });
9
+ const roleSchema = z.object({ roleId: z.string().trim().min(1).max(120) });
15
10
  const teamAdminApiId = "@voyant-travel/auth#team.api.admin";
16
11
  const jsonBody = (schema) => ({
17
12
  required: true,
@@ -26,185 +21,141 @@ const teamRoute = (config) => createRoute({
26
21
  ...(config.request ? { request: config.request } : {}),
27
22
  responses: responses(...config.statuses),
28
23
  });
24
+ const capabilitiesRoute = teamRoute({
25
+ method: "get",
26
+ path: "/capabilities",
27
+ operationId: "getTeamManagementCapabilities",
28
+ statuses: [200, 401, 403, 501],
29
+ });
29
30
  const listMembersRoute = teamRoute({
30
31
  method: "get",
31
32
  path: "/members",
32
33
  operationId: "listTeamMembers",
33
- statuses: [200, 401, 403, 404, 501],
34
+ statuses: [200, 401, 403, 501],
34
35
  });
35
36
  const listRolesRoute = teamRoute({
36
37
  method: "get",
37
38
  path: "/roles",
38
39
  operationId: "listTeamRoles",
39
- statuses: [200, 401, 403, 404, 501],
40
+ statuses: [200, 401, 403, 501],
40
41
  });
41
- const listTeamInvitationsRoute = teamRoute({
42
+ const listInvitationsRoute = teamRoute({
42
43
  method: "get",
43
44
  path: "/invitations",
44
45
  operationId: "listTeamInvitations",
45
- statuses: [200, 401, 403, 404, 501],
46
+ statuses: [200, 401, 403, 501],
46
47
  });
47
- const createTeamInvitationRoute = teamRoute({
48
+ const createInvitationRoute = teamRoute({
48
49
  method: "post",
49
50
  path: "/invitations",
50
51
  operationId: "createTeamInvitation",
51
52
  request: { body: jsonBody(inviteSchema) },
52
- statuses: [201, 400, 401, 403, 404, 501],
53
+ statuses: [201, 400, 401, 403, 404, 409, 501],
53
54
  });
54
- const revokeTeamInvitationRoute = teamRoute({
55
+ const revokeInvitationRoute = teamRoute({
55
56
  method: "delete",
56
57
  path: "/invitations/{invitationId}",
57
58
  operationId: "revokeTeamInvitation",
58
59
  request: { params: z.object({ invitationId: z.string() }) },
59
60
  statuses: [204, 401, 403, 404, 501],
60
61
  });
61
- const setTeamMemberAccessRoute = teamRoute({
62
+ const updateRoleRoute = teamRoute({
62
63
  method: "put",
63
- path: "/members/{membershipId}/access",
64
- operationId: "setTeamMemberAccess",
64
+ path: "/members/{memberId}/role",
65
+ operationId: "updateTeamMemberRole",
65
66
  request: {
66
- params: z.object({ membershipId: z.string() }),
67
- body: jsonBody(accessSchema),
67
+ params: z.object({ memberId: z.string() }),
68
+ body: jsonBody(roleSchema),
68
69
  },
69
- statuses: [200, 400, 401, 403, 404, 501],
70
+ statuses: [200, 400, 401, 403, 404, 409, 501],
71
+ });
72
+ const deactivateMemberRoute = teamRoute({
73
+ method: "delete",
74
+ path: "/members/{memberId}",
75
+ operationId: "deactivateTeamMember",
76
+ request: { params: z.object({ memberId: z.string() }) },
77
+ statuses: [200, 401, 403, 404, 409, 501],
70
78
  });
71
- const setTeamMemberPermissionsRoute = teamRoute({
79
+ const activateMemberRoute = teamRoute({
72
80
  method: "put",
73
- path: "/members/{membershipId}/permissions",
74
- operationId: "setTeamMemberPermissions",
75
- request: {
76
- params: z.object({ membershipId: z.string() }),
77
- body: jsonBody(permissionsSchema),
78
- },
79
- statuses: [200, 400, 401, 403, 404, 501],
81
+ path: "/members/{memberId}/activation",
82
+ operationId: "activateTeamMember",
83
+ request: { params: z.object({ memberId: z.string() }) },
84
+ statuses: [200, 401, 403, 404, 409, 501],
80
85
  });
81
- async function resolveActingWorkosUserId(db, userId) {
82
- const [link] = await db
83
- .select({ providerAccountId: cloudAuthUserLinks.providerAccountId })
84
- .from(cloudAuthUserLinks)
85
- .where(eq(cloudAuthUserLinks.userId, userId))
86
- .limit(1);
87
- return link?.providerAccountId ?? null;
86
+ function requestContext(c) {
87
+ const userId = c.get("userId");
88
+ if (!userId)
89
+ return c.json({ error: "Unauthorized" }, 401);
90
+ return { bindings: c.env, db: c.get("db"), userId };
91
+ }
92
+ function handleError(c, error) {
93
+ if (error instanceof TeamManagementError) {
94
+ return c.json({ error: error.message, code: error.code }, error.status);
95
+ }
96
+ if (error instanceof Error &&
97
+ "status" in error &&
98
+ typeof error.status === "number" &&
99
+ error.status >= 400 &&
100
+ error.status <= 599) {
101
+ return c.json({ error: error.message }, error.status);
102
+ }
103
+ throw error;
88
104
  }
89
105
  export function createTeamAdminRoutes(runtime) {
90
106
  const routes = new OpenAPIHono({ defaultHook: openApiValidationHook });
91
- const resolveContext = async (c) => {
92
- const deployment = runtime.resolveDeployment(c.env);
93
- if (deployment.authMode !== "voyant-cloud")
94
- return c.json({ error: "Not found" }, 404);
95
- const userId = c.get("userId");
96
- if (!userId)
97
- return c.json({ error: "Unauthorized" }, 401);
98
- if (!deployment.cloudAdminMembers) {
99
- return c.json({ error: "Voyant Cloud member management is not configured" }, 501);
100
- }
101
- const actingWorkosUserId = await resolveActingWorkosUserId(c.get("db"), userId);
102
- if (!actingWorkosUserId) {
103
- return c.json({ error: "No Voyant Cloud identity for this session" }, 403);
104
- }
105
- return { config: deployment.cloudAdminMembers, actingWorkosUserId };
106
- };
107
- const handleError = (c, error) => {
108
- if (error instanceof CloudAdminMembersError) {
109
- return c.json({ error: error.reason ?? error.message }, error.status);
110
- }
111
- throw error;
112
- };
113
- routes.openapi(listMembersRoute, async (c) => {
114
- const context = await resolveContext(c);
107
+ const run = async (c, operation) => {
108
+ const context = requestContext(c);
115
109
  if (context instanceof Response)
116
110
  return context;
117
111
  try {
118
- return c.json({ data: await listCloudAdminMembers(context) });
112
+ return await operation(context);
119
113
  }
120
114
  catch (error) {
121
115
  return handleError(c, error);
122
116
  }
117
+ };
118
+ routes.openapi(capabilitiesRoute, async (c) => {
119
+ const result = await run(c, (context) => runtime.getCapabilities(context));
120
+ return result instanceof Response ? result : c.json({ data: result });
121
+ });
122
+ routes.openapi(listMembersRoute, async (c) => {
123
+ const result = await run(c, (context) => runtime.listMembers(context));
124
+ return result instanceof Response ? result : c.json({ data: result });
123
125
  });
124
126
  routes.openapi(listRolesRoute, async (c) => {
125
- const context = await resolveContext(c);
126
- if (context instanceof Response)
127
- return context;
128
- try {
129
- return c.json({ data: await listCloudAdminMemberRoles(context) });
130
- }
131
- catch (error) {
132
- return handleError(c, error);
133
- }
127
+ const result = await run(c, (context) => runtime.listRoles(context));
128
+ return result instanceof Response ? result : c.json({ data: result });
134
129
  });
135
- routes.openapi(listTeamInvitationsRoute, async (c) => {
136
- const context = await resolveContext(c);
137
- if (context instanceof Response)
138
- return context;
139
- try {
140
- return c.json({ data: await listCloudAdminInvitations(context) });
141
- }
142
- catch (error) {
143
- return handleError(c, error);
144
- }
130
+ routes.openapi(listInvitationsRoute, async (c) => {
131
+ const result = await run(c, (context) => runtime.listInvitations(context));
132
+ return result instanceof Response ? result : c.json({ data: result });
145
133
  });
146
- routes.openapi(createTeamInvitationRoute, async (c) => {
147
- const context = await resolveContext(c);
148
- if (context instanceof Response)
149
- return context;
134
+ routes.openapi(createInvitationRoute, async (c) => {
150
135
  const input = await parseJsonBody(c, inviteSchema);
151
- try {
152
- return c.json({ data: await inviteCloudAdminMember({ ...context, input }) }, 201);
153
- }
154
- catch (error) {
155
- return handleError(c, error);
156
- }
136
+ const result = await run(c, (context) => runtime.inviteMember(context, input));
137
+ return result instanceof Response ? result : c.json({ data: result }, 201);
157
138
  });
158
- routes.openapi(revokeTeamInvitationRoute, async (c) => {
159
- const context = await resolveContext(c);
160
- if (context instanceof Response)
161
- return context;
162
- try {
163
- await revokeCloudAdminInvitation({
164
- ...context,
165
- invitationId: c.req.param("invitationId"),
166
- });
167
- return c.body(null, 204);
168
- }
169
- catch (error) {
170
- return handleError(c, error);
171
- }
139
+ routes.openapi(revokeInvitationRoute, async (c) => {
140
+ const { invitationId } = c.req.param();
141
+ const result = await run(c, (context) => runtime.revokeInvitation(context, invitationId));
142
+ return result instanceof Response ? result : c.body(null, 204);
172
143
  });
173
- routes.openapi(setTeamMemberAccessRoute, async (c) => {
174
- const context = await resolveContext(c);
175
- if (context instanceof Response)
176
- return context;
177
- const input = await parseJsonBody(c, accessSchema);
178
- try {
179
- return c.json({
180
- data: await setCloudAdminMemberAccess({
181
- ...context,
182
- membershipId: c.req.param("membershipId"),
183
- hasAccess: input.hasAccess,
184
- }),
185
- });
186
- }
187
- catch (error) {
188
- return handleError(c, error);
189
- }
144
+ routes.openapi(updateRoleRoute, async (c) => {
145
+ const { memberId } = c.req.param();
146
+ const input = await parseJsonBody(c, roleSchema);
147
+ const result = await run(c, (context) => runtime.updateMemberRole(context, memberId, input.roleId));
148
+ return result instanceof Response ? result : c.json({ data: result });
190
149
  });
191
- routes.openapi(setTeamMemberPermissionsRoute, async (c) => {
192
- const context = await resolveContext(c);
193
- if (context instanceof Response)
194
- return context;
195
- const input = await parseJsonBody(c, permissionsSchema);
196
- try {
197
- return c.json({
198
- data: await setCloudAdminMemberPermissions({
199
- ...context,
200
- membershipId: c.req.param("membershipId"),
201
- permissions: input.permissions,
202
- }),
203
- });
204
- }
205
- catch (error) {
206
- return handleError(c, error);
207
- }
150
+ routes.openapi(deactivateMemberRoute, async (c) => {
151
+ const { memberId } = c.req.param();
152
+ const result = await run(c, (context) => runtime.deactivateMember(context, memberId));
153
+ return result instanceof Response ? result : c.json({ data: result });
154
+ });
155
+ routes.openapi(activateMemberRoute, async (c) => {
156
+ const { memberId } = c.req.param();
157
+ const result = await run(c, (context) => runtime.activateMember(context, memberId));
158
+ return result instanceof Response ? result : c.json({ data: result });
208
159
  });
209
160
  return routes;
210
161
  }
@@ -1 +1 @@
1
- {"version":3,"file":"team-routes.js","sourceRoot":"","sources":["../src/team-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRoute, OpenAPIHono, z } from \"@hono/zod-openapi\"\nimport { cloudAuthUserLinks } from \"@voyant-travel/db/schema/iam\"\nimport { openApiValidationHook, parseJsonBody, type VoyantDb } from \"@voyant-travel/hono\"\nimport { eq } from \"drizzle-orm\"\nimport type { Context } from \"hono\"\n\nimport {\n type CloudAdminMembersConfig,\n CloudAdminMembersError,\n inviteCloudAdminMember,\n listCloudAdminInvitations,\n listCloudAdminMemberRoles,\n listCloudAdminMembers,\n revokeCloudAdminInvitation,\n setCloudAdminMemberAccess,\n setCloudAdminMemberPermissions,\n} from \"./cloud-broker.js\"\nimport type { IdentityAccessRuntimeProvider } from \"./identity-access-runtime-port.js\"\n\ntype IdentityAccessEnv = {\n Bindings: Record<string, unknown>\n Variables: { userId?: string; db: VoyantDb }\n}\ntype TeamContext = { config: CloudAdminMembersConfig; actingWorkosUserId: string }\ntype TeamRouteContext = Context<IdentityAccessEnv>\n\nconst inviteSchema = z.object({\n email: z.string().email(),\n roleSlug: z.string().trim().min(1).max(120).optional().nullable(),\n expiresInDays: z.number().int().min(1).max(30).optional(),\n})\nconst accessSchema = z.object({ hasAccess: z.boolean() })\nconst permissionsSchema = z.object({\n permissions: z.array(z.string().trim().min(1).max(120)).max(200),\n})\n\nconst teamAdminApiId = \"@voyant-travel/auth#team.api.admin\"\nconst jsonBody = <T extends z.ZodTypeAny>(schema: T) => ({\n required: true,\n content: { \"application/json\": { schema } },\n})\nconst responses = (...statuses: number[]) =>\n Object.fromEntries(statuses.map((status) => [status, { description: `HTTP ${status}` }]))\nconst teamRoute = <M extends \"get\" | \"post\" | \"put\" | \"delete\", P extends string>(config: {\n method: M\n path: P\n operationId: string\n request?: Record<string, unknown>\n statuses: number[]\n}) =>\n createRoute({\n method: config.method,\n path: config.path,\n operationId: config.operationId,\n \"x-voyant-api-id\": teamAdminApiId,\n ...(config.request ? { request: config.request } : {}),\n responses: responses(...config.statuses),\n })\n\nconst listMembersRoute = teamRoute({\n method: \"get\",\n path: \"/members\",\n operationId: \"listTeamMembers\",\n statuses: [200, 401, 403, 404, 501],\n})\nconst listRolesRoute = teamRoute({\n method: \"get\",\n path: \"/roles\",\n operationId: \"listTeamRoles\",\n statuses: [200, 401, 403, 404, 501],\n})\nconst listTeamInvitationsRoute = teamRoute({\n method: \"get\",\n path: \"/invitations\",\n operationId: \"listTeamInvitations\",\n statuses: [200, 401, 403, 404, 501],\n})\nconst createTeamInvitationRoute = teamRoute({\n method: \"post\",\n path: \"/invitations\",\n operationId: \"createTeamInvitation\",\n request: { body: jsonBody(inviteSchema) },\n statuses: [201, 400, 401, 403, 404, 501],\n})\nconst revokeTeamInvitationRoute = teamRoute({\n method: \"delete\",\n path: \"/invitations/{invitationId}\",\n operationId: \"revokeTeamInvitation\",\n request: { params: z.object({ invitationId: z.string() }) },\n statuses: [204, 401, 403, 404, 501],\n})\nconst setTeamMemberAccessRoute = teamRoute({\n method: \"put\",\n path: \"/members/{membershipId}/access\",\n operationId: \"setTeamMemberAccess\",\n request: {\n params: z.object({ membershipId: z.string() }),\n body: jsonBody(accessSchema),\n },\n statuses: [200, 400, 401, 403, 404, 501],\n})\nconst setTeamMemberPermissionsRoute = teamRoute({\n method: \"put\",\n path: \"/members/{membershipId}/permissions\",\n operationId: \"setTeamMemberPermissions\",\n request: {\n params: z.object({ membershipId: z.string() }),\n body: jsonBody(permissionsSchema),\n },\n statuses: [200, 400, 401, 403, 404, 501],\n})\n\nasync function resolveActingWorkosUserId(db: VoyantDb, userId: string): Promise<string | null> {\n const [link] = await db\n .select({ providerAccountId: cloudAuthUserLinks.providerAccountId })\n .from(cloudAuthUserLinks)\n .where(eq(cloudAuthUserLinks.userId, userId))\n .limit(1)\n return link?.providerAccountId ?? null\n}\n\nexport function createTeamAdminRoutes(runtime: IdentityAccessRuntimeProvider) {\n const routes = new OpenAPIHono<IdentityAccessEnv>({ defaultHook: openApiValidationHook })\n\n const resolveContext = async (c: TeamRouteContext): Promise<TeamContext | Response> => {\n const deployment = runtime.resolveDeployment(c.env)\n if (deployment.authMode !== \"voyant-cloud\") return c.json({ error: \"Not found\" }, 404)\n\n const userId = c.get(\"userId\")\n if (!userId) return c.json({ error: \"Unauthorized\" }, 401)\n if (!deployment.cloudAdminMembers) {\n return c.json({ error: \"Voyant Cloud member management is not configured\" }, 501)\n }\n\n const actingWorkosUserId = await resolveActingWorkosUserId(c.get(\"db\"), userId)\n if (!actingWorkosUserId) {\n return c.json({ error: \"No Voyant Cloud identity for this session\" }, 403)\n }\n return { config: deployment.cloudAdminMembers, actingWorkosUserId }\n }\n\n const handleError = (c: TeamRouteContext, error: unknown): Response => {\n if (error instanceof CloudAdminMembersError) {\n return c.json({ error: error.reason ?? error.message }, error.status as 403)\n }\n throw error\n }\n\n routes.openapi(listMembersRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n try {\n return c.json({ data: await listCloudAdminMembers(context) })\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(listRolesRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n try {\n return c.json({ data: await listCloudAdminMemberRoles(context) })\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(listTeamInvitationsRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n try {\n return c.json({ data: await listCloudAdminInvitations(context) })\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(createTeamInvitationRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n const input = await parseJsonBody(c, inviteSchema)\n try {\n return c.json({ data: await inviteCloudAdminMember({ ...context, input }) }, 201)\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(revokeTeamInvitationRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n try {\n await revokeCloudAdminInvitation({\n ...context,\n invitationId: c.req.param(\"invitationId\"),\n })\n return c.body(null, 204)\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(setTeamMemberAccessRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n const input = await parseJsonBody(c, accessSchema)\n try {\n return c.json({\n data: await setCloudAdminMemberAccess({\n ...context,\n membershipId: c.req.param(\"membershipId\"),\n hasAccess: input.hasAccess,\n }),\n })\n } catch (error) {\n return handleError(c, error)\n }\n })\n routes.openapi(setTeamMemberPermissionsRoute, async (c) => {\n const context = await resolveContext(c)\n if (context instanceof Response) return context\n const input = await parseJsonBody(c, permissionsSchema)\n try {\n return c.json({\n data: await setCloudAdminMemberPermissions({\n ...context,\n membershipId: c.req.param(\"membershipId\"),\n permissions: input.permissions,\n }),\n })\n } catch (error) {\n return handleError(c, error)\n }\n })\n\n return routes\n}\n"]}
1
+ {"version":3,"file":"team-routes.js","sourceRoot":"","sources":["../src/team-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRoute, OpenAPIHono, z } from \"@hono/zod-openapi\"\nimport { openApiValidationHook, parseJsonBody, type VoyantDb } from \"@voyant-travel/hono\"\nimport type { Context } from \"hono\"\n\nimport { TeamManagementError } from \"./team-management-policy.js\"\nimport type {\n TeamManagementRequestContext,\n TeamManagementRuntimeProvider,\n} from \"./team-management-runtime-port.js\"\n\ntype TeamEnv = {\n Bindings: Record<string, unknown>\n Variables: { userId?: string; db: VoyantDb }\n}\ntype TeamRouteContext = Context<TeamEnv>\n\nconst inviteSchema = z.object({\n email: z.string().email(),\n roleId: z.string().trim().min(1).max(120),\n expiresInDays: z.number().int().min(1).max(30).optional(),\n})\nconst roleSchema = z.object({ roleId: z.string().trim().min(1).max(120) })\n\nconst teamAdminApiId = \"@voyant-travel/auth#team.api.admin\"\nconst jsonBody = <T extends z.ZodTypeAny>(schema: T) => ({\n required: true,\n content: { \"application/json\": { schema } },\n})\nconst responses = (...statuses: number[]) =>\n Object.fromEntries(statuses.map((status) => [status, { description: `HTTP ${status}` }]))\nconst teamRoute = <M extends \"get\" | \"post\" | \"put\" | \"delete\", P extends string>(config: {\n method: M\n path: P\n operationId: string\n request?: Record<string, unknown>\n statuses: number[]\n}) =>\n createRoute({\n method: config.method,\n path: config.path,\n operationId: config.operationId,\n \"x-voyant-api-id\": teamAdminApiId,\n ...(config.request ? { request: config.request } : {}),\n responses: responses(...config.statuses),\n })\n\nconst capabilitiesRoute = teamRoute({\n method: \"get\",\n path: \"/capabilities\",\n operationId: \"getTeamManagementCapabilities\",\n statuses: [200, 401, 403, 501],\n})\nconst listMembersRoute = teamRoute({\n method: \"get\",\n path: \"/members\",\n operationId: \"listTeamMembers\",\n statuses: [200, 401, 403, 501],\n})\nconst listRolesRoute = teamRoute({\n method: \"get\",\n path: \"/roles\",\n operationId: \"listTeamRoles\",\n statuses: [200, 401, 403, 501],\n})\nconst listInvitationsRoute = teamRoute({\n method: \"get\",\n path: \"/invitations\",\n operationId: \"listTeamInvitations\",\n statuses: [200, 401, 403, 501],\n})\nconst createInvitationRoute = teamRoute({\n method: \"post\",\n path: \"/invitations\",\n operationId: \"createTeamInvitation\",\n request: { body: jsonBody(inviteSchema) },\n statuses: [201, 400, 401, 403, 404, 409, 501],\n})\nconst revokeInvitationRoute = teamRoute({\n method: \"delete\",\n path: \"/invitations/{invitationId}\",\n operationId: \"revokeTeamInvitation\",\n request: { params: z.object({ invitationId: z.string() }) },\n statuses: [204, 401, 403, 404, 501],\n})\nconst updateRoleRoute = teamRoute({\n method: \"put\",\n path: \"/members/{memberId}/role\",\n operationId: \"updateTeamMemberRole\",\n request: {\n params: z.object({ memberId: z.string() }),\n body: jsonBody(roleSchema),\n },\n statuses: [200, 400, 401, 403, 404, 409, 501],\n})\nconst deactivateMemberRoute = teamRoute({\n method: \"delete\",\n path: \"/members/{memberId}\",\n operationId: \"deactivateTeamMember\",\n request: { params: z.object({ memberId: z.string() }) },\n statuses: [200, 401, 403, 404, 409, 501],\n})\nconst activateMemberRoute = teamRoute({\n method: \"put\",\n path: \"/members/{memberId}/activation\",\n operationId: \"activateTeamMember\",\n request: { params: z.object({ memberId: z.string() }) },\n statuses: [200, 401, 403, 404, 409, 501],\n})\n\nfunction requestContext(c: TeamRouteContext): TeamManagementRequestContext | Response {\n const userId = c.get(\"userId\")\n if (!userId) return c.json({ error: \"Unauthorized\" }, 401)\n return { bindings: c.env, db: c.get(\"db\"), userId }\n}\n\nfunction handleError(c: TeamRouteContext, error: unknown): Response {\n if (error instanceof TeamManagementError) {\n return c.json({ error: error.message, code: error.code }, error.status)\n }\n if (\n error instanceof Error &&\n \"status\" in error &&\n typeof error.status === \"number\" &&\n error.status >= 400 &&\n error.status <= 599\n ) {\n return c.json({ error: error.message }, error.status as 400)\n }\n throw error\n}\n\nexport function createTeamAdminRoutes(runtime: TeamManagementRuntimeProvider) {\n const routes = new OpenAPIHono<TeamEnv>({ defaultHook: openApiValidationHook })\n\n const run = async <T>(\n c: TeamRouteContext,\n operation: (context: TeamManagementRequestContext) => Promise<T>,\n ): Promise<T | Response> => {\n const context = requestContext(c)\n if (context instanceof Response) return context\n try {\n return await operation(context)\n } catch (error) {\n return handleError(c, error)\n }\n }\n\n routes.openapi(capabilitiesRoute, async (c) => {\n const result = await run(c, (context) => runtime.getCapabilities(context))\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(listMembersRoute, async (c) => {\n const result = await run(c, (context) => runtime.listMembers(context))\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(listRolesRoute, async (c) => {\n const result = await run(c, (context) => runtime.listRoles(context))\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(listInvitationsRoute, async (c) => {\n const result = await run(c, (context) => runtime.listInvitations(context))\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(createInvitationRoute, async (c) => {\n const input = await parseJsonBody(c, inviteSchema)\n const result = await run(c, (context) => runtime.inviteMember(context, input))\n return result instanceof Response ? result : c.json({ data: result }, 201)\n })\n routes.openapi(revokeInvitationRoute, async (c) => {\n const { invitationId } = c.req.param()\n const result = await run(c, (context) => runtime.revokeInvitation(context, invitationId))\n return result instanceof Response ? result : c.body(null, 204)\n })\n routes.openapi(updateRoleRoute, async (c) => {\n const { memberId } = c.req.param()\n const input = await parseJsonBody(c, roleSchema)\n const result = await run(c, (context) =>\n runtime.updateMemberRole(context, memberId, input.roleId),\n )\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(deactivateMemberRoute, async (c) => {\n const { memberId } = c.req.param()\n const result = await run(c, (context) => runtime.deactivateMember(context, memberId))\n return result instanceof Response ? result : c.json({ data: result })\n })\n routes.openapi(activateMemberRoute, async (c) => {\n const { memberId } = c.req.param()\n const result = await run(c, (context) => runtime.activateMember(context, memberId))\n return result instanceof Response ? result : c.json({ data: result })\n })\n\n return routes\n}\n"]}