@shipfox/api-workspaces 10.2.0 → 12.0.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 (167) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +48 -0
  3. package/README.md +27 -4
  4. package/dist/core/entities/workspace.d.ts +1 -0
  5. package/dist/core/entities/workspace.d.ts.map +1 -1
  6. package/dist/core/entities/workspace.js.map +1 -1
  7. package/dist/core/errors.d.ts +3 -0
  8. package/dist/core/errors.d.ts.map +1 -1
  9. package/dist/core/errors.js +6 -0
  10. package/dist/core/errors.js.map +1 -1
  11. package/dist/core/index.d.ts +2 -2
  12. package/dist/core/index.d.ts.map +1 -1
  13. package/dist/core/index.js +2 -2
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/invitations.d.ts.map +1 -1
  16. package/dist/core/invitations.js +7 -4
  17. package/dist/core/invitations.js.map +1 -1
  18. package/dist/core/rate-limit.d.ts +39 -0
  19. package/dist/core/rate-limit.d.ts.map +1 -0
  20. package/dist/core/rate-limit.js +70 -0
  21. package/dist/core/rate-limit.js.map +1 -0
  22. package/dist/core/workspaces.d.ts +8 -0
  23. package/dist/core/workspaces.d.ts.map +1 -1
  24. package/dist/core/workspaces.js +47 -7
  25. package/dist/core/workspaces.js.map +1 -1
  26. package/dist/db/db.d.ts +320 -0
  27. package/dist/db/db.d.ts.map +1 -1
  28. package/dist/db/db.js +3 -1
  29. package/dist/db/db.js.map +1 -1
  30. package/dist/db/index.d.ts +4 -1
  31. package/dist/db/index.d.ts.map +1 -1
  32. package/dist/db/index.js +3 -1
  33. package/dist/db/index.js.map +1 -1
  34. package/dist/db/memberships.d.ts +1 -0
  35. package/dist/db/memberships.d.ts.map +1 -1
  36. package/dist/db/memberships.js +2 -0
  37. package/dist/db/memberships.js.map +1 -1
  38. package/dist/db/rate-limits.d.ts +9 -0
  39. package/dist/db/rate-limits.d.ts.map +1 -0
  40. package/dist/db/rate-limits.js +43 -0
  41. package/dist/db/rate-limits.js.map +1 -0
  42. package/dist/db/schema/rate-limits.d.ts +145 -0
  43. package/dist/db/schema/rate-limits.d.ts.map +1 -0
  44. package/dist/db/schema/rate-limits.js +25 -0
  45. package/dist/db/schema/rate-limits.js.map +1 -0
  46. package/dist/db/schema/workspaces.d.ts +17 -0
  47. package/dist/db/schema/workspaces.d.ts.map +1 -1
  48. package/dist/db/schema/workspaces.js +5 -2
  49. package/dist/db/schema/workspaces.js.map +1 -1
  50. package/dist/db/workspaces.d.ts +11 -1
  51. package/dist/db/workspaces.d.ts.map +1 -1
  52. package/dist/db/workspaces.js +12 -3
  53. package/dist/db/workspaces.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +1 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/metrics/instance.d.ts +6 -0
  59. package/dist/metrics/instance.d.ts.map +1 -1
  60. package/dist/metrics/instance.js +12 -0
  61. package/dist/metrics/instance.js.map +1 -1
  62. package/dist/presentation/dto/membership.d.ts.map +1 -1
  63. package/dist/presentation/dto/membership.js +1 -0
  64. package/dist/presentation/dto/membership.js.map +1 -1
  65. package/dist/presentation/dto/workspace.d.ts.map +1 -1
  66. package/dist/presentation/dto/workspace.js +1 -0
  67. package/dist/presentation/dto/workspace.js.map +1 -1
  68. package/dist/presentation/e2eRoutes/create-workspace.d.ts.map +1 -1
  69. package/dist/presentation/e2eRoutes/create-workspace.js +11 -1
  70. package/dist/presentation/e2eRoutes/create-workspace.js.map +1 -1
  71. package/dist/presentation/inter-module.d.ts.map +1 -1
  72. package/dist/presentation/inter-module.js +3 -2
  73. package/dist/presentation/inter-module.js.map +1 -1
  74. package/dist/presentation/routes/index.d.ts.map +1 -1
  75. package/dist/presentation/routes/index.js +3 -1
  76. package/dist/presentation/routes/index.js.map +1 -1
  77. package/dist/presentation/routes/invitations/create.d.ts.map +1 -1
  78. package/dist/presentation/routes/invitations/create.js +5 -1
  79. package/dist/presentation/routes/invitations/create.js.map +1 -1
  80. package/dist/presentation/routes/invitations/list.d.ts.map +1 -1
  81. package/dist/presentation/routes/invitations/list.js +5 -1
  82. package/dist/presentation/routes/invitations/list.js.map +1 -1
  83. package/dist/presentation/routes/invitations/revoke.d.ts.map +1 -1
  84. package/dist/presentation/routes/invitations/revoke.js +5 -1
  85. package/dist/presentation/routes/invitations/revoke.js.map +1 -1
  86. package/dist/presentation/routes/members/list.d.ts.map +1 -1
  87. package/dist/presentation/routes/members/list.js +5 -1
  88. package/dist/presentation/routes/members/list.js.map +1 -1
  89. package/dist/presentation/routes/members/remove.d.ts.map +1 -1
  90. package/dist/presentation/routes/members/remove.js +5 -1
  91. package/dist/presentation/routes/members/remove.js.map +1 -1
  92. package/dist/presentation/routes/rate-limit.d.ts +3 -0
  93. package/dist/presentation/routes/rate-limit.d.ts.map +1 -0
  94. package/dist/presentation/routes/rate-limit.js +42 -0
  95. package/dist/presentation/routes/rate-limit.js.map +1 -0
  96. package/dist/presentation/routes/workspaces/create.d.ts.map +1 -1
  97. package/dist/presentation/routes/workspaces/create.js +11 -1
  98. package/dist/presentation/routes/workspaces/create.js.map +1 -1
  99. package/dist/presentation/routes/workspaces/index.d.ts +2 -0
  100. package/dist/presentation/routes/workspaces/index.d.ts.map +1 -1
  101. package/dist/presentation/routes/workspaces/index.js +2 -0
  102. package/dist/presentation/routes/workspaces/index.js.map +1 -1
  103. package/dist/presentation/routes/workspaces/slug-availability.d.ts +2 -0
  104. package/dist/presentation/routes/workspaces/slug-availability.d.ts.map +1 -0
  105. package/dist/presentation/routes/workspaces/slug-availability.js +31 -0
  106. package/dist/presentation/routes/workspaces/slug-availability.js.map +1 -0
  107. package/dist/presentation/routes/workspaces/update.d.ts +2 -0
  108. package/dist/presentation/routes/workspaces/update.d.ts.map +1 -0
  109. package/dist/presentation/routes/workspaces/update.js +49 -0
  110. package/dist/presentation/routes/workspaces/update.js.map +1 -0
  111. package/dist/tsconfig.test.tsbuildinfo +1 -1
  112. package/drizzle/0000_initial.sql +2 -0
  113. package/drizzle/0003_dapper_talos.sql +13 -0
  114. package/drizzle/meta/0000_snapshot.json +23 -1
  115. package/drizzle/meta/0003_snapshot.json +689 -0
  116. package/drizzle/meta/_journal.json +7 -0
  117. package/package.json +14 -12
  118. package/src/core/entities/workspace.ts +1 -0
  119. package/src/core/errors.ts +7 -0
  120. package/src/core/index.ts +3 -0
  121. package/src/core/invitations.test.ts +8 -8
  122. package/src/core/invitations.ts +4 -1
  123. package/src/core/rate-limit.test.ts +113 -0
  124. package/src/core/rate-limit.ts +119 -0
  125. package/src/core/workspaces.test.ts +31 -3
  126. package/src/core/workspaces.ts +51 -4
  127. package/src/db/db.ts +2 -0
  128. package/src/db/index.ts +10 -0
  129. package/src/db/memberships.ts +3 -0
  130. package/src/db/rate-limits.test.ts +74 -0
  131. package/src/db/rate-limits.ts +59 -0
  132. package/src/db/schema/rate-limits.ts +27 -0
  133. package/src/db/schema/workspaces.ts +7 -2
  134. package/src/db/workspaces.ts +21 -1
  135. package/src/index.test.ts +2 -0
  136. package/src/index.ts +1 -0
  137. package/src/metrics/instance.ts +26 -0
  138. package/src/presentation/dto/membership.ts +1 -0
  139. package/src/presentation/dto/workspace.ts +1 -0
  140. package/src/presentation/e2eRoutes/create-workspace.ts +9 -1
  141. package/src/presentation/inter-module.test.ts +69 -0
  142. package/src/presentation/inter-module.ts +7 -4
  143. package/src/presentation/routes/index.ts +8 -1
  144. package/src/presentation/routes/invitations/create.test.ts +15 -0
  145. package/src/presentation/routes/invitations/create.ts +2 -1
  146. package/src/presentation/routes/invitations/list.test.ts +30 -0
  147. package/src/presentation/routes/invitations/list.ts +2 -1
  148. package/src/presentation/routes/invitations/revoke.test.ts +14 -0
  149. package/src/presentation/routes/invitations/revoke.ts +2 -1
  150. package/src/presentation/routes/members/list.test.ts +29 -1
  151. package/src/presentation/routes/members/list.ts +2 -1
  152. package/src/presentation/routes/members/remove.test.ts +14 -0
  153. package/src/presentation/routes/members/remove.ts +2 -1
  154. package/src/presentation/routes/rate-limit.ts +45 -0
  155. package/src/presentation/routes/workspaces/create.test.ts +33 -3
  156. package/src/presentation/routes/workspaces/create.ts +9 -1
  157. package/src/presentation/routes/workspaces/index.ts +2 -0
  158. package/src/presentation/routes/workspaces/list.test.ts +1 -0
  159. package/src/presentation/routes/workspaces/slug-availability.test.ts +159 -0
  160. package/src/presentation/routes/workspaces/slug-availability.ts +30 -0
  161. package/src/presentation/routes/workspaces/update.test.ts +114 -0
  162. package/src/presentation/routes/workspaces/update.ts +41 -0
  163. package/test/env.ts +1 -0
  164. package/test/factories/workspace.ts +3 -1
  165. package/test/globalSetup.ts +1 -1
  166. package/test/routes.ts +26 -7
  167. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,12 +1,13 @@
1
- import { WORKSPACES_WORKSPACE_CREATED } from '@shipfox/api-workspaces-dto';
1
+ import { WORKSPACES_WORKSPACE_CREATED, WORKSPACES_WORKSPACE_UPDATED } from '@shipfox/api-workspaces-dto';
2
+ import { isUniqueViolation } from '@shipfox/node-drizzle';
2
3
  import { writeOutboxEvent } from '@shipfox/node-outbox';
3
4
  import { db } from '#db/db.js';
4
5
  import { findMembership, listMembershipsByUser, listMembershipsByWorkspace, removeMembership } from '#db/memberships.js';
5
6
  import { memberships } from '#db/schema/memberships.js';
6
7
  import { workspacesOutbox } from '#db/schema/outbox.js';
7
8
  import { toWorkspace, workspaces } from '#db/schema/workspaces.js';
8
- import { getWorkspaceById } from '#db/workspaces.js';
9
- import { MembershipNotFoundError, MembershipRequiredError, SelfRemovalNotAllowedError, WorkspaceInactiveError, WorkspaceNotFoundError } from './errors.js';
9
+ import { getWorkspaceById, isWorkspaceSlugAvailable, updateWorkspace } from '#db/workspaces.js';
10
+ import { MembershipNotFoundError, MembershipRequiredError, SelfRemovalNotAllowedError, WorkspaceInactiveError, WorkspaceNotFoundError, WorkspaceSlugConflictError } from './errors.js';
10
11
  export async function requireWorkspaceMembership(params) {
11
12
  const membership = params.memberships.find((m)=>m.workspaceId === params.workspaceId);
12
13
  if (!membership) {
@@ -16,7 +17,7 @@ export async function requireWorkspaceMembership(params) {
16
17
  if (!workspace) {
17
18
  throw new WorkspaceNotFoundError(params.workspaceId);
18
19
  }
19
- if (workspace.status !== 'active') {
20
+ if (params.enforceWorkspaceStatus !== false && workspace.status !== 'active') {
20
21
  throw new WorkspaceInactiveError(params.workspaceId);
21
22
  }
22
23
  return {
@@ -30,9 +31,14 @@ export async function createWorkspaceForUser(params) {
30
31
  return await db().transaction(async (tx)=>{
31
32
  const [workspaceRow] = await tx.insert(workspaces).values({
32
33
  name: params.name,
34
+ slug: params.slug,
33
35
  createdBy: params.userId
36
+ }).onConflictDoNothing({
37
+ target: workspaces.slug
34
38
  }).returning();
35
- if (!workspaceRow) throw new Error('Insert returned no rows');
39
+ if (!workspaceRow) {
40
+ throw new WorkspaceSlugConflictError(params.slug);
41
+ }
36
42
  await tx.insert(memberships).values({
37
43
  userId: params.userId,
38
44
  userEmail: params.userEmail ?? `user-${params.userId}@example.local`,
@@ -45,12 +51,44 @@ export async function createWorkspaceForUser(params) {
45
51
  payload: {
46
52
  workspaceId: workspace.id,
47
53
  name: workspace.name,
54
+ slug: workspace.slug,
48
55
  creatorUserId: params.userId
49
56
  }
50
57
  });
51
58
  return workspace;
52
59
  });
53
60
  }
61
+ export async function checkWorkspaceSlugAvailability(slug) {
62
+ return await isWorkspaceSlugAvailable(slug);
63
+ }
64
+ export async function updateWorkspaceDetails(params) {
65
+ try {
66
+ return await db().transaction(async (tx)=>{
67
+ const workspace = await updateWorkspace({
68
+ id: params.workspaceId,
69
+ name: params.name,
70
+ slug: params.slug
71
+ }, {
72
+ tx
73
+ });
74
+ if (!workspace) throw new WorkspaceNotFoundError(params.workspaceId);
75
+ await writeOutboxEvent(tx, workspacesOutbox, {
76
+ type: WORKSPACES_WORKSPACE_UPDATED,
77
+ payload: {
78
+ workspaceId: workspace.id,
79
+ name: workspace.name,
80
+ slug: workspace.slug
81
+ }
82
+ });
83
+ return workspace;
84
+ });
85
+ } catch (error) {
86
+ if (isUniqueViolation(error, 'workspaces_slug_unique') && params.slug) {
87
+ throw new WorkspaceSlugConflictError(params.slug);
88
+ }
89
+ throw error;
90
+ }
91
+ }
54
92
  export async function getWorkspace(params) {
55
93
  const workspace = await getWorkspaceById(params.workspaceId);
56
94
  if (!workspace) {
@@ -75,7 +113,8 @@ export async function listWorkspaceMembers(params) {
75
113
  await requireWorkspaceMembership({
76
114
  workspaceId: params.workspaceId,
77
115
  userId: params.requesterUserId,
78
- memberships: params.requesterMemberships
116
+ memberships: params.requesterMemberships,
117
+ enforceWorkspaceStatus: false
79
118
  });
80
119
  return listMembershipsByWorkspace({
81
120
  workspaceId: params.workspaceId
@@ -85,7 +124,8 @@ export async function removeWorkspaceMember(params) {
85
124
  await requireWorkspaceMembership({
86
125
  workspaceId: params.workspaceId,
87
126
  userId: params.requesterUserId,
88
- memberships: params.requesterMemberships
127
+ memberships: params.requesterMemberships,
128
+ enforceWorkspaceStatus: false
89
129
  });
90
130
  if (params.userId === params.requesterUserId) {
91
131
  throw new SelfRemovalNotAllowedError();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/workspaces.ts"],"sourcesContent":["import type {UserContextMembership} from '@shipfox/api-auth-context';\nimport {\n WORKSPACES_WORKSPACE_CREATED,\n type WorkspaceRole,\n type WorkspacesEventMap,\n} from '@shipfox/api-workspaces-dto';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {db} from '#db/db.js';\nimport {\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n type MembershipWithUser,\n type MembershipWithWorkspace,\n removeMembership,\n} from '#db/memberships.js';\nimport {memberships} from '#db/schema/memberships.js';\nimport {workspacesOutbox} from '#db/schema/outbox.js';\nimport {toWorkspace, workspaces} from '#db/schema/workspaces.js';\nimport {getWorkspaceById} from '#db/workspaces.js';\nimport type {Workspace} from './entities/workspace.js';\nimport {\n MembershipNotFoundError,\n MembershipRequiredError,\n SelfRemovalNotAllowedError,\n WorkspaceInactiveError,\n WorkspaceNotFoundError,\n} from './errors.js';\n\nexport interface RequireWorkspaceMembershipParams {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<UserContextMembership>;\n}\n\nexport interface RequireWorkspaceMembershipResult {\n workspace: Workspace;\n workspaceId: string;\n userId: string;\n role: WorkspaceRole;\n}\n\nexport async function requireWorkspaceMembership(\n params: RequireWorkspaceMembershipParams,\n): Promise<RequireWorkspaceMembershipResult> {\n const membership = params.memberships.find((m) => m.workspaceId === params.workspaceId);\n if (!membership) {\n throw new MembershipRequiredError(params.workspaceId);\n }\n\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n if (workspace.status !== 'active') {\n throw new WorkspaceInactiveError(params.workspaceId);\n }\n\n return {workspace, workspaceId: workspace.id, userId: params.userId, role: membership.role};\n}\n\nexport async function createWorkspaceForUser(params: {\n name: string;\n userId: string;\n userEmail?: string | undefined;\n userName?: string | null | undefined;\n}): Promise<Workspace> {\n return await db().transaction(async (tx) => {\n const [workspaceRow] = await tx\n .insert(workspaces)\n .values({name: params.name, createdBy: params.userId})\n .returning();\n if (!workspaceRow) throw new Error('Insert returned no rows');\n await tx.insert(memberships).values({\n userId: params.userId,\n userEmail: params.userEmail ?? `user-${params.userId}@example.local`,\n userName: params.userName ?? null,\n workspaceId: workspaceRow.id,\n });\n const workspace = toWorkspace(workspaceRow);\n\n await writeOutboxEvent<WorkspacesEventMap>(tx, workspacesOutbox, {\n type: WORKSPACES_WORKSPACE_CREATED,\n payload: {\n workspaceId: workspace.id,\n name: workspace.name,\n creatorUserId: params.userId,\n },\n });\n\n return workspace;\n });\n}\n\nexport async function getWorkspace(params: {workspaceId: string}): Promise<Workspace> {\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n\n return workspace;\n}\n\nexport async function getWorkspaceCreator(params: {workspaceId: string}): Promise<string | null> {\n const workspace = await getWorkspace(params);\n return workspace.createdBy;\n}\n\nexport async function getWorkspaceOperatingState(params: {\n workspaceId: string;\n}): Promise<Workspace['status']> {\n const workspace = await getWorkspace(params);\n return workspace.status;\n}\n\nexport async function listUserWorkspaceMemberships(params: {\n userId: string;\n}): Promise<MembershipWithWorkspace[]> {\n return await listMembershipsByUser({userId: params.userId});\n}\n\nexport async function listWorkspaceMembers(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<MembershipWithUser[]> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n return listMembershipsByWorkspace({workspaceId: params.workspaceId});\n}\n\nexport async function removeWorkspaceMember(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n userId: string;\n}): Promise<void> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n if (params.userId === params.requesterUserId) {\n throw new SelfRemovalNotAllowedError();\n }\n\n const target = await findMembership({userId: params.userId, workspaceId: params.workspaceId});\n if (!target) {\n throw new MembershipNotFoundError(params.userId, params.workspaceId);\n }\n\n await removeMembership({userId: params.userId, workspaceId: params.workspaceId});\n}\n"],"names":["WORKSPACES_WORKSPACE_CREATED","writeOutboxEvent","db","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","memberships","workspacesOutbox","toWorkspace","workspaces","getWorkspaceById","MembershipNotFoundError","MembershipRequiredError","SelfRemovalNotAllowedError","WorkspaceInactiveError","WorkspaceNotFoundError","requireWorkspaceMembership","params","membership","find","m","workspaceId","workspace","status","id","userId","role","createWorkspaceForUser","transaction","tx","workspaceRow","insert","values","name","createdBy","returning","Error","userEmail","userName","type","payload","creatorUserId","getWorkspace","getWorkspaceCreator","getWorkspaceOperatingState","listUserWorkspaceMemberships","listWorkspaceMembers","requesterUserId","requesterMemberships","removeWorkspaceMember","target"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/workspaces.ts"],"sourcesContent":["import type {UserContextMembership} from '@shipfox/api-auth-context';\nimport {\n WORKSPACES_WORKSPACE_CREATED,\n WORKSPACES_WORKSPACE_UPDATED,\n type WorkspaceRole,\n type WorkspacesEventMap,\n} from '@shipfox/api-workspaces-dto';\nimport {isUniqueViolation} from '@shipfox/node-drizzle';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {db} from '#db/db.js';\nimport {\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n type MembershipWithUser,\n type MembershipWithWorkspace,\n removeMembership,\n} from '#db/memberships.js';\nimport {memberships} from '#db/schema/memberships.js';\nimport {workspacesOutbox} from '#db/schema/outbox.js';\nimport {toWorkspace, workspaces} from '#db/schema/workspaces.js';\nimport {getWorkspaceById, isWorkspaceSlugAvailable, updateWorkspace} from '#db/workspaces.js';\nimport type {Workspace} from './entities/workspace.js';\nimport {\n MembershipNotFoundError,\n MembershipRequiredError,\n SelfRemovalNotAllowedError,\n WorkspaceInactiveError,\n WorkspaceNotFoundError,\n WorkspaceSlugConflictError,\n} from './errors.js';\n\nexport interface RequireWorkspaceMembershipParams {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<UserContextMembership>;\n enforceWorkspaceStatus?: boolean;\n}\n\nexport interface RequireWorkspaceMembershipResult {\n workspace: Workspace;\n workspaceId: string;\n userId: string;\n role: WorkspaceRole;\n}\n\nexport async function requireWorkspaceMembership(\n params: RequireWorkspaceMembershipParams,\n): Promise<RequireWorkspaceMembershipResult> {\n const membership = params.memberships.find((m) => m.workspaceId === params.workspaceId);\n if (!membership) {\n throw new MembershipRequiredError(params.workspaceId);\n }\n\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n if (params.enforceWorkspaceStatus !== false && workspace.status !== 'active') {\n throw new WorkspaceInactiveError(params.workspaceId);\n }\n\n return {workspace, workspaceId: workspace.id, userId: params.userId, role: membership.role};\n}\n\nexport async function createWorkspaceForUser(params: {\n name: string;\n slug: string;\n userId: string;\n userEmail?: string | undefined;\n userName?: string | null | undefined;\n}): Promise<Workspace> {\n return await db().transaction(async (tx) => {\n const [workspaceRow] = await tx\n .insert(workspaces)\n .values({name: params.name, slug: params.slug, createdBy: params.userId})\n .onConflictDoNothing({target: workspaces.slug})\n .returning();\n if (!workspaceRow) {\n throw new WorkspaceSlugConflictError(params.slug);\n }\n await tx.insert(memberships).values({\n userId: params.userId,\n userEmail: params.userEmail ?? `user-${params.userId}@example.local`,\n userName: params.userName ?? null,\n workspaceId: workspaceRow.id,\n });\n const workspace = toWorkspace(workspaceRow);\n\n await writeOutboxEvent<WorkspacesEventMap>(tx, workspacesOutbox, {\n type: WORKSPACES_WORKSPACE_CREATED,\n payload: {\n workspaceId: workspace.id,\n name: workspace.name,\n slug: workspace.slug,\n creatorUserId: params.userId,\n },\n });\n\n return workspace;\n });\n}\n\nexport async function checkWorkspaceSlugAvailability(slug: string): Promise<boolean> {\n return await isWorkspaceSlugAvailable(slug);\n}\n\nexport async function updateWorkspaceDetails(params: {\n workspaceId: string;\n name?: string | undefined;\n slug?: string | undefined;\n}): Promise<Workspace> {\n try {\n return await db().transaction(async (tx) => {\n const workspace = await updateWorkspace(\n {id: params.workspaceId, name: params.name, slug: params.slug},\n {tx},\n );\n if (!workspace) throw new WorkspaceNotFoundError(params.workspaceId);\n\n await writeOutboxEvent<WorkspacesEventMap>(tx, workspacesOutbox, {\n type: WORKSPACES_WORKSPACE_UPDATED,\n payload: {\n workspaceId: workspace.id,\n name: workspace.name,\n slug: workspace.slug,\n },\n });\n\n return workspace;\n });\n } catch (error) {\n if (isUniqueViolation(error, 'workspaces_slug_unique') && params.slug) {\n throw new WorkspaceSlugConflictError(params.slug);\n }\n throw error;\n }\n}\n\nexport async function getWorkspace(params: {workspaceId: string}): Promise<Workspace> {\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n\n return workspace;\n}\n\nexport async function getWorkspaceCreator(params: {workspaceId: string}): Promise<string | null> {\n const workspace = await getWorkspace(params);\n return workspace.createdBy;\n}\n\nexport async function getWorkspaceOperatingState(params: {\n workspaceId: string;\n}): Promise<Workspace['status']> {\n const workspace = await getWorkspace(params);\n return workspace.status;\n}\n\nexport async function listUserWorkspaceMemberships(params: {\n userId: string;\n}): Promise<MembershipWithWorkspace[]> {\n return await listMembershipsByUser({userId: params.userId});\n}\n\nexport async function listWorkspaceMembers(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<MembershipWithUser[]> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n enforceWorkspaceStatus: false,\n });\n\n return listMembershipsByWorkspace({workspaceId: params.workspaceId});\n}\n\nexport async function removeWorkspaceMember(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n userId: string;\n}): Promise<void> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n enforceWorkspaceStatus: false,\n });\n\n if (params.userId === params.requesterUserId) {\n throw new SelfRemovalNotAllowedError();\n }\n\n const target = await findMembership({userId: params.userId, workspaceId: params.workspaceId});\n if (!target) {\n throw new MembershipNotFoundError(params.userId, params.workspaceId);\n }\n\n await removeMembership({userId: params.userId, workspaceId: params.workspaceId});\n}\n"],"names":["WORKSPACES_WORKSPACE_CREATED","WORKSPACES_WORKSPACE_UPDATED","isUniqueViolation","writeOutboxEvent","db","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","memberships","workspacesOutbox","toWorkspace","workspaces","getWorkspaceById","isWorkspaceSlugAvailable","updateWorkspace","MembershipNotFoundError","MembershipRequiredError","SelfRemovalNotAllowedError","WorkspaceInactiveError","WorkspaceNotFoundError","WorkspaceSlugConflictError","requireWorkspaceMembership","params","membership","find","m","workspaceId","workspace","enforceWorkspaceStatus","status","id","userId","role","createWorkspaceForUser","transaction","tx","workspaceRow","insert","values","name","slug","createdBy","onConflictDoNothing","target","returning","userEmail","userName","type","payload","creatorUserId","checkWorkspaceSlugAvailability","updateWorkspaceDetails","error","getWorkspace","getWorkspaceCreator","getWorkspaceOperatingState","listUserWorkspaceMemberships","listWorkspaceMembers","requesterUserId","requesterMemberships","removeWorkspaceMember"],"mappings":"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"}
package/dist/db/db.d.ts CHANGED
@@ -166,6 +166,23 @@ export declare const schema: {
166
166
  identity: undefined;
167
167
  generated: undefined;
168
168
  }, {}, {}>;
169
+ slug: import("drizzle-orm/pg-core").PgColumn<{
170
+ name: "slug";
171
+ tableName: "workspaces";
172
+ dataType: "string";
173
+ columnType: "PgText";
174
+ data: string;
175
+ driverParam: string;
176
+ notNull: true;
177
+ hasDefault: false;
178
+ isPrimaryKey: false;
179
+ isAutoincrement: false;
180
+ hasRuntimeDefault: false;
181
+ enumValues: [string, ...string[]];
182
+ baseColumn: never;
183
+ identity: undefined;
184
+ generated: undefined;
185
+ }, {}, {}>;
169
186
  status: import("drizzle-orm/pg-core").PgColumn<{
170
187
  name: "status";
171
188
  tableName: "workspaces";
@@ -785,6 +802,149 @@ export declare const schema: {
785
802
  };
786
803
  dialect: "pg";
787
804
  }>;
805
+ workspacesRateLimits: import("drizzle-orm/pg-core").PgTableWithColumns<{
806
+ name: "rate_limits";
807
+ schema: undefined;
808
+ columns: {
809
+ action: import("drizzle-orm/pg-core").PgColumn<{
810
+ name: "action";
811
+ tableName: "rate_limits";
812
+ dataType: "string";
813
+ columnType: "PgText";
814
+ data: string;
815
+ driverParam: string;
816
+ notNull: true;
817
+ hasDefault: false;
818
+ isPrimaryKey: false;
819
+ isAutoincrement: false;
820
+ hasRuntimeDefault: false;
821
+ enumValues: [string, ...string[]];
822
+ baseColumn: never;
823
+ identity: undefined;
824
+ generated: undefined;
825
+ }, {}, {}>;
826
+ scope: import("drizzle-orm/pg-core").PgColumn<{
827
+ name: "scope";
828
+ tableName: "rate_limits";
829
+ dataType: "string";
830
+ columnType: "PgText";
831
+ data: string;
832
+ driverParam: string;
833
+ notNull: true;
834
+ hasDefault: false;
835
+ isPrimaryKey: false;
836
+ isAutoincrement: false;
837
+ hasRuntimeDefault: false;
838
+ enumValues: [string, ...string[]];
839
+ baseColumn: never;
840
+ identity: undefined;
841
+ generated: undefined;
842
+ }, {}, {}>;
843
+ identifierHmac: import("drizzle-orm/pg-core").PgColumn<{
844
+ name: "identifier_hmac";
845
+ tableName: "rate_limits";
846
+ dataType: "string";
847
+ columnType: "PgText";
848
+ data: string;
849
+ driverParam: string;
850
+ notNull: true;
851
+ hasDefault: false;
852
+ isPrimaryKey: false;
853
+ isAutoincrement: false;
854
+ hasRuntimeDefault: false;
855
+ enumValues: [string, ...string[]];
856
+ baseColumn: never;
857
+ identity: undefined;
858
+ generated: undefined;
859
+ }, {}, {}>;
860
+ windowStart: import("drizzle-orm/pg-core").PgColumn<{
861
+ name: "window_start";
862
+ tableName: "rate_limits";
863
+ dataType: "date";
864
+ columnType: "PgTimestamp";
865
+ data: Date;
866
+ driverParam: string;
867
+ notNull: true;
868
+ hasDefault: false;
869
+ isPrimaryKey: false;
870
+ isAutoincrement: false;
871
+ hasRuntimeDefault: false;
872
+ enumValues: undefined;
873
+ baseColumn: never;
874
+ identity: undefined;
875
+ generated: undefined;
876
+ }, {}, {}>;
877
+ count: import("drizzle-orm/pg-core").PgColumn<{
878
+ name: "count";
879
+ tableName: "rate_limits";
880
+ dataType: "number";
881
+ columnType: "PgInteger";
882
+ data: number;
883
+ driverParam: string | number;
884
+ notNull: true;
885
+ hasDefault: true;
886
+ isPrimaryKey: false;
887
+ isAutoincrement: false;
888
+ hasRuntimeDefault: false;
889
+ enumValues: undefined;
890
+ baseColumn: never;
891
+ identity: undefined;
892
+ generated: undefined;
893
+ }, {}, {}>;
894
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
895
+ name: "expires_at";
896
+ tableName: "rate_limits";
897
+ dataType: "date";
898
+ columnType: "PgTimestamp";
899
+ data: Date;
900
+ driverParam: string;
901
+ notNull: true;
902
+ hasDefault: false;
903
+ isPrimaryKey: false;
904
+ isAutoincrement: false;
905
+ hasRuntimeDefault: false;
906
+ enumValues: undefined;
907
+ baseColumn: never;
908
+ identity: undefined;
909
+ generated: undefined;
910
+ }, {}, {}>;
911
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
912
+ name: "created_at";
913
+ tableName: "rate_limits";
914
+ dataType: "date";
915
+ columnType: "PgTimestamp";
916
+ data: Date;
917
+ driverParam: string;
918
+ notNull: true;
919
+ hasDefault: true;
920
+ isPrimaryKey: false;
921
+ isAutoincrement: false;
922
+ hasRuntimeDefault: false;
923
+ enumValues: undefined;
924
+ baseColumn: never;
925
+ identity: undefined;
926
+ generated: undefined;
927
+ }, {}, {}>;
928
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
929
+ name: "updated_at";
930
+ tableName: "rate_limits";
931
+ dataType: "date";
932
+ columnType: "PgTimestamp";
933
+ data: Date;
934
+ driverParam: string;
935
+ notNull: true;
936
+ hasDefault: true;
937
+ isPrimaryKey: false;
938
+ isAutoincrement: false;
939
+ hasRuntimeDefault: false;
940
+ enumValues: undefined;
941
+ baseColumn: never;
942
+ identity: undefined;
943
+ generated: undefined;
944
+ }, {}, {}>;
945
+ };
946
+ dialect: "pg";
947
+ }>;
788
948
  };
789
949
  export declare function db(): NodePgDatabase<{
790
950
  workspacesAdminCommandResults: import("drizzle-orm/pg-core").PgTableWithColumns<{
@@ -953,6 +1113,23 @@ export declare function db(): NodePgDatabase<{
953
1113
  identity: undefined;
954
1114
  generated: undefined;
955
1115
  }, {}, {}>;
1116
+ slug: import("drizzle-orm/pg-core").PgColumn<{
1117
+ name: "slug";
1118
+ tableName: "workspaces";
1119
+ dataType: "string";
1120
+ columnType: "PgText";
1121
+ data: string;
1122
+ driverParam: string;
1123
+ notNull: true;
1124
+ hasDefault: false;
1125
+ isPrimaryKey: false;
1126
+ isAutoincrement: false;
1127
+ hasRuntimeDefault: false;
1128
+ enumValues: [string, ...string[]];
1129
+ baseColumn: never;
1130
+ identity: undefined;
1131
+ generated: undefined;
1132
+ }, {}, {}>;
956
1133
  status: import("drizzle-orm/pg-core").PgColumn<{
957
1134
  name: "status";
958
1135
  tableName: "workspaces";
@@ -1572,6 +1749,149 @@ export declare function db(): NodePgDatabase<{
1572
1749
  };
1573
1750
  dialect: "pg";
1574
1751
  }>;
1752
+ workspacesRateLimits: import("drizzle-orm/pg-core").PgTableWithColumns<{
1753
+ name: "rate_limits";
1754
+ schema: undefined;
1755
+ columns: {
1756
+ action: import("drizzle-orm/pg-core").PgColumn<{
1757
+ name: "action";
1758
+ tableName: "rate_limits";
1759
+ dataType: "string";
1760
+ columnType: "PgText";
1761
+ data: string;
1762
+ driverParam: string;
1763
+ notNull: true;
1764
+ hasDefault: false;
1765
+ isPrimaryKey: false;
1766
+ isAutoincrement: false;
1767
+ hasRuntimeDefault: false;
1768
+ enumValues: [string, ...string[]];
1769
+ baseColumn: never;
1770
+ identity: undefined;
1771
+ generated: undefined;
1772
+ }, {}, {}>;
1773
+ scope: import("drizzle-orm/pg-core").PgColumn<{
1774
+ name: "scope";
1775
+ tableName: "rate_limits";
1776
+ dataType: "string";
1777
+ columnType: "PgText";
1778
+ data: string;
1779
+ driverParam: string;
1780
+ notNull: true;
1781
+ hasDefault: false;
1782
+ isPrimaryKey: false;
1783
+ isAutoincrement: false;
1784
+ hasRuntimeDefault: false;
1785
+ enumValues: [string, ...string[]];
1786
+ baseColumn: never;
1787
+ identity: undefined;
1788
+ generated: undefined;
1789
+ }, {}, {}>;
1790
+ identifierHmac: import("drizzle-orm/pg-core").PgColumn<{
1791
+ name: "identifier_hmac";
1792
+ tableName: "rate_limits";
1793
+ dataType: "string";
1794
+ columnType: "PgText";
1795
+ data: string;
1796
+ driverParam: string;
1797
+ notNull: true;
1798
+ hasDefault: false;
1799
+ isPrimaryKey: false;
1800
+ isAutoincrement: false;
1801
+ hasRuntimeDefault: false;
1802
+ enumValues: [string, ...string[]];
1803
+ baseColumn: never;
1804
+ identity: undefined;
1805
+ generated: undefined;
1806
+ }, {}, {}>;
1807
+ windowStart: import("drizzle-orm/pg-core").PgColumn<{
1808
+ name: "window_start";
1809
+ tableName: "rate_limits";
1810
+ dataType: "date";
1811
+ columnType: "PgTimestamp";
1812
+ data: Date;
1813
+ driverParam: string;
1814
+ notNull: true;
1815
+ hasDefault: false;
1816
+ isPrimaryKey: false;
1817
+ isAutoincrement: false;
1818
+ hasRuntimeDefault: false;
1819
+ enumValues: undefined;
1820
+ baseColumn: never;
1821
+ identity: undefined;
1822
+ generated: undefined;
1823
+ }, {}, {}>;
1824
+ count: import("drizzle-orm/pg-core").PgColumn<{
1825
+ name: "count";
1826
+ tableName: "rate_limits";
1827
+ dataType: "number";
1828
+ columnType: "PgInteger";
1829
+ data: number;
1830
+ driverParam: string | number;
1831
+ notNull: true;
1832
+ hasDefault: true;
1833
+ isPrimaryKey: false;
1834
+ isAutoincrement: false;
1835
+ hasRuntimeDefault: false;
1836
+ enumValues: undefined;
1837
+ baseColumn: never;
1838
+ identity: undefined;
1839
+ generated: undefined;
1840
+ }, {}, {}>;
1841
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
1842
+ name: "expires_at";
1843
+ tableName: "rate_limits";
1844
+ dataType: "date";
1845
+ columnType: "PgTimestamp";
1846
+ data: Date;
1847
+ driverParam: string;
1848
+ notNull: true;
1849
+ hasDefault: false;
1850
+ isPrimaryKey: false;
1851
+ isAutoincrement: false;
1852
+ hasRuntimeDefault: false;
1853
+ enumValues: undefined;
1854
+ baseColumn: never;
1855
+ identity: undefined;
1856
+ generated: undefined;
1857
+ }, {}, {}>;
1858
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1859
+ name: "created_at";
1860
+ tableName: "rate_limits";
1861
+ dataType: "date";
1862
+ columnType: "PgTimestamp";
1863
+ data: Date;
1864
+ driverParam: string;
1865
+ notNull: true;
1866
+ hasDefault: true;
1867
+ isPrimaryKey: false;
1868
+ isAutoincrement: false;
1869
+ hasRuntimeDefault: false;
1870
+ enumValues: undefined;
1871
+ baseColumn: never;
1872
+ identity: undefined;
1873
+ generated: undefined;
1874
+ }, {}, {}>;
1875
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
1876
+ name: "updated_at";
1877
+ tableName: "rate_limits";
1878
+ dataType: "date";
1879
+ columnType: "PgTimestamp";
1880
+ data: Date;
1881
+ driverParam: string;
1882
+ notNull: true;
1883
+ hasDefault: true;
1884
+ isPrimaryKey: false;
1885
+ isAutoincrement: false;
1886
+ hasRuntimeDefault: false;
1887
+ enumValues: undefined;
1888
+ baseColumn: never;
1889
+ identity: undefined;
1890
+ generated: undefined;
1891
+ }, {}, {}>;
1892
+ };
1893
+ dialect: "pg";
1894
+ }>;
1575
1895
  }>;
1576
1896
  export declare function closeDb(): void;
1577
1897
  //# sourceMappingURL=db.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAQnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMlB,CAAC;AAIF,wBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGjB;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AASnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOlB,CAAC;AAIF,wBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGjB;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B"}
package/dist/db/db.js CHANGED
@@ -4,13 +4,15 @@ import { workspacesAdminCommandResults } from './schema/admin-command-results.js
4
4
  import { invitations } from './schema/invitations.js';
5
5
  import { memberships } from './schema/memberships.js';
6
6
  import { workspacesOutbox } from './schema/outbox.js';
7
+ import { workspacesRateLimits } from './schema/rate-limits.js';
7
8
  import { workspaces } from './schema/workspaces.js';
8
9
  export const schema = {
9
10
  workspacesAdminCommandResults,
10
11
  workspaces,
11
12
  memberships,
12
13
  invitations,
13
- workspacesOutbox
14
+ workspacesOutbox,
15
+ workspacesRateLimits
14
16
  };
15
17
  let _db;
16
18
  export function db() {
package/dist/db/db.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/db.ts"],"sourcesContent":["import {drizzle, type NodePgDatabase} from '@shipfox/node-drizzle';\nimport {pgClient} from '@shipfox/node-postgres';\nimport {workspacesAdminCommandResults} from './schema/admin-command-results.js';\nimport {invitations} from './schema/invitations.js';\nimport {memberships} from './schema/memberships.js';\nimport {workspacesOutbox} from './schema/outbox.js';\nimport {workspaces} from './schema/workspaces.js';\n\nexport const schema = {\n workspacesAdminCommandResults,\n workspaces,\n memberships,\n invitations,\n workspacesOutbox,\n};\n\nlet _db: NodePgDatabase<typeof schema> | undefined;\n\nexport function db() {\n if (!_db) _db = drizzle(pgClient(), {schema});\n return _db;\n}\n\nexport function closeDb(): void {\n _db = undefined;\n}\n"],"names":["drizzle","pgClient","workspacesAdminCommandResults","invitations","memberships","workspacesOutbox","workspaces","schema","_db","db","closeDb","undefined"],"mappings":"AAAA,SAAQA,OAAO,QAA4B,wBAAwB;AACnE,SAAQC,QAAQ,QAAO,yBAAyB;AAChD,SAAQC,6BAA6B,QAAO,oCAAoC;AAChF,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,gBAAgB,QAAO,qBAAqB;AACpD,SAAQC,UAAU,QAAO,yBAAyB;AAElD,OAAO,MAAMC,SAAS;IACpBL;IACAI;IACAF;IACAD;IACAE;AACF,EAAE;AAEF,IAAIG;AAEJ,OAAO,SAASC;IACd,IAAI,CAACD,KAAKA,MAAMR,QAAQC,YAAY;QAACM;IAAM;IAC3C,OAAOC;AACT;AAEA,OAAO,SAASE;IACdF,MAAMG;AACR"}
1
+ {"version":3,"sources":["../../src/db/db.ts"],"sourcesContent":["import {drizzle, type NodePgDatabase} from '@shipfox/node-drizzle';\nimport {pgClient} from '@shipfox/node-postgres';\nimport {workspacesAdminCommandResults} from './schema/admin-command-results.js';\nimport {invitations} from './schema/invitations.js';\nimport {memberships} from './schema/memberships.js';\nimport {workspacesOutbox} from './schema/outbox.js';\nimport {workspacesRateLimits} from './schema/rate-limits.js';\nimport {workspaces} from './schema/workspaces.js';\n\nexport const schema = {\n workspacesAdminCommandResults,\n workspaces,\n memberships,\n invitations,\n workspacesOutbox,\n workspacesRateLimits,\n};\n\nlet _db: NodePgDatabase<typeof schema> | undefined;\n\nexport function db() {\n if (!_db) _db = drizzle(pgClient(), {schema});\n return _db;\n}\n\nexport function closeDb(): void {\n _db = undefined;\n}\n"],"names":["drizzle","pgClient","workspacesAdminCommandResults","invitations","memberships","workspacesOutbox","workspacesRateLimits","workspaces","schema","_db","db","closeDb","undefined"],"mappings":"AAAA,SAAQA,OAAO,QAA4B,wBAAwB;AACnE,SAAQC,QAAQ,QAAO,yBAAyB;AAChD,SAAQC,6BAA6B,QAAO,oCAAoC;AAChF,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,gBAAgB,QAAO,qBAAqB;AACpD,SAAQC,oBAAoB,QAAO,0BAA0B;AAC7D,SAAQC,UAAU,QAAO,yBAAyB;AAElD,OAAO,MAAMC,SAAS;IACpBN;IACAK;IACAH;IACAD;IACAE;IACAC;AACF,EAAE;AAEF,IAAIG;AAEJ,OAAO,SAASC;IACd,IAAI,CAACD,KAAKA,MAAMT,QAAQC,YAAY;QAACO;IAAM;IAC3C,OAAOC;AACT;AAEA,OAAO,SAASE;IACdF,MAAMG;AACR"}
@@ -3,9 +3,12 @@ export type { CreateInvitationParams } from './invitations.js';
3
3
  export { createInvitation, findInvitationByToken, listOpenInvitationsByWorkspace, revokeInvitation, } from './invitations.js';
4
4
  export type { CreateMembershipParams, MembershipWithUser, MembershipWithWorkspace, RemoveMembershipParams, } from './memberships.js';
5
5
  export { createMembership, findMembership, listMembershipsByUser, listMembershipsByWorkspace, removeMembership, } from './memberships.js';
6
+ export type { ConsumeWorkspacesRateLimitParams, ConsumeWorkspacesRateLimitResult, } from './rate-limits.js';
7
+ export { consumeWorkspacesRateLimit, pruneExpiredWorkspacesRateLimits, } from './rate-limits.js';
6
8
  export { workspacesAdminCommandResults } from './schema/admin-command-results.js';
7
9
  export { workspacesOutbox } from './schema/outbox.js';
10
+ export { workspacesRateLimits } from './schema/rate-limits.js';
8
11
  export type { AdminWorkspaceRow, CreateWorkspaceParams, ListAdminWorkspaceParams, ListAdminWorkspaceResult, UpdateWorkspaceParams, WorkspaceServiceMetrics, } from './workspaces.js';
9
- export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, listAdminWorkspaces, updateWorkspace, } from './workspaces.js';
12
+ export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, isWorkspaceSlugAvailable, listAdminWorkspaces, updateWorkspace, } from './workspaces.js';
10
13
  export declare const migrationsPath: string;
11
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,6BAA6B,EAAC,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,eAAO,MAAM,cAAc,QAAoE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,6BAA6B,EAAC,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,eAAO,MAAM,cAAc,QAAoE,CAAC"}
package/dist/db/index.js CHANGED
@@ -3,9 +3,11 @@ import { fileURLToPath } from 'node:url';
3
3
  export { closeDb, db, schema } from './db.js';
4
4
  export { createInvitation, findInvitationByToken, listOpenInvitationsByWorkspace, revokeInvitation } from './invitations.js';
5
5
  export { createMembership, findMembership, listMembershipsByUser, listMembershipsByWorkspace, removeMembership } from './memberships.js';
6
+ export { consumeWorkspacesRateLimit, pruneExpiredWorkspacesRateLimits } from './rate-limits.js';
6
7
  export { workspacesAdminCommandResults } from './schema/admin-command-results.js';
7
8
  export { workspacesOutbox } from './schema/outbox.js';
8
- export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, listAdminWorkspaces, updateWorkspace } from './workspaces.js';
9
+ export { workspacesRateLimits } from './schema/rate-limits.js';
10
+ export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, isWorkspaceSlugAvailable, listAdminWorkspaces, updateWorkspace } from './workspaces.js';
9
11
  export const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');
10
12
 
11
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {CreateInvitationParams} from './invitations.js';\nexport {\n createInvitation,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n revokeInvitation,\n} from './invitations.js';\nexport type {\n CreateMembershipParams,\n MembershipWithUser,\n MembershipWithWorkspace,\n RemoveMembershipParams,\n} from './memberships.js';\nexport {\n createMembership,\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n removeMembership,\n} from './memberships.js';\nexport {workspacesAdminCommandResults} from './schema/admin-command-results.js';\nexport {workspacesOutbox} from './schema/outbox.js';\nexport type {\n AdminWorkspaceRow,\n CreateWorkspaceParams,\n ListAdminWorkspaceParams,\n ListAdminWorkspaceResult,\n UpdateWorkspaceParams,\n WorkspaceServiceMetrics,\n} from './workspaces.js';\nexport {\n createWorkspace,\n getWorkspaceById,\n getWorkspaceServiceMetrics,\n listAdminWorkspaces,\n updateWorkspace,\n} from './workspaces.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createInvitation","findInvitationByToken","listOpenInvitationsByWorkspace","revokeInvitation","createMembership","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","workspacesAdminCommandResults","workspacesOutbox","createWorkspace","getWorkspaceById","getWorkspaceServiceMetrics","listAdminWorkspaces","updateWorkspace","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAE5C,SACEC,gBAAgB,EAChBC,qBAAqB,EACrBC,8BAA8B,EAC9BC,gBAAgB,QACX,mBAAmB;AAO1B,SACEC,gBAAgB,EAChBC,cAAc,EACdC,qBAAqB,EACrBC,0BAA0B,EAC1BC,gBAAgB,QACX,mBAAmB;AAC1B,SAAQC,6BAA6B,QAAO,oCAAoC;AAChF,SAAQC,gBAAgB,QAAO,qBAAqB;AASpD,SACEC,eAAe,EACfC,gBAAgB,EAChBC,0BAA0B,EAC1BC,mBAAmB,EACnBC,eAAe,QACV,kBAAkB;AAEzB,OAAO,MAAMC,iBAAiBrB,QAAQD,QAAQE,cAAc,YAAYqB,GAAG,IAAI,iBAAiB"}
1
+ {"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {CreateInvitationParams} from './invitations.js';\nexport {\n createInvitation,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n revokeInvitation,\n} from './invitations.js';\nexport type {\n CreateMembershipParams,\n MembershipWithUser,\n MembershipWithWorkspace,\n RemoveMembershipParams,\n} from './memberships.js';\nexport {\n createMembership,\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n removeMembership,\n} from './memberships.js';\nexport type {\n ConsumeWorkspacesRateLimitParams,\n ConsumeWorkspacesRateLimitResult,\n} from './rate-limits.js';\nexport {\n consumeWorkspacesRateLimit,\n pruneExpiredWorkspacesRateLimits,\n} from './rate-limits.js';\nexport {workspacesAdminCommandResults} from './schema/admin-command-results.js';\nexport {workspacesOutbox} from './schema/outbox.js';\nexport {workspacesRateLimits} from './schema/rate-limits.js';\nexport type {\n AdminWorkspaceRow,\n CreateWorkspaceParams,\n ListAdminWorkspaceParams,\n ListAdminWorkspaceResult,\n UpdateWorkspaceParams,\n WorkspaceServiceMetrics,\n} from './workspaces.js';\nexport {\n createWorkspace,\n getWorkspaceById,\n getWorkspaceServiceMetrics,\n isWorkspaceSlugAvailable,\n listAdminWorkspaces,\n updateWorkspace,\n} from './workspaces.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createInvitation","findInvitationByToken","listOpenInvitationsByWorkspace","revokeInvitation","createMembership","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","consumeWorkspacesRateLimit","pruneExpiredWorkspacesRateLimits","workspacesAdminCommandResults","workspacesOutbox","workspacesRateLimits","createWorkspace","getWorkspaceById","getWorkspaceServiceMetrics","isWorkspaceSlugAvailable","listAdminWorkspaces","updateWorkspace","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAE5C,SACEC,gBAAgB,EAChBC,qBAAqB,EACrBC,8BAA8B,EAC9BC,gBAAgB,QACX,mBAAmB;AAO1B,SACEC,gBAAgB,EAChBC,cAAc,EACdC,qBAAqB,EACrBC,0BAA0B,EAC1BC,gBAAgB,QACX,mBAAmB;AAK1B,SACEC,0BAA0B,EAC1BC,gCAAgC,QAC3B,mBAAmB;AAC1B,SAAQC,6BAA6B,QAAO,oCAAoC;AAChF,SAAQC,gBAAgB,QAAO,qBAAqB;AACpD,SAAQC,oBAAoB,QAAO,0BAA0B;AAS7D,SACEC,eAAe,EACfC,gBAAgB,EAChBC,0BAA0B,EAC1BC,wBAAwB,EACxBC,mBAAmB,EACnBC,eAAe,QACV,kBAAkB;AAEzB,OAAO,MAAMC,iBAAiBzB,QAAQD,QAAQE,cAAc,YAAYyB,GAAG,IAAI,iBAAiB"}
@@ -22,6 +22,7 @@ export declare function createMembership(params: CreateMembershipParams): Promis
22
22
  export declare function ensureMembership(params: EnsureMembershipParams): Promise<Membership>;
23
23
  export interface MembershipWithWorkspace extends Membership {
24
24
  workspaceName: string;
25
+ workspaceSlug: string;
25
26
  workspaceStatus: Workspace['status'];
26
27
  }
27
28
  export declare function listMembershipsByUser(params: {
@@ -1 +1 @@
1
- {"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../../src/db/memberships.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAO3D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB;;;;;EAO9D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAO1F;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgB1F;AAED,MAAM,WAAW,uBAAwB,SAAQ,UAAU;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAiBrC;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAOhC;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAYlC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpF"}
1
+ {"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../../src/db/memberships.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAO3D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB;;;;;EAO9D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAO1F;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgB1F;AAED,MAAM,WAAW,uBAAwB,SAAQ,UAAU;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAmBrC;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAOhC;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAYlC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpF"}
@@ -39,11 +39,13 @@ export async function listMembershipsByUser(params) {
39
39
  const rows = await db().select({
40
40
  membership: memberships,
41
41
  workspaceName: workspaces.name,
42
+ workspaceSlug: workspaces.slug,
42
43
  workspaceStatus: workspaces.status
43
44
  }).from(memberships).innerJoin(workspaces, eq(workspaces.id, memberships.workspaceId)).where(eq(memberships.userId, params.userId)).orderBy(workspaces.name);
44
45
  return rows.map((row)=>({
45
46
  ...toMembership(row.membership),
46
47
  workspaceName: row.workspaceName,
48
+ workspaceSlug: row.workspaceSlug,
47
49
  workspaceStatus: row.workspaceStatus
48
50
  }));
49
51
  }