@shipfox/api-workspaces 9.3.0 → 10.1.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 (64) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +43 -0
  3. package/README.md +5 -2
  4. package/dist/core/admin-workspaces.d.ts +41 -0
  5. package/dist/core/admin-workspaces.d.ts.map +1 -0
  6. package/dist/core/admin-workspaces.js +86 -0
  7. package/dist/core/admin-workspaces.js.map +1 -0
  8. package/dist/core/index.d.ts +1 -0
  9. package/dist/core/index.d.ts.map +1 -1
  10. package/dist/core/index.js +1 -0
  11. package/dist/core/index.js.map +1 -1
  12. package/dist/db/index.d.ts +2 -2
  13. package/dist/db/index.d.ts.map +1 -1
  14. package/dist/db/index.js +1 -1
  15. package/dist/db/index.js.map +1 -1
  16. package/dist/db/memberships.d.ts +2 -0
  17. package/dist/db/memberships.d.ts.map +1 -1
  18. package/dist/db/memberships.js +4 -2
  19. package/dist/db/memberships.js.map +1 -1
  20. package/dist/db/schema/workspaces.d.ts.map +1 -1
  21. package/dist/db/schema/workspaces.js +4 -2
  22. package/dist/db/schema/workspaces.js.map +1 -1
  23. package/dist/db/workspaces.d.ts +16 -0
  24. package/dist/db/workspaces.d.ts.map +1 -1
  25. package/dist/db/workspaces.js +43 -1
  26. package/dist/db/workspaces.js.map +1 -1
  27. package/dist/index.d.ts +11 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +32 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/presentation/dto/membership.d.ts.map +1 -1
  32. package/dist/presentation/dto/membership.js +1 -0
  33. package/dist/presentation/dto/membership.js.map +1 -1
  34. package/dist/presentation/index.d.ts +1 -1
  35. package/dist/presentation/index.d.ts.map +1 -1
  36. package/dist/presentation/index.js +1 -1
  37. package/dist/presentation/index.js.map +1 -1
  38. package/dist/presentation/routes/admin-workspaces.d.ts +10 -0
  39. package/dist/presentation/routes/admin-workspaces.d.ts.map +1 -0
  40. package/dist/presentation/routes/admin-workspaces.js +84 -0
  41. package/dist/presentation/routes/admin-workspaces.js.map +1 -0
  42. package/dist/presentation/routes/index.d.ts +8 -0
  43. package/dist/presentation/routes/index.d.ts.map +1 -1
  44. package/dist/presentation/routes/index.js +7 -0
  45. package/dist/presentation/routes/index.js.map +1 -1
  46. package/dist/tsconfig.test.tsbuildinfo +1 -1
  47. package/drizzle/0001_complex_beast.sql +1 -0
  48. package/drizzle/meta/0001_snapshot.json +476 -0
  49. package/drizzle/meta/_journal.json +7 -0
  50. package/package.json +8 -5
  51. package/src/core/admin-workspaces.ts +114 -0
  52. package/src/core/index.ts +6 -0
  53. package/src/db/index.ts +4 -0
  54. package/src/db/memberships.ts +8 -1
  55. package/src/db/schema/workspaces.ts +14 -10
  56. package/src/db/workspaces.test.ts +25 -0
  57. package/src/db/workspaces.ts +75 -1
  58. package/src/index.ts +27 -2
  59. package/src/presentation/dto/membership.ts +1 -0
  60. package/src/presentation/index.ts +1 -1
  61. package/src/presentation/routes/admin-workspaces.test.ts +168 -0
  62. package/src/presentation/routes/admin-workspaces.ts +93 -0
  63. package/src/presentation/routes/index.ts +12 -0
  64. package/tsconfig.build.tsbuildinfo +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { db, migrationsPath, workspacesOutbox } from '#db/index.js';
4
4
  import { registerWorkspacesServiceMetrics } from '#metrics/index.js';
5
5
  import { workspacesE2eRoutes } from '#presentation/e2eRoutes/index.js';
6
6
  import { createWorkspacesInterModulePresentation } from '#presentation/inter-module.js';
7
- import { workspacesRoutes } from '#presentation/routes/index.js';
7
+ import { createWorkspacesRoutes, workspacesRoutes } from '#presentation/routes/index.js';
8
8
  import { onInvitationSendRequested } from '#presentation/subscribers/index.js';
9
9
  export { InvitationEmailMismatchError, TokenAlreadyUsedError, TokenExpiredError, TokenInvalidError, WorkspaceNotFoundError } from '#core/errors.js';
10
10
  export { acceptWorkspaceInvitation, peekInvitationByRawToken, reconcileWorkspaceInvitationAcceptance } from '#core/invitations.js';
@@ -12,9 +12,38 @@ export { ensureMembership } from '#core/memberships.js';
12
12
  export { getWorkspace, requireWorkspaceMembership } from '#core/workspaces.js';
13
13
  export { db, migrationsPath } from '#db/index.js';
14
14
  export { listMembershipsByUser } from '#db/memberships.js';
15
- export { workspacesRoutes as routes } from '#presentation/routes/index.js';
15
+ export { createWorkspacesRoutes, workspacesRoutes as routes } from '#presentation/routes/index.js';
16
16
  const subscriber = subscriberFactory();
17
- export const workspacesModule = {
17
+ export function createWorkspacesModule(options) {
18
+ return {
19
+ name: 'workspaces',
20
+ database: {
21
+ db,
22
+ migrationsPath,
23
+ databaseNamespace: 'workspaces'
24
+ },
25
+ routes: createWorkspacesRoutes(options),
26
+ e2eRoutes: [
27
+ workspacesE2eRoutes
28
+ ],
29
+ publishers: [
30
+ {
31
+ name: 'workspaces',
32
+ table: workspacesOutbox,
33
+ db,
34
+ eventSchemas: workspacesEventSchemas
35
+ }
36
+ ],
37
+ subscribers: [
38
+ subscriber(WORKSPACES_INVITATION_SEND_REQUESTED, onInvitationSendRequested)
39
+ ],
40
+ metrics: registerWorkspacesServiceMetrics,
41
+ interModulePresentations: [
42
+ createWorkspacesInterModulePresentation()
43
+ ]
44
+ };
45
+ }
46
+ /** @deprecated Use createWorkspacesModule from the application composition root. */ export const workspacesModule = {
18
47
  name: 'workspaces',
19
48
  database: {
20
49
  db,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n WORKSPACES_INVITATION_SEND_REQUESTED,\n type WorkspacesEventMap,\n workspacesEventSchemas,\n} from '@shipfox/api-workspaces-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {subscriberFactory} from '@shipfox/node-module';\nimport {db, migrationsPath, workspacesOutbox} from '#db/index.js';\nimport {registerWorkspacesServiceMetrics} from '#metrics/index.js';\nimport {workspacesE2eRoutes} from '#presentation/e2eRoutes/index.js';\nimport {createWorkspacesInterModulePresentation} from '#presentation/inter-module.js';\nimport {workspacesRoutes} from '#presentation/routes/index.js';\nimport {onInvitationSendRequested} from '#presentation/subscribers/index.js';\n\nexport type {Invitation} from '#core/entities/invitation.js';\nexport type {Membership} from '#core/entities/membership.js';\nexport type {Workspace, WorkspaceStatus} from '#core/entities/workspace.js';\nexport {\n InvitationEmailMismatchError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n TokenInvalidError,\n WorkspaceNotFoundError,\n} from '#core/errors.js';\nexport {\n acceptWorkspaceInvitation,\n peekInvitationByRawToken,\n reconcileWorkspaceInvitationAcceptance,\n type WorkspaceInvitationReconciliation,\n} from '#core/invitations.js';\nexport {type EnsureMembershipParams, ensureMembership} from '#core/memberships.js';\nexport {getWorkspace, requireWorkspaceMembership} from '#core/workspaces.js';\nexport {db, migrationsPath} from '#db/index.js';\nexport {listMembershipsByUser} from '#db/memberships.js';\nexport {workspacesRoutes as routes} from '#presentation/routes/index.js';\n\nconst subscriber = subscriberFactory<WorkspacesEventMap>();\n\nexport const workspacesModule: ShipfoxModule = {\n name: 'workspaces',\n database: {db, migrationsPath, databaseNamespace: 'workspaces'},\n routes: workspacesRoutes,\n e2eRoutes: [workspacesE2eRoutes],\n publishers: [\n {name: 'workspaces', table: workspacesOutbox, db, eventSchemas: workspacesEventSchemas},\n ],\n subscribers: [subscriber(WORKSPACES_INVITATION_SEND_REQUESTED, onInvitationSendRequested)],\n metrics: registerWorkspacesServiceMetrics,\n interModulePresentations: [createWorkspacesInterModulePresentation()],\n};\n"],"names":["WORKSPACES_INVITATION_SEND_REQUESTED","workspacesEventSchemas","subscriberFactory","db","migrationsPath","workspacesOutbox","registerWorkspacesServiceMetrics","workspacesE2eRoutes","createWorkspacesInterModulePresentation","workspacesRoutes","onInvitationSendRequested","InvitationEmailMismatchError","TokenAlreadyUsedError","TokenExpiredError","TokenInvalidError","WorkspaceNotFoundError","acceptWorkspaceInvitation","peekInvitationByRawToken","reconcileWorkspaceInvitationAcceptance","ensureMembership","getWorkspace","requireWorkspaceMembership","listMembershipsByUser","routes","subscriber","workspacesModule","name","database","databaseNamespace","e2eRoutes","publishers","table","eventSchemas","subscribers","metrics","interModulePresentations"],"mappings":"AAAA,SACEA,oCAAoC,EAEpCC,sBAAsB,QACjB,8BAA8B;AAErC,SAAQC,iBAAiB,QAAO,uBAAuB;AACvD,SAAQC,EAAE,EAAEC,cAAc,EAAEC,gBAAgB,QAAO,eAAe;AAClE,SAAQC,gCAAgC,QAAO,oBAAoB;AACnE,SAAQC,mBAAmB,QAAO,mCAAmC;AACrE,SAAQC,uCAAuC,QAAO,gCAAgC;AACtF,SAAQC,gBAAgB,QAAO,gCAAgC;AAC/D,SAAQC,yBAAyB,QAAO,qCAAqC;AAK7E,SACEC,4BAA4B,EAC5BC,qBAAqB,EACrBC,iBAAiB,EACjBC,iBAAiB,EACjBC,sBAAsB,QACjB,kBAAkB;AACzB,SACEC,yBAAyB,EACzBC,wBAAwB,EACxBC,sCAAsC,QAEjC,uBAAuB;AAC9B,SAAqCC,gBAAgB,QAAO,uBAAuB;AACnF,SAAQC,YAAY,EAAEC,0BAA0B,QAAO,sBAAsB;AAC7E,SAAQlB,EAAE,EAAEC,cAAc,QAAO,eAAe;AAChD,SAAQkB,qBAAqB,QAAO,qBAAqB;AACzD,SAAQb,oBAAoBc,MAAM,QAAO,gCAAgC;AAEzE,MAAMC,aAAatB;AAEnB,OAAO,MAAMuB,mBAAkC;IAC7CC,MAAM;IACNC,UAAU;QAACxB;QAAIC;QAAgBwB,mBAAmB;IAAY;IAC9DL,QAAQd;IACRoB,WAAW;QAACtB;KAAoB;IAChCuB,YAAY;QACV;YAACJ,MAAM;YAAcK,OAAO1B;YAAkBF;YAAI6B,cAAc/B;QAAsB;KACvF;IACDgC,aAAa;QAACT,WAAWxB,sCAAsCU;KAA2B;IAC1FwB,SAAS5B;IACT6B,0BAA0B;QAAC3B;KAA0C;AACvE,EAAE"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {RunnersInterModuleClient} from '@shipfox/api-runners-dto/inter-module';\nimport {\n WORKSPACES_INVITATION_SEND_REQUESTED,\n type WorkspacesEventMap,\n workspacesEventSchemas,\n} from '@shipfox/api-workspaces-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {subscriberFactory} from '@shipfox/node-module';\nimport {db, migrationsPath, workspacesOutbox} from '#db/index.js';\nimport {registerWorkspacesServiceMetrics} from '#metrics/index.js';\nimport {workspacesE2eRoutes} from '#presentation/e2eRoutes/index.js';\nimport {createWorkspacesInterModulePresentation} from '#presentation/inter-module.js';\nimport {createWorkspacesRoutes, workspacesRoutes} from '#presentation/routes/index.js';\nimport {onInvitationSendRequested} from '#presentation/subscribers/index.js';\n\nexport type {Invitation} from '#core/entities/invitation.js';\nexport type {Membership} from '#core/entities/membership.js';\nexport type {Workspace, WorkspaceStatus} from '#core/entities/workspace.js';\nexport {\n InvitationEmailMismatchError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n TokenInvalidError,\n WorkspaceNotFoundError,\n} from '#core/errors.js';\nexport {\n acceptWorkspaceInvitation,\n peekInvitationByRawToken,\n reconcileWorkspaceInvitationAcceptance,\n type WorkspaceInvitationReconciliation,\n} from '#core/invitations.js';\nexport {type EnsureMembershipParams, ensureMembership} from '#core/memberships.js';\nexport {getWorkspace, requireWorkspaceMembership} from '#core/workspaces.js';\nexport {db, migrationsPath} from '#db/index.js';\nexport {listMembershipsByUser} from '#db/memberships.js';\nexport {createWorkspacesRoutes, workspacesRoutes as routes} from '#presentation/routes/index.js';\n\nconst subscriber = subscriberFactory<WorkspacesEventMap>();\n\nexport interface WorkspacesModuleOptions {\n auth: AuthInterModuleClient;\n projects: ProjectsModuleClient;\n runners: RunnersInterModuleClient;\n}\n\nexport function createWorkspacesModule(options: WorkspacesModuleOptions): ShipfoxModule {\n return {\n name: 'workspaces',\n database: {db, migrationsPath, databaseNamespace: 'workspaces'},\n routes: createWorkspacesRoutes(options),\n e2eRoutes: [workspacesE2eRoutes],\n publishers: [\n {name: 'workspaces', table: workspacesOutbox, db, eventSchemas: workspacesEventSchemas},\n ],\n subscribers: [subscriber(WORKSPACES_INVITATION_SEND_REQUESTED, onInvitationSendRequested)],\n metrics: registerWorkspacesServiceMetrics,\n interModulePresentations: [createWorkspacesInterModulePresentation()],\n };\n}\n\n/** @deprecated Use createWorkspacesModule from the application composition root. */\nexport const workspacesModule: ShipfoxModule = {\n name: 'workspaces',\n database: {db, migrationsPath, databaseNamespace: 'workspaces'},\n routes: workspacesRoutes,\n e2eRoutes: [workspacesE2eRoutes],\n publishers: [\n {name: 'workspaces', table: workspacesOutbox, db, eventSchemas: workspacesEventSchemas},\n ],\n subscribers: [subscriber(WORKSPACES_INVITATION_SEND_REQUESTED, onInvitationSendRequested)],\n metrics: registerWorkspacesServiceMetrics,\n interModulePresentations: [createWorkspacesInterModulePresentation()],\n};\n"],"names":["WORKSPACES_INVITATION_SEND_REQUESTED","workspacesEventSchemas","subscriberFactory","db","migrationsPath","workspacesOutbox","registerWorkspacesServiceMetrics","workspacesE2eRoutes","createWorkspacesInterModulePresentation","createWorkspacesRoutes","workspacesRoutes","onInvitationSendRequested","InvitationEmailMismatchError","TokenAlreadyUsedError","TokenExpiredError","TokenInvalidError","WorkspaceNotFoundError","acceptWorkspaceInvitation","peekInvitationByRawToken","reconcileWorkspaceInvitationAcceptance","ensureMembership","getWorkspace","requireWorkspaceMembership","listMembershipsByUser","routes","subscriber","createWorkspacesModule","options","name","database","databaseNamespace","e2eRoutes","publishers","table","eventSchemas","subscribers","metrics","interModulePresentations","workspacesModule"],"mappings":"AAGA,SACEA,oCAAoC,EAEpCC,sBAAsB,QACjB,8BAA8B;AAErC,SAAQC,iBAAiB,QAAO,uBAAuB;AACvD,SAAQC,EAAE,EAAEC,cAAc,EAAEC,gBAAgB,QAAO,eAAe;AAClE,SAAQC,gCAAgC,QAAO,oBAAoB;AACnE,SAAQC,mBAAmB,QAAO,mCAAmC;AACrE,SAAQC,uCAAuC,QAAO,gCAAgC;AACtF,SAAQC,sBAAsB,EAAEC,gBAAgB,QAAO,gCAAgC;AACvF,SAAQC,yBAAyB,QAAO,qCAAqC;AAK7E,SACEC,4BAA4B,EAC5BC,qBAAqB,EACrBC,iBAAiB,EACjBC,iBAAiB,EACjBC,sBAAsB,QACjB,kBAAkB;AACzB,SACEC,yBAAyB,EACzBC,wBAAwB,EACxBC,sCAAsC,QAEjC,uBAAuB;AAC9B,SAAqCC,gBAAgB,QAAO,uBAAuB;AACnF,SAAQC,YAAY,EAAEC,0BAA0B,QAAO,sBAAsB;AAC7E,SAAQnB,EAAE,EAAEC,cAAc,QAAO,eAAe;AAChD,SAAQmB,qBAAqB,QAAO,qBAAqB;AACzD,SAAQd,sBAAsB,EAAEC,oBAAoBc,MAAM,QAAO,gCAAgC;AAEjG,MAAMC,aAAavB;AAQnB,OAAO,SAASwB,uBAAuBC,OAAgC;IACrE,OAAO;QACLC,MAAM;QACNC,UAAU;YAAC1B;YAAIC;YAAgB0B,mBAAmB;QAAY;QAC9DN,QAAQf,uBAAuBkB;QAC/BI,WAAW;YAACxB;SAAoB;QAChCyB,YAAY;YACV;gBAACJ,MAAM;gBAAcK,OAAO5B;gBAAkBF;gBAAI+B,cAAcjC;YAAsB;SACvF;QACDkC,aAAa;YAACV,WAAWzB,sCAAsCW;SAA2B;QAC1FyB,SAAS9B;QACT+B,0BAA0B;YAAC7B;SAA0C;IACvE;AACF;AAEA,kFAAkF,GAClF,OAAO,MAAM8B,mBAAkC;IAC7CV,MAAM;IACNC,UAAU;QAAC1B;QAAIC;QAAgB0B,mBAAmB;IAAY;IAC9DN,QAAQd;IACRqB,WAAW;QAACxB;KAAoB;IAChCyB,YAAY;QACV;YAACJ,MAAM;YAAcK,OAAO5B;YAAkBF;YAAI+B,cAAcjC;QAAsB;KACvF;IACDkC,aAAa;QAACV,WAAWzB,sCAAsCW;KAA2B;IAC1FyB,SAAS9B;IACT+B,0BAA0B;QAAC7B;KAA0C;AACvE,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/membership.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAE,0BAA0B,EAAC,MAAM,6BAA6B,CAAC;AACnG,OAAO,KAAK,EAAC,kBAAkB,EAAE,uBAAuB,EAAC,MAAM,oBAAoB,CAAC;AAEpF,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,uBAAuB,GAClC,0BAA0B,CAS5B;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,qBAAqB,CAU7F"}
1
+ {"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/membership.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAE,0BAA0B,EAAC,MAAM,6BAA6B,CAAC;AACnG,OAAO,KAAK,EAAC,kBAAkB,EAAE,uBAAuB,EAAC,MAAM,oBAAoB,CAAC;AAEpF,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,uBAAuB,GAClC,0BAA0B,CAU5B;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,qBAAqB,CAU7F"}
@@ -4,6 +4,7 @@ export function toMembershipWithWorkspaceDto(membership) {
4
4
  user_id: membership.userId,
5
5
  workspace_id: membership.workspaceId,
6
6
  workspace_name: membership.workspaceName,
7
+ workspace_status: membership.workspaceStatus,
7
8
  created_at: membership.createdAt.toISOString(),
8
9
  updated_at: membership.updatedAt.toISOString()
9
10
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/dto/membership.ts"],"sourcesContent":["import type {MembershipWithUserDto, MembershipWithWorkspaceDto} from '@shipfox/api-workspaces-dto';\nimport type {MembershipWithUser, MembershipWithWorkspace} from '#db/memberships.js';\n\nexport function toMembershipWithWorkspaceDto(\n membership: MembershipWithWorkspace,\n): MembershipWithWorkspaceDto {\n return {\n id: membership.id,\n user_id: membership.userId,\n workspace_id: membership.workspaceId,\n workspace_name: membership.workspaceName,\n created_at: membership.createdAt.toISOString(),\n updated_at: membership.updatedAt.toISOString(),\n };\n}\n\nexport function toMembershipWithUserDto(membership: MembershipWithUser): MembershipWithUserDto {\n return {\n id: membership.id,\n user_id: membership.userId,\n workspace_id: membership.workspaceId,\n user_email: membership.userEmail,\n user_name: membership.userName,\n created_at: membership.createdAt.toISOString(),\n updated_at: membership.updatedAt.toISOString(),\n };\n}\n"],"names":["toMembershipWithWorkspaceDto","membership","id","user_id","userId","workspace_id","workspaceId","workspace_name","workspaceName","created_at","createdAt","toISOString","updated_at","updatedAt","toMembershipWithUserDto","user_email","userEmail","user_name","userName"],"mappings":"AAGA,OAAO,SAASA,6BACdC,UAAmC;IAEnC,OAAO;QACLC,IAAID,WAAWC,EAAE;QACjBC,SAASF,WAAWG,MAAM;QAC1BC,cAAcJ,WAAWK,WAAW;QACpCC,gBAAgBN,WAAWO,aAAa;QACxCC,YAAYR,WAAWS,SAAS,CAACC,WAAW;QAC5CC,YAAYX,WAAWY,SAAS,CAACF,WAAW;IAC9C;AACF;AAEA,OAAO,SAASG,wBAAwBb,UAA8B;IACpE,OAAO;QACLC,IAAID,WAAWC,EAAE;QACjBC,SAASF,WAAWG,MAAM;QAC1BC,cAAcJ,WAAWK,WAAW;QACpCS,YAAYd,WAAWe,SAAS;QAChCC,WAAWhB,WAAWiB,QAAQ;QAC9BT,YAAYR,WAAWS,SAAS,CAACC,WAAW;QAC5CC,YAAYX,WAAWY,SAAS,CAACF,WAAW;IAC9C;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/dto/membership.ts"],"sourcesContent":["import type {MembershipWithUserDto, MembershipWithWorkspaceDto} from '@shipfox/api-workspaces-dto';\nimport type {MembershipWithUser, MembershipWithWorkspace} from '#db/memberships.js';\n\nexport function toMembershipWithWorkspaceDto(\n membership: MembershipWithWorkspace,\n): MembershipWithWorkspaceDto {\n return {\n id: membership.id,\n user_id: membership.userId,\n workspace_id: membership.workspaceId,\n workspace_name: membership.workspaceName,\n workspace_status: membership.workspaceStatus,\n created_at: membership.createdAt.toISOString(),\n updated_at: membership.updatedAt.toISOString(),\n };\n}\n\nexport function toMembershipWithUserDto(membership: MembershipWithUser): MembershipWithUserDto {\n return {\n id: membership.id,\n user_id: membership.userId,\n workspace_id: membership.workspaceId,\n user_email: membership.userEmail,\n user_name: membership.userName,\n created_at: membership.createdAt.toISOString(),\n updated_at: membership.updatedAt.toISOString(),\n };\n}\n"],"names":["toMembershipWithWorkspaceDto","membership","id","user_id","userId","workspace_id","workspaceId","workspace_name","workspaceName","workspace_status","workspaceStatus","created_at","createdAt","toISOString","updated_at","updatedAt","toMembershipWithUserDto","user_email","userEmail","user_name","userName"],"mappings":"AAGA,OAAO,SAASA,6BACdC,UAAmC;IAEnC,OAAO;QACLC,IAAID,WAAWC,EAAE;QACjBC,SAASF,WAAWG,MAAM;QAC1BC,cAAcJ,WAAWK,WAAW;QACpCC,gBAAgBN,WAAWO,aAAa;QACxCC,kBAAkBR,WAAWS,eAAe;QAC5CC,YAAYV,WAAWW,SAAS,CAACC,WAAW;QAC5CC,YAAYb,WAAWc,SAAS,CAACF,WAAW;IAC9C;AACF;AAEA,OAAO,SAASG,wBAAwBf,UAA8B;IACpE,OAAO;QACLC,IAAID,WAAWC,EAAE;QACjBC,SAASF,WAAWG,MAAM;QAC1BC,cAAcJ,WAAWK,WAAW;QACpCW,YAAYhB,WAAWiB,SAAS;QAChCC,WAAWlB,WAAWmB,QAAQ;QAC9BT,YAAYV,WAAWW,SAAS,CAACC,WAAW;QAC5CC,YAAYb,WAAWc,SAAS,CAACF,WAAW;IAC9C;AACF"}
@@ -1,2 +1,2 @@
1
- export { workspacesRoutes as routes } from './routes/index.js';
1
+ export { createWorkspacesRoutes, workspacesRoutes as routes } from './routes/index.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,IAAI,MAAM,EAAC,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAE,gBAAgB,IAAI,MAAM,EAAC,MAAM,mBAAmB,CAAC"}
@@ -1,3 +1,3 @@
1
- export { workspacesRoutes as routes } from './routes/index.js';
1
+ export { createWorkspacesRoutes, workspacesRoutes as routes } from './routes/index.js';
2
2
 
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/presentation/index.ts"],"sourcesContent":["export {workspacesRoutes as routes} from './routes/index.js';\n"],"names":["workspacesRoutes","routes"],"mappings":"AAAA,SAAQA,oBAAoBC,MAAM,QAAO,oBAAoB"}
1
+ {"version":3,"sources":["../../src/presentation/index.ts"],"sourcesContent":["export {createWorkspacesRoutes, workspacesRoutes as routes} from './routes/index.js';\n"],"names":["createWorkspacesRoutes","workspacesRoutes","routes"],"mappings":"AAAA,SAAQA,sBAAsB,EAAEC,oBAAoBC,MAAM,QAAO,oBAAoB"}
@@ -0,0 +1,10 @@
1
+ import { type AuthInterModuleClient } from '@shipfox/api-auth-dto/inter-module';
2
+ import type { ProjectsModuleClient } from '@shipfox/api-projects-dto/inter-module';
3
+ import type { RunnersInterModuleClient } from '@shipfox/api-runners-dto/inter-module';
4
+ import { type RouteGroup } from '@shipfox/node-fastify';
5
+ export declare function createAdminWorkspacesRoutes(params: {
6
+ auth: AuthInterModuleClient;
7
+ projects: ProjectsModuleClient;
8
+ runners: RunnersInterModuleClient;
9
+ }): RouteGroup;
10
+ //# sourceMappingURL=admin-workspaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-workspaces.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/admin-workspaces.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAOpF,OAAO,EAA2B,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAmBhF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,wBAAwB,CAAC;CACnC,GAAG,UAAU,CAwDb"}
@@ -0,0 +1,84 @@
1
+ import { AUTH_USER, getUserContext } from '@shipfox/api-auth-context';
2
+ import { authInterModuleContract } from '@shipfox/api-auth-dto/inter-module';
3
+ import { listWorkspaceAdminSummariesResponseSchema, workspaceAdminLookupQuerySchema } from '@shipfox/api-workspaces-dto';
4
+ import { isInterModuleKnownError } from '@shipfox/inter-module';
5
+ import { decodeStringIdCursor, encodeStringIdCursor } from '@shipfox/node-drizzle';
6
+ import { ClientError, defineRoute } from '@shipfox/node-fastify';
7
+ import { listWorkspaceAdministratorSummaries } from '#core/admin-workspaces.js';
8
+ function toWorkspaceAdministratorSummaryDto(summary) {
9
+ return {
10
+ id: summary.id,
11
+ name: summary.name,
12
+ status: summary.status,
13
+ member_summary: summary.memberSummary,
14
+ project_summary: summary.projectSummary,
15
+ job_counts: summary.jobCounts,
16
+ created_at: summary.createdAt.toISOString(),
17
+ updated_at: summary.updatedAt.toISOString()
18
+ };
19
+ }
20
+ export function createAdminWorkspacesRoutes(params) {
21
+ const listRoute = defineRoute({
22
+ method: 'GET',
23
+ path: '/',
24
+ description: 'List bounded safe workspace summaries for administrators.',
25
+ auth: AUTH_USER,
26
+ schema: {
27
+ querystring: workspaceAdminLookupQuerySchema,
28
+ response: {
29
+ 200: listWorkspaceAdminSummariesResponseSchema
30
+ }
31
+ },
32
+ errorHandler: (error)=>{
33
+ if (isInterModuleKnownError(authInterModuleContract.methods.requireAdminRole, error) && error.code === 'admin-role-required') {
34
+ throw new ClientError('Administrator observer role required', 'forbidden', {
35
+ status: 403,
36
+ details: {
37
+ required_role: error.details.requiredRole
38
+ }
39
+ });
40
+ }
41
+ throw error;
42
+ },
43
+ handler: async (request)=>{
44
+ const client = getUserContext(request);
45
+ if (!client) {
46
+ throw new ClientError('Authentication required', 'unauthorized', {
47
+ status: 401
48
+ });
49
+ }
50
+ await params.auth.requireAdminRole({
51
+ userId: client.userId,
52
+ minimumRole: 'admin-observer'
53
+ });
54
+ const { workspace_id: workspaceId, search, status, limit, cursor } = request.query;
55
+ const decodedCursor = decodeStringIdCursor(cursor);
56
+ if (cursor && !decodedCursor) {
57
+ throw new ClientError('Invalid cursor', 'invalid-cursor', {
58
+ status: 400
59
+ });
60
+ }
61
+ const result = await listWorkspaceAdministratorSummaries({
62
+ workspaceId,
63
+ search,
64
+ status,
65
+ limit,
66
+ cursor: decodedCursor,
67
+ projects: params.projects,
68
+ runners: params.runners
69
+ });
70
+ return {
71
+ workspaces: result.workspaces.map(toWorkspaceAdministratorSummaryDto),
72
+ next_cursor: result.nextCursor ? encodeStringIdCursor(result.nextCursor) : null
73
+ };
74
+ }
75
+ });
76
+ return {
77
+ prefix: '/admin/workspaces',
78
+ routes: [
79
+ listRoute
80
+ ]
81
+ };
82
+ }
83
+
84
+ //# sourceMappingURL=admin-workspaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/routes/admin-workspaces.ts"],"sourcesContent":["import {AUTH_USER, getUserContext} from '@shipfox/api-auth-context';\nimport {\n type AuthInterModuleClient,\n authInterModuleContract,\n} from '@shipfox/api-auth-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {RunnersInterModuleClient} from '@shipfox/api-runners-dto/inter-module';\nimport {\n listWorkspaceAdminSummariesResponseSchema,\n workspaceAdminLookupQuerySchema,\n} from '@shipfox/api-workspaces-dto';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {decodeStringIdCursor, encodeStringIdCursor} from '@shipfox/node-drizzle';\nimport {ClientError, defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport {\n listWorkspaceAdministratorSummaries,\n type WorkspaceAdministratorSummary,\n} from '#core/admin-workspaces.js';\n\nfunction toWorkspaceAdministratorSummaryDto(summary: WorkspaceAdministratorSummary) {\n return {\n id: summary.id,\n name: summary.name,\n status: summary.status,\n member_summary: summary.memberSummary,\n project_summary: summary.projectSummary,\n job_counts: summary.jobCounts,\n created_at: summary.createdAt.toISOString(),\n updated_at: summary.updatedAt.toISOString(),\n };\n}\n\nexport function createAdminWorkspacesRoutes(params: {\n auth: AuthInterModuleClient;\n projects: ProjectsModuleClient;\n runners: RunnersInterModuleClient;\n}): RouteGroup {\n const listRoute = defineRoute({\n method: 'GET',\n path: '/',\n description: 'List bounded safe workspace summaries for administrators.',\n auth: AUTH_USER,\n schema: {\n querystring: workspaceAdminLookupQuerySchema,\n response: {200: listWorkspaceAdminSummariesResponseSchema},\n },\n errorHandler: (error) => {\n if (\n isInterModuleKnownError(authInterModuleContract.methods.requireAdminRole, error) &&\n error.code === 'admin-role-required'\n ) {\n throw new ClientError('Administrator observer role required', 'forbidden', {\n status: 403,\n details: {required_role: error.details.requiredRole},\n });\n }\n throw error;\n },\n handler: async (request) => {\n const client = getUserContext(request);\n if (!client) {\n throw new ClientError('Authentication required', 'unauthorized', {status: 401});\n }\n await params.auth.requireAdminRole({\n userId: client.userId,\n minimumRole: 'admin-observer',\n });\n\n const {workspace_id: workspaceId, search, status, limit, cursor} = request.query;\n const decodedCursor = decodeStringIdCursor(cursor);\n if (cursor && !decodedCursor) {\n throw new ClientError('Invalid cursor', 'invalid-cursor', {status: 400});\n }\n\n const result = await listWorkspaceAdministratorSummaries({\n workspaceId,\n search,\n status,\n limit,\n cursor: decodedCursor,\n projects: params.projects,\n runners: params.runners,\n });\n\n return {\n workspaces: result.workspaces.map(toWorkspaceAdministratorSummaryDto),\n next_cursor: result.nextCursor ? encodeStringIdCursor(result.nextCursor) : null,\n };\n },\n });\n\n return {prefix: '/admin/workspaces', routes: [listRoute]};\n}\n"],"names":["AUTH_USER","getUserContext","authInterModuleContract","listWorkspaceAdminSummariesResponseSchema","workspaceAdminLookupQuerySchema","isInterModuleKnownError","decodeStringIdCursor","encodeStringIdCursor","ClientError","defineRoute","listWorkspaceAdministratorSummaries","toWorkspaceAdministratorSummaryDto","summary","id","name","status","member_summary","memberSummary","project_summary","projectSummary","job_counts","jobCounts","created_at","createdAt","toISOString","updated_at","updatedAt","createAdminWorkspacesRoutes","params","listRoute","method","path","description","auth","schema","querystring","response","errorHandler","error","methods","requireAdminRole","code","details","required_role","requiredRole","handler","request","client","userId","minimumRole","workspace_id","workspaceId","search","limit","cursor","query","decodedCursor","result","projects","runners","workspaces","map","next_cursor","nextCursor","prefix","routes"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,cAAc,QAAO,4BAA4B;AACpE,SAEEC,uBAAuB,QAClB,qCAAqC;AAG5C,SACEC,yCAAyC,EACzCC,+BAA+B,QAC1B,8BAA8B;AACrC,SAAQC,uBAAuB,QAAO,wBAAwB;AAC9D,SAAQC,oBAAoB,EAAEC,oBAAoB,QAAO,wBAAwB;AACjF,SAAQC,WAAW,EAAEC,WAAW,QAAwB,wBAAwB;AAChF,SACEC,mCAAmC,QAE9B,4BAA4B;AAEnC,SAASC,mCAAmCC,OAAsC;IAChF,OAAO;QACLC,IAAID,QAAQC,EAAE;QACdC,MAAMF,QAAQE,IAAI;QAClBC,QAAQH,QAAQG,MAAM;QACtBC,gBAAgBJ,QAAQK,aAAa;QACrCC,iBAAiBN,QAAQO,cAAc;QACvCC,YAAYR,QAAQS,SAAS;QAC7BC,YAAYV,QAAQW,SAAS,CAACC,WAAW;QACzCC,YAAYb,QAAQc,SAAS,CAACF,WAAW;IAC3C;AACF;AAEA,OAAO,SAASG,4BAA4BC,MAI3C;IACC,MAAMC,YAAYpB,YAAY;QAC5BqB,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,MAAMjC;QACNkC,QAAQ;YACNC,aAAa/B;YACbgC,UAAU;gBAAC,KAAKjC;YAAyC;QAC3D;QACAkC,cAAc,CAACC;YACb,IACEjC,wBAAwBH,wBAAwBqC,OAAO,CAACC,gBAAgB,EAAEF,UAC1EA,MAAMG,IAAI,KAAK,uBACf;gBACA,MAAM,IAAIjC,YAAY,wCAAwC,aAAa;oBACzEO,QAAQ;oBACR2B,SAAS;wBAACC,eAAeL,MAAMI,OAAO,CAACE,YAAY;oBAAA;gBACrD;YACF;YACA,MAAMN;QACR;QACAO,SAAS,OAAOC;YACd,MAAMC,SAAS9C,eAAe6C;YAC9B,IAAI,CAACC,QAAQ;gBACX,MAAM,IAAIvC,YAAY,2BAA2B,gBAAgB;oBAACO,QAAQ;gBAAG;YAC/E;YACA,MAAMa,OAAOK,IAAI,CAACO,gBAAgB,CAAC;gBACjCQ,QAAQD,OAAOC,MAAM;gBACrBC,aAAa;YACf;YAEA,MAAM,EAACC,cAAcC,WAAW,EAAEC,MAAM,EAAErC,MAAM,EAAEsC,KAAK,EAAEC,MAAM,EAAC,GAAGR,QAAQS,KAAK;YAChF,MAAMC,gBAAgBlD,qBAAqBgD;YAC3C,IAAIA,UAAU,CAACE,eAAe;gBAC5B,MAAM,IAAIhD,YAAY,kBAAkB,kBAAkB;oBAACO,QAAQ;gBAAG;YACxE;YAEA,MAAM0C,SAAS,MAAM/C,oCAAoC;gBACvDyC;gBACAC;gBACArC;gBACAsC;gBACAC,QAAQE;gBACRE,UAAU9B,OAAO8B,QAAQ;gBACzBC,SAAS/B,OAAO+B,OAAO;YACzB;YAEA,OAAO;gBACLC,YAAYH,OAAOG,UAAU,CAACC,GAAG,CAAClD;gBAClCmD,aAAaL,OAAOM,UAAU,GAAGxD,qBAAqBkD,OAAOM,UAAU,IAAI;YAC7E;QACF;IACF;IAEA,OAAO;QAACC,QAAQ;QAAqBC,QAAQ;YAACpC;SAAU;IAAA;AAC1D"}
@@ -1,3 +1,11 @@
1
+ import type { AuthInterModuleClient } from '@shipfox/api-auth-dto/inter-module';
2
+ import type { ProjectsModuleClient } from '@shipfox/api-projects-dto/inter-module';
3
+ import type { RunnersInterModuleClient } from '@shipfox/api-runners-dto/inter-module';
1
4
  import type { RouteGroup } from '@shipfox/node-fastify';
2
5
  export declare const workspacesRoutes: RouteGroup[];
6
+ export declare function createWorkspacesRoutes(params: {
7
+ auth: AuthInterModuleClient;
8
+ projects: ProjectsModuleClient;
9
+ runners: RunnersInterModuleClient;
10
+ }): RouteGroup[];
3
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAKtD,eAAO,MAAM,gBAAgB,EAAE,UAAU,EAiBxC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AACpF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAMtD,eAAO,MAAM,gBAAgB,EAAE,UAAU,EAiBxC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,wBAAwB,CAAC;CACnC,GAAG,UAAU,EAAE,CAEf"}
@@ -1,3 +1,4 @@
1
+ import { createAdminWorkspacesRoutes } from './admin-workspaces.js';
1
2
  import { invitationsAcceptGroup, invitationsWorkspaceScopedRoutes } from './invitations/index.js';
2
3
  import { memberRoutes } from './members/index.js';
3
4
  import { createWorkspaceRoute, listUserWorkspacesRoute } from './workspaces/index.js';
@@ -19,5 +20,11 @@ export const workspacesRoutes = [
19
20
  ]
20
21
  }
21
22
  ];
23
+ export function createWorkspacesRoutes(params) {
24
+ return [
25
+ ...workspacesRoutes,
26
+ createAdminWorkspacesRoutes(params)
27
+ ];
28
+ }
22
29
 
23
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {RouteGroup} from '@shipfox/node-fastify';\nimport {invitationsAcceptGroup, invitationsWorkspaceScopedRoutes} from './invitations/index.js';\nimport {memberRoutes} from './members/index.js';\nimport {createWorkspaceRoute, listUserWorkspacesRoute} from './workspaces/index.js';\n\nexport const workspacesRoutes: RouteGroup[] = [\n invitationsAcceptGroup,\n {\n prefix: '/workspaces',\n routes: [\n listUserWorkspacesRoute,\n createWorkspaceRoute,\n {\n prefix: '/:workspaceId/members',\n routes: memberRoutes,\n },\n {\n prefix: '/:workspaceId/invitations',\n routes: invitationsWorkspaceScopedRoutes,\n },\n ],\n },\n];\n"],"names":["invitationsAcceptGroup","invitationsWorkspaceScopedRoutes","memberRoutes","createWorkspaceRoute","listUserWorkspacesRoute","workspacesRoutes","prefix","routes"],"mappings":"AACA,SAAQA,sBAAsB,EAAEC,gCAAgC,QAAO,yBAAyB;AAChG,SAAQC,YAAY,QAAO,qBAAqB;AAChD,SAAQC,oBAAoB,EAAEC,uBAAuB,QAAO,wBAAwB;AAEpF,OAAO,MAAMC,mBAAiC;IAC5CL;IACA;QACEM,QAAQ;QACRC,QAAQ;YACNH;YACAD;YACA;gBACEG,QAAQ;gBACRC,QAAQL;YACV;YACA;gBACEI,QAAQ;gBACRC,QAAQN;YACV;SACD;IACH;CACD,CAAC"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {RunnersInterModuleClient} from '@shipfox/api-runners-dto/inter-module';\nimport type {RouteGroup} from '@shipfox/node-fastify';\nimport {createAdminWorkspacesRoutes} from './admin-workspaces.js';\nimport {invitationsAcceptGroup, invitationsWorkspaceScopedRoutes} from './invitations/index.js';\nimport {memberRoutes} from './members/index.js';\nimport {createWorkspaceRoute, listUserWorkspacesRoute} from './workspaces/index.js';\n\nexport const workspacesRoutes: RouteGroup[] = [\n invitationsAcceptGroup,\n {\n prefix: '/workspaces',\n routes: [\n listUserWorkspacesRoute,\n createWorkspaceRoute,\n {\n prefix: '/:workspaceId/members',\n routes: memberRoutes,\n },\n {\n prefix: '/:workspaceId/invitations',\n routes: invitationsWorkspaceScopedRoutes,\n },\n ],\n },\n];\n\nexport function createWorkspacesRoutes(params: {\n auth: AuthInterModuleClient;\n projects: ProjectsModuleClient;\n runners: RunnersInterModuleClient;\n}): RouteGroup[] {\n return [...workspacesRoutes, createAdminWorkspacesRoutes(params)];\n}\n"],"names":["createAdminWorkspacesRoutes","invitationsAcceptGroup","invitationsWorkspaceScopedRoutes","memberRoutes","createWorkspaceRoute","listUserWorkspacesRoute","workspacesRoutes","prefix","routes","createWorkspacesRoutes","params"],"mappings":"AAIA,SAAQA,2BAA2B,QAAO,wBAAwB;AAClE,SAAQC,sBAAsB,EAAEC,gCAAgC,QAAO,yBAAyB;AAChG,SAAQC,YAAY,QAAO,qBAAqB;AAChD,SAAQC,oBAAoB,EAAEC,uBAAuB,QAAO,wBAAwB;AAEpF,OAAO,MAAMC,mBAAiC;IAC5CL;IACA;QACEM,QAAQ;QACRC,QAAQ;YACNH;YACAD;YACA;gBACEG,QAAQ;gBACRC,QAAQL;YACV;YACA;gBACEI,QAAQ;gBACRC,QAAQN;YACV;SACD;IACH;CACD,CAAC;AAEF,OAAO,SAASO,uBAAuBC,MAItC;IACC,OAAO;WAAIJ;QAAkBN,4BAA4BU;KAAQ;AACnE"}