@shipfox/api-workspaces 10.1.0 → 11.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +33 -0
- package/README.md +7 -1
- package/dist/core/admin-workspaces.d.ts +16 -0
- package/dist/core/admin-workspaces.d.ts.map +1 -1
- package/dist/core/admin-workspaces.js +52 -0
- package/dist/core/admin-workspaces.js.map +1 -1
- package/dist/core/errors.d.ts +12 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +24 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/invitations.d.ts.map +1 -1
- package/dist/core/invitations.js +6 -3
- package/dist/core/invitations.js.map +1 -1
- package/dist/core/workspaces.d.ts +1 -0
- package/dist/core/workspaces.d.ts.map +1 -1
- package/dist/core/workspaces.js +5 -3
- package/dist/core/workspaces.js.map +1 -1
- package/dist/db/admin-workspace-commands.d.ts +17 -0
- package/dist/db/admin-workspace-commands.d.ts.map +1 -0
- package/dist/db/admin-workspace-commands.js +86 -0
- package/dist/db/admin-workspace-commands.js.map +1 -0
- package/dist/db/db.d.ts +256 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +2 -0
- package/dist/db/db.js.map +1 -1
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema/admin-command-results.d.ts +135 -0
- package/dist/db/schema/admin-command-results.d.ts.map +1 -0
- package/dist/db/schema/admin-command-results.js +18 -0
- package/dist/db/schema/admin-command-results.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +3 -2
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/admin-workspaces.d.ts.map +1 -1
- package/dist/presentation/routes/admin-workspaces.js +119 -14
- package/dist/presentation/routes/admin-workspaces.js.map +1 -1
- package/dist/presentation/routes/invitations/create.d.ts.map +1 -1
- package/dist/presentation/routes/invitations/create.js +5 -1
- package/dist/presentation/routes/invitations/create.js.map +1 -1
- package/dist/presentation/routes/invitations/list.d.ts.map +1 -1
- package/dist/presentation/routes/invitations/list.js +5 -1
- package/dist/presentation/routes/invitations/list.js.map +1 -1
- package/dist/presentation/routes/invitations/revoke.d.ts.map +1 -1
- package/dist/presentation/routes/invitations/revoke.js +5 -1
- package/dist/presentation/routes/invitations/revoke.js.map +1 -1
- package/dist/presentation/routes/members/list.d.ts.map +1 -1
- package/dist/presentation/routes/members/list.js +5 -1
- package/dist/presentation/routes/members/list.js.map +1 -1
- package/dist/presentation/routes/members/remove.d.ts.map +1 -1
- package/dist/presentation/routes/members/remove.js +5 -1
- package/dist/presentation/routes/members/remove.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0002_wide_enchantress.sql +11 -0
- package/drizzle/meta/0002_snapshot.json +555 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/src/core/admin-workspaces.ts +102 -0
- package/src/core/errors.ts +28 -0
- package/src/core/index.ts +8 -0
- package/src/core/invitations.test.ts +8 -8
- package/src/core/invitations.ts +3 -0
- package/src/core/workspaces.test.ts +22 -3
- package/src/core/workspaces.ts +4 -1
- package/src/db/admin-workspace-commands.ts +169 -0
- package/src/db/db.ts +2 -0
- package/src/db/index.ts +1 -0
- package/src/db/schema/admin-command-results.ts +30 -0
- package/src/index.test.ts +3 -1
- package/src/index.ts +17 -2
- package/src/presentation/inter-module.test.ts +51 -0
- package/src/presentation/inter-module.ts +7 -4
- package/src/presentation/routes/admin-workspaces.test.ts +273 -3
- package/src/presentation/routes/admin-workspaces.ts +143 -13
- package/src/presentation/routes/invitations/create.test.ts +15 -0
- package/src/presentation/routes/invitations/create.ts +2 -1
- package/src/presentation/routes/invitations/list.test.ts +30 -0
- package/src/presentation/routes/invitations/list.ts +2 -1
- package/src/presentation/routes/invitations/revoke.test.ts +14 -0
- package/src/presentation/routes/invitations/revoke.ts +2 -1
- package/src/presentation/routes/members/list.test.ts +29 -1
- package/src/presentation/routes/members/list.ts +2 -1
- package/src/presentation/routes/members/remove.test.ts +14 -0
- package/src/presentation/routes/members/remove.ts +2 -1
- package/test/globalSetup.ts +3 -1
- package/test/routes.ts +8 -3
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vitest.config.ts +3 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 52 files with swc (485.39ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @shipfox/api-workspaces
|
|
2
2
|
|
|
3
|
+
## 11.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 25158c8: Carry workspace lifecycle status in JWT membership claims and enforce suspended or inactive access at the stateless workspace gate while keeping access-token verification stateless.
|
|
8
|
+
|
|
9
|
+
`getAuthenticatedSessionContext()` now reads refresh-session metadata from verified access-token claims without checking active refresh-session state; revoking a refresh session does not invalidate an already-issued access token.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [25158c8]
|
|
14
|
+
- @shipfox/api-auth-context@11.0.0
|
|
15
|
+
- @shipfox/api-workspaces-dto@11.0.0
|
|
16
|
+
|
|
17
|
+
## 10.2.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 07e7371: Add idempotent administrator workspace suspension and reactivation commands with atomic redacted administration events.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [c9a188d]
|
|
26
|
+
- Updated dependencies [8678943]
|
|
27
|
+
- Updated dependencies [95d1456]
|
|
28
|
+
- Updated dependencies [0773b85]
|
|
29
|
+
- Updated dependencies [6be5a54]
|
|
30
|
+
- Updated dependencies [07e7371]
|
|
31
|
+
- @shipfox/api-runners-dto@10.2.0
|
|
32
|
+
- @shipfox/api-auth-dto@10.2.0
|
|
33
|
+
- @shipfox/api-workspaces-dto@10.2.0
|
|
34
|
+
- @shipfox/api-auth-context@10.2.0
|
|
35
|
+
|
|
3
36
|
## 10.1.0
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -47,7 +47,12 @@ Routes mount under `/workspaces`. They make and list workspaces, manage members,
|
|
|
47
47
|
and make, list, view, accept, or revoke invites. The composed module also mounts
|
|
48
48
|
`GET /admin/workspaces`, which requires the Auth `admin-observer` role and returns
|
|
49
49
|
bounded workspace identity, lifecycle, member, project, and best-effort job-count
|
|
50
|
-
summaries. Supporting count failures are represented as `unknown`.
|
|
50
|
+
summaries. Supporting count failures are represented as `unknown`. `POST
|
|
51
|
+
/admin/workspaces/:workspaceId/suspend` and `POST
|
|
52
|
+
/admin/workspaces/:workspaceId/reactivate` require the `admin-operator` role, an
|
|
53
|
+
`Idempotency-Key` header, and a `{reason}` body, and return `{workspace_id,
|
|
54
|
+
status, correlation_id}`. Both write a redacted `administration.action.performed`
|
|
55
|
+
outbox event and record their result for idempotent retries.
|
|
51
56
|
|
|
52
57
|
The module creates these tables:
|
|
53
58
|
|
|
@@ -55,6 +60,7 @@ The module creates these tables:
|
|
|
55
60
|
- `workspaces_memberships`
|
|
56
61
|
- `workspaces_invitations`
|
|
57
62
|
- `workspaces_outbox`
|
|
63
|
+
- `workspaces_admin_command_results`
|
|
58
64
|
|
|
59
65
|
## Behavior Notes
|
|
60
66
|
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
import { type AdministrationRole } from '@shipfox/api-common-dto';
|
|
1
2
|
import type { ProjectsModuleClient } from '@shipfox/api-projects-dto/inter-module';
|
|
2
3
|
import type { RunnersInterModuleClient } from '@shipfox/api-runners-dto/inter-module';
|
|
3
4
|
import type { StringIdCursor } from '@shipfox/node-drizzle';
|
|
5
|
+
export interface WorkspaceAdministrationMutationContext {
|
|
6
|
+
actorId: string;
|
|
7
|
+
actorRole: AdministrationRole;
|
|
8
|
+
idempotencyKey: string;
|
|
9
|
+
correlationId: string;
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
reason: string;
|
|
12
|
+
}
|
|
13
|
+
export interface WorkspaceAdministrationMutationResult {
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
status: 'active' | 'suspended';
|
|
16
|
+
correlationId: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function suspendWorkspace(params: WorkspaceAdministrationMutationContext): Promise<WorkspaceAdministrationMutationResult>;
|
|
19
|
+
export declare function reactivateWorkspace(params: WorkspaceAdministrationMutationContext): Promise<WorkspaceAdministrationMutationResult>;
|
|
4
20
|
export interface WorkspaceAdministratorSummary {
|
|
5
21
|
id: string;
|
|
6
22
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-workspaces.d.ts","sourceRoot":"","sources":["../../src/core/admin-workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AACpF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"admin-workspaces.d.ts","sourceRoot":"","sources":["../../src/core/admin-workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,kBAAkB,EAAkC,MAAM,yBAAyB,CAAC;AACjG,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AACpF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAa1D,MAAM,WAAW,sCAAsC;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;CACvB;AA2DD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,sCAAsC,GAC7C,OAAO,CAAC,qCAAqC,CAAC,CAMhD;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,sCAAsC,GAC7C,OAAO,CAAC,qCAAqC,CAAC,CAMhD;AAED,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,aAAa,EAAE;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;IAC/B,cAAc,EAAE;QAAC,KAAK,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG;QAAC,KAAK,EAAE,SAAS,CAAA;KAAC,CAAC;IACzE,SAAS,EAAE;QAAC,KAAK,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,GAAG;QAAC,KAAK,EAAE,SAAS,CAAA;KAAC,CAAC;IACtF,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,yCAAyC;IACxD,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,wBAAwB,CAAC;CACnC;AAED,MAAM,WAAW,yCAAyC;IACxD,UAAU,EAAE,6BAA6B,EAAE,CAAC;IAC5C,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;CACnC;AAED,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,yCAAyC,GAChD,OAAO,CAAC,yCAAyC,CAAC,CAqBpD"}
|
|
@@ -1,5 +1,57 @@
|
|
|
1
|
+
import { createAdministrationActionEvent } from '@shipfox/api-common-dto';
|
|
1
2
|
import { logger } from '@shipfox/node-opentelemetry';
|
|
3
|
+
import { hashOpaqueToken } from '@shipfox/node-tokens';
|
|
4
|
+
import { reactivateWorkspaceWithAudit, suspendWorkspaceWithAudit } from '#db/admin-workspace-commands.js';
|
|
2
5
|
import { listAdminWorkspaces as listAdminWorkspaceRows } from '#db/workspaces.js';
|
|
6
|
+
const ADMIN_OPERATOR_ROLE = 'admin-operator';
|
|
7
|
+
const SUSPEND_COMMAND = 'workspace.suspend';
|
|
8
|
+
const REACTIVATE_COMMAND = 'workspace.reactivate';
|
|
9
|
+
function commandFingerprint(command, params) {
|
|
10
|
+
return hashOpaqueToken(`${command}:${JSON.stringify({
|
|
11
|
+
workspaceId: params.workspaceId,
|
|
12
|
+
reason: params.reason
|
|
13
|
+
})}`);
|
|
14
|
+
}
|
|
15
|
+
function administrationEvent(params) {
|
|
16
|
+
return createAdministrationActionEvent({
|
|
17
|
+
actorId: params.actorId,
|
|
18
|
+
actorRole: params.actorRole,
|
|
19
|
+
requiredRole: ADMIN_OPERATOR_ROLE,
|
|
20
|
+
command: params.command,
|
|
21
|
+
targetType: 'workspace',
|
|
22
|
+
targetId: params.workspaceId,
|
|
23
|
+
reason: params.reason,
|
|
24
|
+
result: 'succeeded',
|
|
25
|
+
correlationId: params.correlationId,
|
|
26
|
+
idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,
|
|
27
|
+
occurredAt: new Date().toISOString()
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function runWorkspaceAdministrationMutation(params, command, update) {
|
|
31
|
+
const idempotencyKeyFingerprint = hashOpaqueToken(params.idempotencyKey);
|
|
32
|
+
const result = await update({
|
|
33
|
+
actorId: params.actorId,
|
|
34
|
+
workspaceId: params.workspaceId,
|
|
35
|
+
idempotencyKeyFingerprint,
|
|
36
|
+
requestFingerprint: commandFingerprint(command, params),
|
|
37
|
+
event: administrationEvent({
|
|
38
|
+
actorId: params.actorId,
|
|
39
|
+
actorRole: params.actorRole,
|
|
40
|
+
command,
|
|
41
|
+
workspaceId: params.workspaceId,
|
|
42
|
+
reason: params.reason,
|
|
43
|
+
correlationId: params.correlationId,
|
|
44
|
+
idempotencyKeyFingerprint
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export async function suspendWorkspace(params) {
|
|
50
|
+
return await runWorkspaceAdministrationMutation(params, SUSPEND_COMMAND, suspendWorkspaceWithAudit);
|
|
51
|
+
}
|
|
52
|
+
export async function reactivateWorkspace(params) {
|
|
53
|
+
return await runWorkspaceAdministrationMutation(params, REACTIVATE_COMMAND, reactivateWorkspaceWithAudit);
|
|
54
|
+
}
|
|
3
55
|
export async function listWorkspaceAdministratorSummaries(params) {
|
|
4
56
|
const result = await listAdminWorkspaceRows(params);
|
|
5
57
|
const workspaceIds = result.workspaces.map(({ id })=>id);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/admin-workspaces.ts"],"sourcesContent":["import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {RunnersInterModuleClient} from '@shipfox/api-runners-dto/inter-module';\nimport type {StringIdCursor} from '@shipfox/node-drizzle';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {listAdminWorkspaces as listAdminWorkspaceRows} from '#db/workspaces.js';\n\nexport interface WorkspaceAdministratorSummary {\n id: string;\n name: string;\n status: 'active' | 'suspended' | 'deleted';\n memberSummary: {count: number};\n projectSummary: {state: 'available'; count: number} | {state: 'unknown'};\n jobCounts: {state: 'available'; queued: number; running: number} | {state: 'unknown'};\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface ListWorkspaceAdministratorSummariesParams {\n workspaceId?: string | undefined;\n search?: string | undefined;\n status?: 'active' | 'suspended' | 'deleted' | undefined;\n limit: number;\n cursor?: StringIdCursor | undefined;\n projects: ProjectsModuleClient;\n runners: RunnersInterModuleClient;\n}\n\nexport interface ListWorkspaceAdministratorSummariesResult {\n workspaces: WorkspaceAdministratorSummary[];\n nextCursor: StringIdCursor | null;\n}\n\nexport async function listWorkspaceAdministratorSummaries(\n params: ListWorkspaceAdministratorSummariesParams,\n): Promise<ListWorkspaceAdministratorSummariesResult> {\n const result = await listAdminWorkspaceRows(params);\n const workspaceIds = result.workspaces.map(({id}) => id);\n const [projectCounts, jobCounts] = await Promise.all([\n getProjectCounts(params.projects, workspaceIds),\n getJobCounts(params.runners, workspaceIds),\n ]);\n\n return {\n workspaces: result.workspaces.map((workspace) => ({\n id: workspace.id,\n name: workspace.name,\n status: workspace.status,\n memberSummary: {count: workspace.memberCount},\n projectSummary: projectCounts?.get(workspace.id) ?? {state: 'unknown'},\n jobCounts: jobCounts?.get(workspace.id) ?? {state: 'unknown'},\n createdAt: workspace.createdAt,\n updatedAt: workspace.updatedAt,\n })),\n nextCursor: result.nextCursor,\n };\n}\n\nasync function getProjectCounts(\n projects: ProjectsModuleClient,\n workspaceIds: string[],\n): Promise<Map<string, {state: 'available'; count: number} | {state: 'unknown'}> | null> {\n if (workspaceIds.length === 0) return new Map();\n\n try {\n const result = await projects.getWorkspaceProjectCounts({workspaceIds});\n const counts = new Map(\n result.counts.map(({workspaceId, count}) => [\n workspaceId,\n {state: 'available', count} as const,\n ]),\n );\n return new Map(\n workspaceIds.map((workspaceId) => [\n workspaceId,\n counts.get(workspaceId) ?? {state: 'unknown'},\n ]),\n );\n } catch (error) {\n logger().warn(\n {operation: 'admin-workspace-project-summary', err: error},\n 'Project summary unavailable',\n );\n return null;\n }\n}\n\nasync function getJobCounts(\n runners: RunnersInterModuleClient,\n workspaceIds: string[],\n): Promise<Map<\n string,\n {state: 'available'; queued: number; running: number} | {state: 'unknown'}\n> | null> {\n if (workspaceIds.length === 0) return new Map();\n\n try {\n const result = await runners.getWorkspaceJobCounts({workspaceIds});\n const counts = new Map(\n result.counts.map(({workspaceId, queued, running}) => [\n workspaceId,\n {state: 'available', queued, running} as const,\n ]),\n );\n return new Map(\n workspaceIds.map((workspaceId) => [\n workspaceId,\n counts.get(workspaceId) ?? {state: 'unknown'},\n ]),\n );\n } catch (error) {\n logger().warn({operation: 'admin-workspace-job-counts', err: error}, 'Job counts unavailable');\n return null;\n }\n}\n"],"names":["logger","listAdminWorkspaces","listAdminWorkspaceRows","listWorkspaceAdministratorSummaries","params","result","workspaceIds","workspaces","map","id","projectCounts","jobCounts","Promise","all","getProjectCounts","projects","getJobCounts","runners","workspace","name","status","memberSummary","count","memberCount","projectSummary","get","state","createdAt","updatedAt","nextCursor","length","Map","getWorkspaceProjectCounts","counts","workspaceId","error","warn","operation","err","getWorkspaceJobCounts","queued","running"],"mappings":"AAGA,SAAQA,MAAM,QAAO,8BAA8B;AACnD,SAAQC,uBAAuBC,sBAAsB,QAAO,oBAAoB;AA4BhF,OAAO,eAAeC,oCACpBC,MAAiD;IAEjD,MAAMC,SAAS,MAAMH,uBAAuBE;IAC5C,MAAME,eAAeD,OAAOE,UAAU,CAACC,GAAG,CAAC,CAAC,EAACC,EAAE,EAAC,GAAKA;IACrD,MAAM,CAACC,eAAeC,UAAU,GAAG,MAAMC,QAAQC,GAAG,CAAC;QACnDC,iBAAiBV,OAAOW,QAAQ,EAAET;QAClCU,aAAaZ,OAAOa,OAAO,EAAEX;KAC9B;IAED,OAAO;QACLC,YAAYF,OAAOE,UAAU,CAACC,GAAG,CAAC,CAACU,YAAe,CAAA;gBAChDT,IAAIS,UAAUT,EAAE;gBAChBU,MAAMD,UAAUC,IAAI;gBACpBC,QAAQF,UAAUE,MAAM;gBACxBC,eAAe;oBAACC,OAAOJ,UAAUK,WAAW;gBAAA;gBAC5CC,gBAAgBd,eAAee,IAAIP,UAAUT,EAAE,KAAK;oBAACiB,OAAO;gBAAS;gBACrEf,WAAWA,WAAWc,IAAIP,UAAUT,EAAE,KAAK;oBAACiB,OAAO;gBAAS;gBAC5DC,WAAWT,UAAUS,SAAS;gBAC9BC,WAAWV,UAAUU,SAAS;YAChC,CAAA;QACAC,YAAYxB,OAAOwB,UAAU;IAC/B;AACF;AAEA,eAAef,iBACbC,QAA8B,EAC9BT,YAAsB;IAEtB,IAAIA,aAAawB,MAAM,KAAK,GAAG,OAAO,IAAIC;IAE1C,IAAI;QACF,MAAM1B,SAAS,MAAMU,SAASiB,yBAAyB,CAAC;YAAC1B;QAAY;QACrE,MAAM2B,SAAS,IAAIF,IACjB1B,OAAO4B,MAAM,CAACzB,GAAG,CAAC,CAAC,EAAC0B,WAAW,EAAEZ,KAAK,EAAC,GAAK;gBAC1CY;gBACA;oBAACR,OAAO;oBAAaJ;gBAAK;aAC3B;QAEH,OAAO,IAAIS,IACTzB,aAAaE,GAAG,CAAC,CAAC0B,cAAgB;gBAChCA;gBACAD,OAAOR,GAAG,CAACS,gBAAgB;oBAACR,OAAO;gBAAS;aAC7C;IAEL,EAAE,OAAOS,OAAO;QACdnC,SAASoC,IAAI,CACX;YAACC,WAAW;YAAmCC,KAAKH;QAAK,GACzD;QAEF,OAAO;IACT;AACF;AAEA,eAAenB,aACbC,OAAiC,EACjCX,YAAsB;IAKtB,IAAIA,aAAawB,MAAM,KAAK,GAAG,OAAO,IAAIC;IAE1C,IAAI;QACF,MAAM1B,SAAS,MAAMY,QAAQsB,qBAAqB,CAAC;YAACjC;QAAY;QAChE,MAAM2B,SAAS,IAAIF,IACjB1B,OAAO4B,MAAM,CAACzB,GAAG,CAAC,CAAC,EAAC0B,WAAW,EAAEM,MAAM,EAAEC,OAAO,EAAC,GAAK;gBACpDP;gBACA;oBAACR,OAAO;oBAAac;oBAAQC;gBAAO;aACrC;QAEH,OAAO,IAAIV,IACTzB,aAAaE,GAAG,CAAC,CAAC0B,cAAgB;gBAChCA;gBACAD,OAAOR,GAAG,CAACS,gBAAgB;oBAACR,OAAO;gBAAS;aAC7C;IAEL,EAAE,OAAOS,OAAO;QACdnC,SAASoC,IAAI,CAAC;YAACC,WAAW;YAA8BC,KAAKH;QAAK,GAAG;QACrE,OAAO;IACT;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/admin-workspaces.ts"],"sourcesContent":["import {type AdministrationRole, createAdministrationActionEvent} from '@shipfox/api-common-dto';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {RunnersInterModuleClient} from '@shipfox/api-runners-dto/inter-module';\nimport type {StringIdCursor} from '@shipfox/node-drizzle';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {hashOpaqueToken} from '@shipfox/node-tokens';\nimport {\n reactivateWorkspaceWithAudit,\n suspendWorkspaceWithAudit,\n} from '#db/admin-workspace-commands.js';\nimport {listAdminWorkspaces as listAdminWorkspaceRows} from '#db/workspaces.js';\n\nconst ADMIN_OPERATOR_ROLE: AdministrationRole = 'admin-operator';\nconst SUSPEND_COMMAND = 'workspace.suspend';\nconst REACTIVATE_COMMAND = 'workspace.reactivate';\n\nexport interface WorkspaceAdministrationMutationContext {\n actorId: string;\n actorRole: AdministrationRole;\n idempotencyKey: string;\n correlationId: string;\n workspaceId: string;\n reason: string;\n}\n\nexport interface WorkspaceAdministrationMutationResult {\n workspaceId: string;\n status: 'active' | 'suspended';\n correlationId: string;\n}\n\nfunction commandFingerprint(\n command: string,\n params: WorkspaceAdministrationMutationContext,\n): string {\n return hashOpaqueToken(\n `${command}:${JSON.stringify({workspaceId: params.workspaceId, reason: params.reason})}`,\n );\n}\n\nfunction administrationEvent(params: {\n actorId: string;\n actorRole: AdministrationRole;\n command: string;\n workspaceId: string;\n reason: string;\n correlationId: string;\n idempotencyKeyFingerprint: string;\n}) {\n return createAdministrationActionEvent({\n actorId: params.actorId,\n actorRole: params.actorRole,\n requiredRole: ADMIN_OPERATOR_ROLE,\n command: params.command,\n targetType: 'workspace',\n targetId: params.workspaceId,\n reason: params.reason,\n result: 'succeeded',\n correlationId: params.correlationId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n occurredAt: new Date().toISOString(),\n });\n}\n\nasync function runWorkspaceAdministrationMutation(\n params: WorkspaceAdministrationMutationContext,\n command: string,\n update: typeof suspendWorkspaceWithAudit,\n): Promise<WorkspaceAdministrationMutationResult> {\n const idempotencyKeyFingerprint = hashOpaqueToken(params.idempotencyKey);\n const result = await update({\n actorId: params.actorId,\n workspaceId: params.workspaceId,\n idempotencyKeyFingerprint,\n requestFingerprint: commandFingerprint(command, params),\n event: administrationEvent({\n actorId: params.actorId,\n actorRole: params.actorRole,\n command,\n workspaceId: params.workspaceId,\n reason: params.reason,\n correlationId: params.correlationId,\n idempotencyKeyFingerprint,\n }),\n });\n return result;\n}\n\nexport async function suspendWorkspace(\n params: WorkspaceAdministrationMutationContext,\n): Promise<WorkspaceAdministrationMutationResult> {\n return await runWorkspaceAdministrationMutation(\n params,\n SUSPEND_COMMAND,\n suspendWorkspaceWithAudit,\n );\n}\n\nexport async function reactivateWorkspace(\n params: WorkspaceAdministrationMutationContext,\n): Promise<WorkspaceAdministrationMutationResult> {\n return await runWorkspaceAdministrationMutation(\n params,\n REACTIVATE_COMMAND,\n reactivateWorkspaceWithAudit,\n );\n}\n\nexport interface WorkspaceAdministratorSummary {\n id: string;\n name: string;\n status: 'active' | 'suspended' | 'deleted';\n memberSummary: {count: number};\n projectSummary: {state: 'available'; count: number} | {state: 'unknown'};\n jobCounts: {state: 'available'; queued: number; running: number} | {state: 'unknown'};\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface ListWorkspaceAdministratorSummariesParams {\n workspaceId?: string | undefined;\n search?: string | undefined;\n status?: 'active' | 'suspended' | 'deleted' | undefined;\n limit: number;\n cursor?: StringIdCursor | undefined;\n projects: ProjectsModuleClient;\n runners: RunnersInterModuleClient;\n}\n\nexport interface ListWorkspaceAdministratorSummariesResult {\n workspaces: WorkspaceAdministratorSummary[];\n nextCursor: StringIdCursor | null;\n}\n\nexport async function listWorkspaceAdministratorSummaries(\n params: ListWorkspaceAdministratorSummariesParams,\n): Promise<ListWorkspaceAdministratorSummariesResult> {\n const result = await listAdminWorkspaceRows(params);\n const workspaceIds = result.workspaces.map(({id}) => id);\n const [projectCounts, jobCounts] = await Promise.all([\n getProjectCounts(params.projects, workspaceIds),\n getJobCounts(params.runners, workspaceIds),\n ]);\n\n return {\n workspaces: result.workspaces.map((workspace) => ({\n id: workspace.id,\n name: workspace.name,\n status: workspace.status,\n memberSummary: {count: workspace.memberCount},\n projectSummary: projectCounts?.get(workspace.id) ?? {state: 'unknown'},\n jobCounts: jobCounts?.get(workspace.id) ?? {state: 'unknown'},\n createdAt: workspace.createdAt,\n updatedAt: workspace.updatedAt,\n })),\n nextCursor: result.nextCursor,\n };\n}\n\nasync function getProjectCounts(\n projects: ProjectsModuleClient,\n workspaceIds: string[],\n): Promise<Map<string, {state: 'available'; count: number} | {state: 'unknown'}> | null> {\n if (workspaceIds.length === 0) return new Map();\n\n try {\n const result = await projects.getWorkspaceProjectCounts({workspaceIds});\n const counts = new Map(\n result.counts.map(({workspaceId, count}) => [\n workspaceId,\n {state: 'available', count} as const,\n ]),\n );\n return new Map(\n workspaceIds.map((workspaceId) => [\n workspaceId,\n counts.get(workspaceId) ?? {state: 'unknown'},\n ]),\n );\n } catch (error) {\n logger().warn(\n {operation: 'admin-workspace-project-summary', err: error},\n 'Project summary unavailable',\n );\n return null;\n }\n}\n\nasync function getJobCounts(\n runners: RunnersInterModuleClient,\n workspaceIds: string[],\n): Promise<Map<\n string,\n {state: 'available'; queued: number; running: number} | {state: 'unknown'}\n> | null> {\n if (workspaceIds.length === 0) return new Map();\n\n try {\n const result = await runners.getWorkspaceJobCounts({workspaceIds});\n const counts = new Map(\n result.counts.map(({workspaceId, queued, running}) => [\n workspaceId,\n {state: 'available', queued, running} as const,\n ]),\n );\n return new Map(\n workspaceIds.map((workspaceId) => [\n workspaceId,\n counts.get(workspaceId) ?? {state: 'unknown'},\n ]),\n );\n } catch (error) {\n logger().warn({operation: 'admin-workspace-job-counts', err: error}, 'Job counts unavailable');\n return null;\n }\n}\n"],"names":["createAdministrationActionEvent","logger","hashOpaqueToken","reactivateWorkspaceWithAudit","suspendWorkspaceWithAudit","listAdminWorkspaces","listAdminWorkspaceRows","ADMIN_OPERATOR_ROLE","SUSPEND_COMMAND","REACTIVATE_COMMAND","commandFingerprint","command","params","JSON","stringify","workspaceId","reason","administrationEvent","actorId","actorRole","requiredRole","targetType","targetId","result","correlationId","idempotencyKeyFingerprint","occurredAt","Date","toISOString","runWorkspaceAdministrationMutation","update","idempotencyKey","requestFingerprint","event","suspendWorkspace","reactivateWorkspace","listWorkspaceAdministratorSummaries","workspaceIds","workspaces","map","id","projectCounts","jobCounts","Promise","all","getProjectCounts","projects","getJobCounts","runners","workspace","name","status","memberSummary","count","memberCount","projectSummary","get","state","createdAt","updatedAt","nextCursor","length","Map","getWorkspaceProjectCounts","counts","error","warn","operation","err","getWorkspaceJobCounts","queued","running"],"mappings":"AAAA,SAAiCA,+BAA+B,QAAO,0BAA0B;AAIjG,SAAQC,MAAM,QAAO,8BAA8B;AACnD,SAAQC,eAAe,QAAO,uBAAuB;AACrD,SACEC,4BAA4B,EAC5BC,yBAAyB,QACpB,kCAAkC;AACzC,SAAQC,uBAAuBC,sBAAsB,QAAO,oBAAoB;AAEhF,MAAMC,sBAA0C;AAChD,MAAMC,kBAAkB;AACxB,MAAMC,qBAAqB;AAiB3B,SAASC,mBACPC,OAAe,EACfC,MAA8C;IAE9C,OAAOV,gBACL,GAAGS,QAAQ,CAAC,EAAEE,KAAKC,SAAS,CAAC;QAACC,aAAaH,OAAOG,WAAW;QAAEC,QAAQJ,OAAOI,MAAM;IAAA,IAAI;AAE5F;AAEA,SAASC,oBAAoBL,MAQ5B;IACC,OAAOZ,gCAAgC;QACrCkB,SAASN,OAAOM,OAAO;QACvBC,WAAWP,OAAOO,SAAS;QAC3BC,cAAcb;QACdI,SAASC,OAAOD,OAAO;QACvBU,YAAY;QACZC,UAAUV,OAAOG,WAAW;QAC5BC,QAAQJ,OAAOI,MAAM;QACrBO,QAAQ;QACRC,eAAeZ,OAAOY,aAAa;QACnCC,2BAA2Bb,OAAOa,yBAAyB;QAC3DC,YAAY,IAAIC,OAAOC,WAAW;IACpC;AACF;AAEA,eAAeC,mCACbjB,MAA8C,EAC9CD,OAAe,EACfmB,MAAwC;IAExC,MAAML,4BAA4BvB,gBAAgBU,OAAOmB,cAAc;IACvE,MAAMR,SAAS,MAAMO,OAAO;QAC1BZ,SAASN,OAAOM,OAAO;QACvBH,aAAaH,OAAOG,WAAW;QAC/BU;QACAO,oBAAoBtB,mBAAmBC,SAASC;QAChDqB,OAAOhB,oBAAoB;YACzBC,SAASN,OAAOM,OAAO;YACvBC,WAAWP,OAAOO,SAAS;YAC3BR;YACAI,aAAaH,OAAOG,WAAW;YAC/BC,QAAQJ,OAAOI,MAAM;YACrBQ,eAAeZ,OAAOY,aAAa;YACnCC;QACF;IACF;IACA,OAAOF;AACT;AAEA,OAAO,eAAeW,iBACpBtB,MAA8C;IAE9C,OAAO,MAAMiB,mCACXjB,QACAJ,iBACAJ;AAEJ;AAEA,OAAO,eAAe+B,oBACpBvB,MAA8C;IAE9C,OAAO,MAAMiB,mCACXjB,QACAH,oBACAN;AAEJ;AA4BA,OAAO,eAAeiC,oCACpBxB,MAAiD;IAEjD,MAAMW,SAAS,MAAMjB,uBAAuBM;IAC5C,MAAMyB,eAAed,OAAOe,UAAU,CAACC,GAAG,CAAC,CAAC,EAACC,EAAE,EAAC,GAAKA;IACrD,MAAM,CAACC,eAAeC,UAAU,GAAG,MAAMC,QAAQC,GAAG,CAAC;QACnDC,iBAAiBjC,OAAOkC,QAAQ,EAAET;QAClCU,aAAanC,OAAOoC,OAAO,EAAEX;KAC9B;IAED,OAAO;QACLC,YAAYf,OAAOe,UAAU,CAACC,GAAG,CAAC,CAACU,YAAe,CAAA;gBAChDT,IAAIS,UAAUT,EAAE;gBAChBU,MAAMD,UAAUC,IAAI;gBACpBC,QAAQF,UAAUE,MAAM;gBACxBC,eAAe;oBAACC,OAAOJ,UAAUK,WAAW;gBAAA;gBAC5CC,gBAAgBd,eAAee,IAAIP,UAAUT,EAAE,KAAK;oBAACiB,OAAO;gBAAS;gBACrEf,WAAWA,WAAWc,IAAIP,UAAUT,EAAE,KAAK;oBAACiB,OAAO;gBAAS;gBAC5DC,WAAWT,UAAUS,SAAS;gBAC9BC,WAAWV,UAAUU,SAAS;YAChC,CAAA;QACAC,YAAYrC,OAAOqC,UAAU;IAC/B;AACF;AAEA,eAAef,iBACbC,QAA8B,EAC9BT,YAAsB;IAEtB,IAAIA,aAAawB,MAAM,KAAK,GAAG,OAAO,IAAIC;IAE1C,IAAI;QACF,MAAMvC,SAAS,MAAMuB,SAASiB,yBAAyB,CAAC;YAAC1B;QAAY;QACrE,MAAM2B,SAAS,IAAIF,IACjBvC,OAAOyC,MAAM,CAACzB,GAAG,CAAC,CAAC,EAACxB,WAAW,EAAEsC,KAAK,EAAC,GAAK;gBAC1CtC;gBACA;oBAAC0C,OAAO;oBAAaJ;gBAAK;aAC3B;QAEH,OAAO,IAAIS,IACTzB,aAAaE,GAAG,CAAC,CAACxB,cAAgB;gBAChCA;gBACAiD,OAAOR,GAAG,CAACzC,gBAAgB;oBAAC0C,OAAO;gBAAS;aAC7C;IAEL,EAAE,OAAOQ,OAAO;QACdhE,SAASiE,IAAI,CACX;YAACC,WAAW;YAAmCC,KAAKH;QAAK,GACzD;QAEF,OAAO;IACT;AACF;AAEA,eAAelB,aACbC,OAAiC,EACjCX,YAAsB;IAKtB,IAAIA,aAAawB,MAAM,KAAK,GAAG,OAAO,IAAIC;IAE1C,IAAI;QACF,MAAMvC,SAAS,MAAMyB,QAAQqB,qBAAqB,CAAC;YAAChC;QAAY;QAChE,MAAM2B,SAAS,IAAIF,IACjBvC,OAAOyC,MAAM,CAACzB,GAAG,CAAC,CAAC,EAACxB,WAAW,EAAEuD,MAAM,EAAEC,OAAO,EAAC,GAAK;gBACpDxD;gBACA;oBAAC0C,OAAO;oBAAaa;oBAAQC;gBAAO;aACrC;QAEH,OAAO,IAAIT,IACTzB,aAAaE,GAAG,CAAC,CAACxB,cAAgB;gBAChCA;gBACAiD,OAAOR,GAAG,CAACzC,gBAAgB;oBAAC0C,OAAO;gBAAS;aAC7C;IAEL,EAAE,OAAOQ,OAAO;QACdhE,SAASiE,IAAI,CAAC;YAACC,WAAW;YAA8BC,KAAKH;QAAK,GAAG;QACrE,OAAO;IACT;AACF"}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -4,6 +4,18 @@ export declare class WorkspaceNotFoundError extends Error {
|
|
|
4
4
|
export declare class WorkspaceInactiveError extends Error {
|
|
5
5
|
constructor(workspaceId: string);
|
|
6
6
|
}
|
|
7
|
+
export declare class WorkspaceAlreadySuspendedError extends Error {
|
|
8
|
+
constructor(workspaceId: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class WorkspaceNotSuspendedError extends Error {
|
|
11
|
+
constructor(workspaceId: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class WorkspaceDeletedError extends Error {
|
|
14
|
+
constructor(workspaceId: string);
|
|
15
|
+
}
|
|
16
|
+
export declare class WorkspaceAdminIdempotencyKeyReuseError extends Error {
|
|
17
|
+
constructor();
|
|
18
|
+
}
|
|
7
19
|
export declare class InvitationNotFoundError extends Error {
|
|
8
20
|
constructor(id: string);
|
|
9
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,gCAAiC,SAAQ,KAAK;;CAK1D;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAIhD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;;CAKjD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,0BAA2B,SAAQ,KAAK;;CAKpD;AAED,qBAAa,4BAA6B,SAAQ,KAAK;;CAKtD;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,EAAE,MAAM;CAI1B"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,8BAA+B,SAAQ,KAAK;gBAC3C,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,sCAAuC,SAAQ,KAAK;;CAKhE;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,gCAAiC,SAAQ,KAAK;;CAK1D;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAIhD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;;CAKjD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,0BAA2B,SAAQ,KAAK;;CAKpD;AAED,qBAAa,4BAA6B,SAAQ,KAAK;;CAKtD;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,EAAE,MAAM;CAI1B"}
|
package/dist/core/errors.js
CHANGED
|
@@ -10,6 +10,30 @@ export class WorkspaceInactiveError extends Error {
|
|
|
10
10
|
this.name = 'WorkspaceInactiveError';
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
export class WorkspaceAlreadySuspendedError extends Error {
|
|
14
|
+
constructor(workspaceId){
|
|
15
|
+
super(`Workspace is already suspended: ${workspaceId}`);
|
|
16
|
+
this.name = 'WorkspaceAlreadySuspendedError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class WorkspaceNotSuspendedError extends Error {
|
|
20
|
+
constructor(workspaceId){
|
|
21
|
+
super(`Workspace is not suspended: ${workspaceId}`);
|
|
22
|
+
this.name = 'WorkspaceNotSuspendedError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class WorkspaceDeletedError extends Error {
|
|
26
|
+
constructor(workspaceId){
|
|
27
|
+
super(`Workspace is deleted: ${workspaceId}`);
|
|
28
|
+
this.name = 'WorkspaceDeletedError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class WorkspaceAdminIdempotencyKeyReuseError extends Error {
|
|
32
|
+
constructor(){
|
|
33
|
+
super('Idempotency key was already used for a different workspace command');
|
|
34
|
+
this.name = 'WorkspaceAdminIdempotencyKeyReuseError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
13
37
|
export class InvitationNotFoundError extends Error {
|
|
14
38
|
constructor(id){
|
|
15
39
|
super(`Invitation not found: ${id}`);
|
package/dist/core/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class WorkspaceNotFoundError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace not found: ${workspaceId}`);\n this.name = 'WorkspaceNotFoundError';\n }\n}\n\nexport class WorkspaceInactiveError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is not active: ${workspaceId}`);\n this.name = 'WorkspaceInactiveError';\n }\n}\n\nexport class InvitationNotFoundError extends Error {\n constructor(id: string) {\n super(`Invitation not found: ${id}`);\n this.name = 'InvitationNotFoundError';\n }\n}\n\nexport class InvitationWorkspaceMismatchError extends Error {\n constructor() {\n super('Invitation does not belong to this workspace');\n this.name = 'InvitationWorkspaceMismatchError';\n }\n}\n\nexport class MembershipNotFoundError extends Error {\n constructor(userId: string, workspaceId: string) {\n super(`Membership not found for user ${userId} in workspace ${workspaceId}`);\n this.name = 'MembershipNotFoundError';\n }\n}\n\nexport class UserNotFoundError extends Error {\n constructor(idOrEmail: string) {\n super(`User not found: ${idOrEmail}`);\n this.name = 'UserNotFoundError';\n }\n}\n\nexport class EmailTakenError extends Error {\n constructor(email: string) {\n super(`Email already registered: ${email}`);\n this.name = 'EmailTakenError';\n }\n}\n\nexport class InvalidCredentialsError extends Error {\n constructor() {\n super('Invalid credentials');\n this.name = 'InvalidCredentialsError';\n }\n}\n\nexport class EmailNotVerifiedError extends Error {\n constructor() {\n super('Email not verified');\n this.name = 'EmailNotVerifiedError';\n }\n}\n\nexport class TokenInvalidError extends Error {\n constructor(reason?: string) {\n super(reason ? `Invalid token: ${reason}` : 'Invalid token');\n this.name = 'TokenInvalidError';\n }\n}\n\nexport class TokenExpiredError extends Error {\n constructor() {\n super('Token has expired');\n this.name = 'TokenExpiredError';\n }\n}\n\nexport class TokenAlreadyUsedError extends Error {\n constructor() {\n super('Token has already been used');\n this.name = 'TokenAlreadyUsedError';\n }\n}\n\nexport class MembershipRequiredError extends Error {\n constructor(workspaceId: string) {\n super(`Membership required for workspace: ${workspaceId}`);\n this.name = 'MembershipRequiredError';\n }\n}\n\nexport class LastMemberError extends Error {\n constructor(workspaceId: string) {\n super(`Cannot remove the last member of workspace: ${workspaceId}`);\n this.name = 'LastMemberError';\n }\n}\n\nexport class SelfRemovalNotAllowedError extends Error {\n constructor() {\n super('Cannot remove yourself from a workspace');\n this.name = 'SelfRemovalNotAllowedError';\n }\n}\n\nexport class InvitationEmailMismatchError extends Error {\n constructor() {\n super('Invitation email does not match authenticated user');\n this.name = 'InvitationEmailMismatchError';\n }\n}\n\nexport class OpenInvitationExistsError extends Error {\n constructor(email: string) {\n super(`An open invitation already exists for: ${email}`);\n this.name = 'OpenInvitationExistsError';\n }\n}\n"],"names":["WorkspaceNotFoundError","Error","workspaceId","name","WorkspaceInactiveError","InvitationNotFoundError","id","InvitationWorkspaceMismatchError","MembershipNotFoundError","userId","UserNotFoundError","idOrEmail","EmailTakenError","email","InvalidCredentialsError","EmailNotVerifiedError","TokenInvalidError","reason","TokenExpiredError","TokenAlreadyUsedError","MembershipRequiredError","LastMemberError","SelfRemovalNotAllowedError","InvitationEmailMismatchError","OpenInvitationExistsError"],"mappings":"AAAA,OAAO,MAAMA,+BAA+BC;IAC1C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,qBAAqB,EAAEA,aAAa;QAC3C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,+BAA+BH;IAC1C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,yBAAyB,EAAEA,aAAa;QAC/C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAME,
|
|
1
|
+
{"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class WorkspaceNotFoundError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace not found: ${workspaceId}`);\n this.name = 'WorkspaceNotFoundError';\n }\n}\n\nexport class WorkspaceInactiveError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is not active: ${workspaceId}`);\n this.name = 'WorkspaceInactiveError';\n }\n}\n\nexport class WorkspaceAlreadySuspendedError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is already suspended: ${workspaceId}`);\n this.name = 'WorkspaceAlreadySuspendedError';\n }\n}\n\nexport class WorkspaceNotSuspendedError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is not suspended: ${workspaceId}`);\n this.name = 'WorkspaceNotSuspendedError';\n }\n}\n\nexport class WorkspaceDeletedError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is deleted: ${workspaceId}`);\n this.name = 'WorkspaceDeletedError';\n }\n}\n\nexport class WorkspaceAdminIdempotencyKeyReuseError extends Error {\n constructor() {\n super('Idempotency key was already used for a different workspace command');\n this.name = 'WorkspaceAdminIdempotencyKeyReuseError';\n }\n}\n\nexport class InvitationNotFoundError extends Error {\n constructor(id: string) {\n super(`Invitation not found: ${id}`);\n this.name = 'InvitationNotFoundError';\n }\n}\n\nexport class InvitationWorkspaceMismatchError extends Error {\n constructor() {\n super('Invitation does not belong to this workspace');\n this.name = 'InvitationWorkspaceMismatchError';\n }\n}\n\nexport class MembershipNotFoundError extends Error {\n constructor(userId: string, workspaceId: string) {\n super(`Membership not found for user ${userId} in workspace ${workspaceId}`);\n this.name = 'MembershipNotFoundError';\n }\n}\n\nexport class UserNotFoundError extends Error {\n constructor(idOrEmail: string) {\n super(`User not found: ${idOrEmail}`);\n this.name = 'UserNotFoundError';\n }\n}\n\nexport class EmailTakenError extends Error {\n constructor(email: string) {\n super(`Email already registered: ${email}`);\n this.name = 'EmailTakenError';\n }\n}\n\nexport class InvalidCredentialsError extends Error {\n constructor() {\n super('Invalid credentials');\n this.name = 'InvalidCredentialsError';\n }\n}\n\nexport class EmailNotVerifiedError extends Error {\n constructor() {\n super('Email not verified');\n this.name = 'EmailNotVerifiedError';\n }\n}\n\nexport class TokenInvalidError extends Error {\n constructor(reason?: string) {\n super(reason ? `Invalid token: ${reason}` : 'Invalid token');\n this.name = 'TokenInvalidError';\n }\n}\n\nexport class TokenExpiredError extends Error {\n constructor() {\n super('Token has expired');\n this.name = 'TokenExpiredError';\n }\n}\n\nexport class TokenAlreadyUsedError extends Error {\n constructor() {\n super('Token has already been used');\n this.name = 'TokenAlreadyUsedError';\n }\n}\n\nexport class MembershipRequiredError extends Error {\n constructor(workspaceId: string) {\n super(`Membership required for workspace: ${workspaceId}`);\n this.name = 'MembershipRequiredError';\n }\n}\n\nexport class LastMemberError extends Error {\n constructor(workspaceId: string) {\n super(`Cannot remove the last member of workspace: ${workspaceId}`);\n this.name = 'LastMemberError';\n }\n}\n\nexport class SelfRemovalNotAllowedError extends Error {\n constructor() {\n super('Cannot remove yourself from a workspace');\n this.name = 'SelfRemovalNotAllowedError';\n }\n}\n\nexport class InvitationEmailMismatchError extends Error {\n constructor() {\n super('Invitation email does not match authenticated user');\n this.name = 'InvitationEmailMismatchError';\n }\n}\n\nexport class OpenInvitationExistsError extends Error {\n constructor(email: string) {\n super(`An open invitation already exists for: ${email}`);\n this.name = 'OpenInvitationExistsError';\n }\n}\n"],"names":["WorkspaceNotFoundError","Error","workspaceId","name","WorkspaceInactiveError","WorkspaceAlreadySuspendedError","WorkspaceNotSuspendedError","WorkspaceDeletedError","WorkspaceAdminIdempotencyKeyReuseError","InvitationNotFoundError","id","InvitationWorkspaceMismatchError","MembershipNotFoundError","userId","UserNotFoundError","idOrEmail","EmailTakenError","email","InvalidCredentialsError","EmailNotVerifiedError","TokenInvalidError","reason","TokenExpiredError","TokenAlreadyUsedError","MembershipRequiredError","LastMemberError","SelfRemovalNotAllowedError","InvitationEmailMismatchError","OpenInvitationExistsError"],"mappings":"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"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { type ListWorkspaceAdministratorSummariesParams, type ListWorkspaceAdministratorSummariesResult, listWorkspaceAdministratorSummaries, type WorkspaceAdministratorSummary, } from './admin-workspaces.js';
|
|
1
|
+
export { type ListWorkspaceAdministratorSummariesParams, type ListWorkspaceAdministratorSummariesResult, listWorkspaceAdministratorSummaries, reactivateWorkspace, suspendWorkspace, type WorkspaceAdministrationMutationContext, type WorkspaceAdministrationMutationResult, type WorkspaceAdministratorSummary, } from './admin-workspaces.js';
|
|
2
2
|
export type { Invitation } from './entities/invitation.js';
|
|
3
3
|
export type { Membership } from './entities/membership.js';
|
|
4
4
|
export type { Workspace, WorkspaceStatus } from './entities/workspace.js';
|
|
5
|
-
export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceNotFoundError, } from './errors.js';
|
|
5
|
+
export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceAdminIdempotencyKeyReuseError, WorkspaceAlreadySuspendedError, WorkspaceDeletedError, WorkspaceNotFoundError, WorkspaceNotSuspendedError, } from './errors.js';
|
|
6
6
|
export { acceptWorkspaceInvitation, createWorkspaceInvitation, listWorkspaceInvitations, type PreviewInvitationResult, previewInvitation, revokeWorkspaceInvitation, } from './invitations.js';
|
|
7
7
|
export { type EnsureMembershipParams, ensureMembership } from './memberships.js';
|
|
8
8
|
export { createWorkspaceForUser, getWorkspace, listUserWorkspaceMemberships, listWorkspaceMembers, type RequireWorkspaceMembershipParams, type RequireWorkspaceMembershipResult, removeWorkspaceMember, requireWorkspaceMembership, } from './workspaces.js';
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,yCAAyC,EAC9C,KAAK,yCAAyC,EAC9C,mCAAmC,EACnC,KAAK,6BAA6B,GACnC,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,yCAAyC,EAC9C,KAAK,yCAAyC,EAC9C,mCAAmC,EACnC,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,sCAAsC,EAC3C,KAAK,qCAAqC,EAC1C,KAAK,6BAA6B,GACnC,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,sCAAsC,EACtC,8BAA8B,EAC9B,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,KAAK,sBAAsB,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,4BAA4B,EAC5B,oBAAoB,EACpB,KAAK,gCAAgC,EACrC,KAAK,gCAAgC,EACrC,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC"}
|
package/dist/core/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { listWorkspaceAdministratorSummaries } from './admin-workspaces.js';
|
|
2
|
-
export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceNotFoundError } from './errors.js';
|
|
1
|
+
export { listWorkspaceAdministratorSummaries, reactivateWorkspace, suspendWorkspace } from './admin-workspaces.js';
|
|
2
|
+
export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceAdminIdempotencyKeyReuseError, WorkspaceAlreadySuspendedError, WorkspaceDeletedError, WorkspaceNotFoundError, WorkspaceNotSuspendedError } from './errors.js';
|
|
3
3
|
export { acceptWorkspaceInvitation, createWorkspaceInvitation, listWorkspaceInvitations, previewInvitation, revokeWorkspaceInvitation } from './invitations.js';
|
|
4
4
|
export { ensureMembership } from './memberships.js';
|
|
5
5
|
export { createWorkspaceForUser, getWorkspace, listUserWorkspaceMemberships, listWorkspaceMembers, removeWorkspaceMember, requireWorkspaceMembership } from './workspaces.js';
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export {\n type ListWorkspaceAdministratorSummariesParams,\n type ListWorkspaceAdministratorSummariesResult,\n listWorkspaceAdministratorSummaries,\n type WorkspaceAdministratorSummary,\n} from './admin-workspaces.js';\nexport type {Invitation} from './entities/invitation.js';\nexport type {Membership} from './entities/membership.js';\nexport type {Workspace, WorkspaceStatus} from './entities/workspace.js';\nexport {\n InvitationEmailMismatchError,\n InvitationNotFoundError,\n InvitationWorkspaceMismatchError,\n LastMemberError,\n MembershipNotFoundError,\n MembershipRequiredError,\n OpenInvitationExistsError,\n SelfRemovalNotAllowedError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n WorkspaceNotFoundError,\n} from './errors.js';\nexport {\n acceptWorkspaceInvitation,\n createWorkspaceInvitation,\n listWorkspaceInvitations,\n type PreviewInvitationResult,\n previewInvitation,\n revokeWorkspaceInvitation,\n} from './invitations.js';\nexport {type EnsureMembershipParams, ensureMembership} from './memberships.js';\nexport {\n createWorkspaceForUser,\n getWorkspace,\n listUserWorkspaceMemberships,\n listWorkspaceMembers,\n type RequireWorkspaceMembershipParams,\n type RequireWorkspaceMembershipResult,\n removeWorkspaceMember,\n requireWorkspaceMembership,\n} from './workspaces.js';\n"],"names":["listWorkspaceAdministratorSummaries","InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","LastMemberError","MembershipNotFoundError","MembershipRequiredError","OpenInvitationExistsError","SelfRemovalNotAllowedError","TokenAlreadyUsedError","TokenExpiredError","WorkspaceNotFoundError","acceptWorkspaceInvitation","createWorkspaceInvitation","listWorkspaceInvitations","previewInvitation","revokeWorkspaceInvitation","ensureMembership","createWorkspaceForUser","getWorkspace","listUserWorkspaceMemberships","listWorkspaceMembers","removeWorkspaceMember","requireWorkspaceMembership"],"mappings":"AAAA,SAGEA,mCAAmC,
|
|
1
|
+
{"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export {\n type ListWorkspaceAdministratorSummariesParams,\n type ListWorkspaceAdministratorSummariesResult,\n listWorkspaceAdministratorSummaries,\n reactivateWorkspace,\n suspendWorkspace,\n type WorkspaceAdministrationMutationContext,\n type WorkspaceAdministrationMutationResult,\n type WorkspaceAdministratorSummary,\n} from './admin-workspaces.js';\nexport type {Invitation} from './entities/invitation.js';\nexport type {Membership} from './entities/membership.js';\nexport type {Workspace, WorkspaceStatus} from './entities/workspace.js';\nexport {\n InvitationEmailMismatchError,\n InvitationNotFoundError,\n InvitationWorkspaceMismatchError,\n LastMemberError,\n MembershipNotFoundError,\n MembershipRequiredError,\n OpenInvitationExistsError,\n SelfRemovalNotAllowedError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n WorkspaceAdminIdempotencyKeyReuseError,\n WorkspaceAlreadySuspendedError,\n WorkspaceDeletedError,\n WorkspaceNotFoundError,\n WorkspaceNotSuspendedError,\n} from './errors.js';\nexport {\n acceptWorkspaceInvitation,\n createWorkspaceInvitation,\n listWorkspaceInvitations,\n type PreviewInvitationResult,\n previewInvitation,\n revokeWorkspaceInvitation,\n} from './invitations.js';\nexport {type EnsureMembershipParams, ensureMembership} from './memberships.js';\nexport {\n createWorkspaceForUser,\n getWorkspace,\n listUserWorkspaceMemberships,\n listWorkspaceMembers,\n type RequireWorkspaceMembershipParams,\n type RequireWorkspaceMembershipResult,\n removeWorkspaceMember,\n requireWorkspaceMembership,\n} from './workspaces.js';\n"],"names":["listWorkspaceAdministratorSummaries","reactivateWorkspace","suspendWorkspace","InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","LastMemberError","MembershipNotFoundError","MembershipRequiredError","OpenInvitationExistsError","SelfRemovalNotAllowedError","TokenAlreadyUsedError","TokenExpiredError","WorkspaceAdminIdempotencyKeyReuseError","WorkspaceAlreadySuspendedError","WorkspaceDeletedError","WorkspaceNotFoundError","WorkspaceNotSuspendedError","acceptWorkspaceInvitation","createWorkspaceInvitation","listWorkspaceInvitations","previewInvitation","revokeWorkspaceInvitation","ensureMembership","createWorkspaceForUser","getWorkspace","listUserWorkspaceMemberships","listWorkspaceMembers","removeWorkspaceMember","requireWorkspaceMembership"],"mappings":"AAAA,SAGEA,mCAAmC,EACnCC,mBAAmB,EACnBC,gBAAgB,QAIX,wBAAwB;AAI/B,SACEC,4BAA4B,EAC5BC,uBAAuB,EACvBC,gCAAgC,EAChCC,eAAe,EACfC,uBAAuB,EACvBC,uBAAuB,EACvBC,yBAAyB,EACzBC,0BAA0B,EAC1BC,qBAAqB,EACrBC,iBAAiB,EACjBC,sCAAsC,EACtCC,8BAA8B,EAC9BC,qBAAqB,EACrBC,sBAAsB,EACtBC,0BAA0B,QACrB,cAAc;AACrB,SACEC,yBAAyB,EACzBC,yBAAyB,EACzBC,wBAAwB,EAExBC,iBAAiB,EACjBC,yBAAyB,QACpB,mBAAmB;AAC1B,SAAqCC,gBAAgB,QAAO,mBAAmB;AAC/E,SACEC,sBAAsB,EACtBC,YAAY,EACZC,4BAA4B,EAC5BC,oBAAoB,EAGpBC,qBAAqB,EACrBC,0BAA0B,QACrB,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invitations.d.ts","sourceRoot":"","sources":["../../src/core/invitations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAarE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAsBzD,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,oBAAoB,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;CAC5D,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"invitations.d.ts","sourceRoot":"","sources":["../../src/core/invitations.ts"],"names":[],"mappings":"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"}
|
package/dist/core/invitations.js
CHANGED
|
@@ -18,7 +18,8 @@ export async function createWorkspaceInvitation(params) {
|
|
|
18
18
|
const { workspace } = await requireWorkspaceMembership({
|
|
19
19
|
workspaceId: params.workspaceId,
|
|
20
20
|
userId: params.invitedByUserId,
|
|
21
|
-
memberships: params.invitedByMemberships
|
|
21
|
+
memberships: params.invitedByMemberships,
|
|
22
|
+
enforceWorkspaceStatus: false
|
|
22
23
|
});
|
|
23
24
|
const rawToken = generateOpaqueToken('invitation');
|
|
24
25
|
const invitation = await createInvitation({
|
|
@@ -144,7 +145,8 @@ export async function listWorkspaceInvitations(params) {
|
|
|
144
145
|
await requireWorkspaceMembership({
|
|
145
146
|
workspaceId: params.workspaceId,
|
|
146
147
|
userId: params.requesterUserId,
|
|
147
|
-
memberships: params.requesterMemberships
|
|
148
|
+
memberships: params.requesterMemberships,
|
|
149
|
+
enforceWorkspaceStatus: false
|
|
148
150
|
});
|
|
149
151
|
return listOpenInvitationsByWorkspace({
|
|
150
152
|
workspaceId: params.workspaceId
|
|
@@ -154,7 +156,8 @@ export async function revokeWorkspaceInvitation(params) {
|
|
|
154
156
|
await requireWorkspaceMembership({
|
|
155
157
|
workspaceId: params.workspaceId,
|
|
156
158
|
userId: params.requesterUserId,
|
|
157
|
-
memberships: params.requesterMemberships
|
|
159
|
+
memberships: params.requesterMemberships,
|
|
160
|
+
enforceWorkspaceStatus: false
|
|
158
161
|
});
|
|
159
162
|
const invitation = await findInvitationById({
|
|
160
163
|
id: params.invitationId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/invitations.ts"],"sourcesContent":["import type {UserContextMembership} from '@shipfox/api-auth-context';\nimport {emailSchema} from '@shipfox/api-common-dto';\nimport {generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {config} from '#config.js';\nimport {\n createInvitation,\n findInvitationById,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n reconcileInvitationAcceptance,\n revokeInvitation,\n} from '#db/invitations.js';\nimport {getWorkspaceById} from '#db/workspaces.js';\nimport type {Invitation} from './entities/invitation.js';\nimport type {Membership} from './entities/membership.js';\nimport {\n InvitationEmailMismatchError,\n InvitationNotFoundError,\n InvitationWorkspaceMismatchError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n TokenInvalidError,\n} from './errors.js';\nimport {requireWorkspaceMembership} from './workspaces.js';\n\nconst INVITATION_TTL_DAYS = 7;\n\nfunction daysFromNow(days: number): Date {\n return new Date(Date.now() + days * 24 * 60 * 60 * 1000);\n}\n\nfunction nonBlankOrFallback(value: string | null | undefined, fallback: string): string {\n const trimmed = value?.trim();\n return trimmed ? trimmed : fallback;\n}\n\nexport async function createWorkspaceInvitation(params: {\n workspaceId: string;\n email: string;\n invitedByUserId: string;\n invitedByDisplay?: string | null;\n invitedByMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<Invitation> {\n const email = emailSchema.parse(params.email);\n const {workspace} = await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.invitedByUserId,\n memberships: params.invitedByMemberships,\n });\n\n const rawToken = generateOpaqueToken('invitation');\n const invitation = await createInvitation({\n workspaceId: params.workspaceId,\n email,\n hashedToken: hashOpaqueToken(rawToken),\n expiresAt: daysFromNow(INVITATION_TTL_DAYS),\n invitedByUserId: params.invitedByUserId,\n invitedByDisplay: params.invitedByDisplay ?? null,\n sendEmail: {\n workspaceName: nonBlankOrFallback(workspace.name, 'your workspace'),\n inviterName: nonBlankOrFallback(params.invitedByDisplay, 'A teammate'),\n inviteLink: `${config.CLIENT_BASE_URL}/invitations/accept?token=${rawToken}`,\n },\n });\n\n return invitation;\n}\n\nexport async function peekInvitationByRawToken(params: {\n token: string;\n}): Promise<Invitation | undefined> {\n return await findInvitationByToken({hashedToken: hashOpaqueToken(params.token)});\n}\n\nexport type PreviewInvitationResult =\n | {\n status: 'pending';\n workspaceId: string;\n workspaceName: string;\n email: string;\n invitedByDisplay: string | null;\n expiresAt: Date;\n }\n | {status: 'expired'; workspaceName: string; expiresAt: Date}\n | {status: 'already_used'; workspaceName: string}\n | {status: 'invalid'};\n\nexport interface AcceptedWorkspaceInvitation {\n invitation: Invitation;\n membership: Membership;\n alreadyMember: boolean;\n}\n\nexport async function previewInvitation(params: {token: string}): Promise<PreviewInvitationResult> {\n const invitation = await peekInvitationByRawToken({token: params.token});\n if (!invitation) {\n return {status: 'invalid'};\n }\n\n const workspace = await getWorkspaceById(invitation.workspaceId);\n if (!workspace) {\n // Workspace cascade-deleted — the invitation row is orphaned. Treat as invalid.\n return {status: 'invalid'};\n }\n\n if (invitation.revokedAt !== null) {\n return {status: 'invalid'};\n }\n\n if (invitation.acceptedAt !== null) {\n return {status: 'already_used', workspaceName: workspace.name};\n }\n\n if (invitation.expiresAt.getTime() <= Date.now()) {\n return {\n status: 'expired',\n workspaceName: workspace.name,\n expiresAt: invitation.expiresAt,\n };\n }\n\n return {\n status: 'pending',\n workspaceId: workspace.id,\n workspaceName: workspace.name,\n email: invitation.email,\n invitedByDisplay: invitation.invitedByDisplay,\n expiresAt: invitation.expiresAt,\n };\n}\n\nexport async function acceptWorkspaceInvitation(params: {\n token: string;\n userId: string;\n email: string;\n name?: string | null | undefined;\n}): Promise<AcceptedWorkspaceInvitation> {\n const result = await reconcileWorkspaceInvitationAcceptance({\n token: params.token,\n email: params.email,\n userId: params.userId,\n name: params.name,\n });\n if (result.status === 'accepted') {\n return {\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: result.alreadyMember,\n };\n }\n if (result.status === 'already_accepted' || result.status === 'consumed_by_another_user') {\n throw new TokenAlreadyUsedError();\n }\n if (result.status === 'expired') {\n throw new TokenExpiredError();\n }\n if (result.status === 'email_mismatch') {\n throw new InvitationEmailMismatchError();\n }\n throw new TokenInvalidError(\n result.status === 'revoked' ? 'Invitation token has been revoked' : 'Invitation is invalid',\n );\n}\n\nexport type WorkspaceInvitationReconciliation =\n | {\n status: 'accepted' | 'already_accepted';\n invitation: Invitation;\n membership: Membership;\n alreadyMember: boolean;\n }\n | {\n status: 'invalid' | 'expired' | 'revoked' | 'consumed_by_another_user' | 'email_mismatch';\n };\n\nexport async function reconcileWorkspaceInvitationAcceptance(params: {\n token: string;\n userId: string;\n email: string;\n name?: string | null | undefined;\n}): Promise<WorkspaceInvitationReconciliation> {\n const invitation = await peekInvitationByRawToken({token: params.token});\n if (!invitation) return {status: 'invalid'};\n\n const result = await reconcileInvitationAcceptance({\n invitationId: invitation.id,\n acceptedByUserId: params.userId,\n email: emailSchema.parse(params.email),\n acceptedByUserName: params.name,\n });\n if (result.status === 'accepted') {\n return {\n status: result.status,\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: result.alreadyMember,\n };\n }\n if (result.status === 'already_accepted') {\n return {\n status: result.status,\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: true,\n };\n }\n return result;\n}\n\nexport async function listWorkspaceInvitations(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<Invitation[]> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n return listOpenInvitationsByWorkspace({workspaceId: params.workspaceId});\n}\n\nexport async function revokeWorkspaceInvitation(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n invitationId: string;\n}): Promise<void> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n const invitation = await findInvitationById({id: params.invitationId});\n if (!invitation) {\n throw new InvitationNotFoundError(params.invitationId);\n }\n\n if (invitation.workspaceId !== params.workspaceId) {\n throw new InvitationWorkspaceMismatchError();\n }\n\n await revokeInvitation({invitationId: params.invitationId});\n}\n"],"names":["emailSchema","generateOpaqueToken","hashOpaqueToken","config","createInvitation","findInvitationById","findInvitationByToken","listOpenInvitationsByWorkspace","reconcileInvitationAcceptance","revokeInvitation","getWorkspaceById","InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","TokenAlreadyUsedError","TokenExpiredError","TokenInvalidError","requireWorkspaceMembership","INVITATION_TTL_DAYS","daysFromNow","days","Date","now","nonBlankOrFallback","value","fallback","trimmed","trim","createWorkspaceInvitation","params","email","parse","workspace","workspaceId","userId","invitedByUserId","memberships","invitedByMemberships","rawToken","invitation","hashedToken","expiresAt","invitedByDisplay","sendEmail","workspaceName","name","inviterName","inviteLink","CLIENT_BASE_URL","peekInvitationByRawToken","token","previewInvitation","status","revokedAt","acceptedAt","getTime","id","acceptWorkspaceInvitation","result","reconcileWorkspaceInvitationAcceptance","membership","alreadyMember","invitationId","acceptedByUserId","acceptedByUserName","listWorkspaceInvitations","requesterUserId","requesterMemberships","revokeWorkspaceInvitation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/invitations.ts"],"sourcesContent":["import type {UserContextMembership} from '@shipfox/api-auth-context';\nimport {emailSchema} from '@shipfox/api-common-dto';\nimport {generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {config} from '#config.js';\nimport {\n createInvitation,\n findInvitationById,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n reconcileInvitationAcceptance,\n revokeInvitation,\n} from '#db/invitations.js';\nimport {getWorkspaceById} from '#db/workspaces.js';\nimport type {Invitation} from './entities/invitation.js';\nimport type {Membership} from './entities/membership.js';\nimport {\n InvitationEmailMismatchError,\n InvitationNotFoundError,\n InvitationWorkspaceMismatchError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n TokenInvalidError,\n} from './errors.js';\nimport {requireWorkspaceMembership} from './workspaces.js';\n\nconst INVITATION_TTL_DAYS = 7;\n\nfunction daysFromNow(days: number): Date {\n return new Date(Date.now() + days * 24 * 60 * 60 * 1000);\n}\n\nfunction nonBlankOrFallback(value: string | null | undefined, fallback: string): string {\n const trimmed = value?.trim();\n return trimmed ? trimmed : fallback;\n}\n\nexport async function createWorkspaceInvitation(params: {\n workspaceId: string;\n email: string;\n invitedByUserId: string;\n invitedByDisplay?: string | null;\n invitedByMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<Invitation> {\n const email = emailSchema.parse(params.email);\n const {workspace} = await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.invitedByUserId,\n memberships: params.invitedByMemberships,\n enforceWorkspaceStatus: false,\n });\n\n const rawToken = generateOpaqueToken('invitation');\n const invitation = await createInvitation({\n workspaceId: params.workspaceId,\n email,\n hashedToken: hashOpaqueToken(rawToken),\n expiresAt: daysFromNow(INVITATION_TTL_DAYS),\n invitedByUserId: params.invitedByUserId,\n invitedByDisplay: params.invitedByDisplay ?? null,\n sendEmail: {\n workspaceName: nonBlankOrFallback(workspace.name, 'your workspace'),\n inviterName: nonBlankOrFallback(params.invitedByDisplay, 'A teammate'),\n inviteLink: `${config.CLIENT_BASE_URL}/invitations/accept?token=${rawToken}`,\n },\n });\n\n return invitation;\n}\n\nexport async function peekInvitationByRawToken(params: {\n token: string;\n}): Promise<Invitation | undefined> {\n return await findInvitationByToken({hashedToken: hashOpaqueToken(params.token)});\n}\n\nexport type PreviewInvitationResult =\n | {\n status: 'pending';\n workspaceId: string;\n workspaceName: string;\n email: string;\n invitedByDisplay: string | null;\n expiresAt: Date;\n }\n | {status: 'expired'; workspaceName: string; expiresAt: Date}\n | {status: 'already_used'; workspaceName: string}\n | {status: 'invalid'};\n\nexport interface AcceptedWorkspaceInvitation {\n invitation: Invitation;\n membership: Membership;\n alreadyMember: boolean;\n}\n\nexport async function previewInvitation(params: {token: string}): Promise<PreviewInvitationResult> {\n const invitation = await peekInvitationByRawToken({token: params.token});\n if (!invitation) {\n return {status: 'invalid'};\n }\n\n const workspace = await getWorkspaceById(invitation.workspaceId);\n if (!workspace) {\n // Workspace cascade-deleted — the invitation row is orphaned. Treat as invalid.\n return {status: 'invalid'};\n }\n\n if (invitation.revokedAt !== null) {\n return {status: 'invalid'};\n }\n\n if (invitation.acceptedAt !== null) {\n return {status: 'already_used', workspaceName: workspace.name};\n }\n\n if (invitation.expiresAt.getTime() <= Date.now()) {\n return {\n status: 'expired',\n workspaceName: workspace.name,\n expiresAt: invitation.expiresAt,\n };\n }\n\n return {\n status: 'pending',\n workspaceId: workspace.id,\n workspaceName: workspace.name,\n email: invitation.email,\n invitedByDisplay: invitation.invitedByDisplay,\n expiresAt: invitation.expiresAt,\n };\n}\n\nexport async function acceptWorkspaceInvitation(params: {\n token: string;\n userId: string;\n email: string;\n name?: string | null | undefined;\n}): Promise<AcceptedWorkspaceInvitation> {\n const result = await reconcileWorkspaceInvitationAcceptance({\n token: params.token,\n email: params.email,\n userId: params.userId,\n name: params.name,\n });\n if (result.status === 'accepted') {\n return {\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: result.alreadyMember,\n };\n }\n if (result.status === 'already_accepted' || result.status === 'consumed_by_another_user') {\n throw new TokenAlreadyUsedError();\n }\n if (result.status === 'expired') {\n throw new TokenExpiredError();\n }\n if (result.status === 'email_mismatch') {\n throw new InvitationEmailMismatchError();\n }\n throw new TokenInvalidError(\n result.status === 'revoked' ? 'Invitation token has been revoked' : 'Invitation is invalid',\n );\n}\n\nexport type WorkspaceInvitationReconciliation =\n | {\n status: 'accepted' | 'already_accepted';\n invitation: Invitation;\n membership: Membership;\n alreadyMember: boolean;\n }\n | {\n status: 'invalid' | 'expired' | 'revoked' | 'consumed_by_another_user' | 'email_mismatch';\n };\n\nexport async function reconcileWorkspaceInvitationAcceptance(params: {\n token: string;\n userId: string;\n email: string;\n name?: string | null | undefined;\n}): Promise<WorkspaceInvitationReconciliation> {\n const invitation = await peekInvitationByRawToken({token: params.token});\n if (!invitation) return {status: 'invalid'};\n\n const result = await reconcileInvitationAcceptance({\n invitationId: invitation.id,\n acceptedByUserId: params.userId,\n email: emailSchema.parse(params.email),\n acceptedByUserName: params.name,\n });\n if (result.status === 'accepted') {\n return {\n status: result.status,\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: result.alreadyMember,\n };\n }\n if (result.status === 'already_accepted') {\n return {\n status: result.status,\n invitation: result.invitation,\n membership: result.membership,\n alreadyMember: true,\n };\n }\n return result;\n}\n\nexport async function listWorkspaceInvitations(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<Invitation[]> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n enforceWorkspaceStatus: false,\n });\n\n return listOpenInvitationsByWorkspace({workspaceId: params.workspaceId});\n}\n\nexport async function revokeWorkspaceInvitation(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n invitationId: 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 const invitation = await findInvitationById({id: params.invitationId});\n if (!invitation) {\n throw new InvitationNotFoundError(params.invitationId);\n }\n\n if (invitation.workspaceId !== params.workspaceId) {\n throw new InvitationWorkspaceMismatchError();\n }\n\n await revokeInvitation({invitationId: params.invitationId});\n}\n"],"names":["emailSchema","generateOpaqueToken","hashOpaqueToken","config","createInvitation","findInvitationById","findInvitationByToken","listOpenInvitationsByWorkspace","reconcileInvitationAcceptance","revokeInvitation","getWorkspaceById","InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","TokenAlreadyUsedError","TokenExpiredError","TokenInvalidError","requireWorkspaceMembership","INVITATION_TTL_DAYS","daysFromNow","days","Date","now","nonBlankOrFallback","value","fallback","trimmed","trim","createWorkspaceInvitation","params","email","parse","workspace","workspaceId","userId","invitedByUserId","memberships","invitedByMemberships","enforceWorkspaceStatus","rawToken","invitation","hashedToken","expiresAt","invitedByDisplay","sendEmail","workspaceName","name","inviterName","inviteLink","CLIENT_BASE_URL","peekInvitationByRawToken","token","previewInvitation","status","revokedAt","acceptedAt","getTime","id","acceptWorkspaceInvitation","result","reconcileWorkspaceInvitationAcceptance","membership","alreadyMember","invitationId","acceptedByUserId","acceptedByUserName","listWorkspaceInvitations","requesterUserId","requesterMemberships","revokeWorkspaceInvitation"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/core/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAE7B,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yBAAyB,CAAC;AASvD,MAAM,WAAW,gCAAgC;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/core/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAE7B,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yBAAyB,CAAC;AASvD,MAAM,WAAW,gCAAgC;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAClD,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,gCAAgC;IAC/C,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,gCAAgC,GACvC,OAAO,CAAC,gCAAgC,CAAC,CAe3C;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACtC,GAAG,OAAO,CAAC,SAAS,CAAC,CA0BrB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAOpF;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG/F;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAG/B;AAED,wBAAsB,4BAA4B,CAAC,MAAM,EAAE;IACzD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAErC;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;CAC5D,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAShC;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB"}
|
package/dist/core/workspaces.js
CHANGED
|
@@ -16,7 +16,7 @@ export async function requireWorkspaceMembership(params) {
|
|
|
16
16
|
if (!workspace) {
|
|
17
17
|
throw new WorkspaceNotFoundError(params.workspaceId);
|
|
18
18
|
}
|
|
19
|
-
if (workspace.status !== 'active') {
|
|
19
|
+
if (params.enforceWorkspaceStatus !== false && workspace.status !== 'active') {
|
|
20
20
|
throw new WorkspaceInactiveError(params.workspaceId);
|
|
21
21
|
}
|
|
22
22
|
return {
|
|
@@ -75,7 +75,8 @@ export async function listWorkspaceMembers(params) {
|
|
|
75
75
|
await requireWorkspaceMembership({
|
|
76
76
|
workspaceId: params.workspaceId,
|
|
77
77
|
userId: params.requesterUserId,
|
|
78
|
-
memberships: params.requesterMemberships
|
|
78
|
+
memberships: params.requesterMemberships,
|
|
79
|
+
enforceWorkspaceStatus: false
|
|
79
80
|
});
|
|
80
81
|
return listMembershipsByWorkspace({
|
|
81
82
|
workspaceId: params.workspaceId
|
|
@@ -85,7 +86,8 @@ export async function removeWorkspaceMember(params) {
|
|
|
85
86
|
await requireWorkspaceMembership({
|
|
86
87
|
workspaceId: params.workspaceId,
|
|
87
88
|
userId: params.requesterUserId,
|
|
88
|
-
memberships: params.requesterMemberships
|
|
89
|
+
memberships: params.requesterMemberships,
|
|
90
|
+
enforceWorkspaceStatus: false
|
|
89
91
|
});
|
|
90
92
|
if (params.userId === params.requesterUserId) {
|
|
91
93
|
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":"AACA,SACEA,4BAA4B,QAGvB,8BAA8B;AACrC,SAAQC,gBAAgB,QAAO,uBAAuB;AACtD,SAAQC,EAAE,QAAO,YAAY;AAC7B,SACEC,cAAc,EACdC,qBAAqB,EACrBC,0BAA0B,EAG1BC,gBAAgB,QACX,qBAAqB;AAC5B,SAAQC,WAAW,QAAO,4BAA4B;AACtD,SAAQC,gBAAgB,QAAO,uBAAuB;AACtD,SAAQC,WAAW,EAAEC,UAAU,QAAO,2BAA2B;AACjE,SAAQC,gBAAgB,QAAO,oBAAoB;AAEnD,SACEC,uBAAuB,EACvBC,uBAAuB,EACvBC,0BAA0B,EAC1BC,sBAAsB,EACtBC,sBAAsB,QACjB,cAAc;
|
|
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 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 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 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","writeOutboxEvent","db","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","memberships","workspacesOutbox","toWorkspace","workspaces","getWorkspaceById","MembershipNotFoundError","MembershipRequiredError","SelfRemovalNotAllowedError","WorkspaceInactiveError","WorkspaceNotFoundError","requireWorkspaceMembership","params","membership","find","m","workspaceId","workspace","enforceWorkspaceStatus","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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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AdministrationActionEvent } from '@shipfox/api-common-dto';
|
|
2
|
+
export interface WorkspaceAdministrationResult {
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
status: 'active' | 'suspended';
|
|
5
|
+
correlationId: string;
|
|
6
|
+
}
|
|
7
|
+
interface AuditedWorkspaceCommandParams {
|
|
8
|
+
actorId: string;
|
|
9
|
+
idempotencyKeyFingerprint: string;
|
|
10
|
+
requestFingerprint: string;
|
|
11
|
+
event: AdministrationActionEvent;
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function suspendWorkspaceWithAudit(params: AuditedWorkspaceCommandParams): Promise<WorkspaceAdministrationResult>;
|
|
15
|
+
export declare function reactivateWorkspaceWithAudit(params: AuditedWorkspaceCommandParams): Promise<WorkspaceAdministrationResult>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=admin-workspace-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-workspace-commands.d.ts","sourceRoot":"","sources":["../../src/db/admin-workspace-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,yBAAyB,CAAC;AAoBjC,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,EAAE,MAAM,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,yBAAyB,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;CACrB;AAmHD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,6BAA6B,CAAC,CAMxC;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,6BAA6B,CAAC,CAMxC"}
|