@shipfox/api-workspaces 9.2.0 → 10.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 +47 -0
- package/README.md +5 -2
- package/dist/core/admin-workspaces.d.ts +41 -0
- package/dist/core/admin-workspaces.d.ts.map +1 -0
- package/dist/core/admin-workspaces.js +86 -0
- package/dist/core/admin-workspaces.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/workspaces.d.ts +3 -0
- package/dist/core/workspaces.d.ts.map +1 -1
- package/dist/core/workspaces.js +4 -0
- package/dist/core/workspaces.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/memberships.d.ts +2 -0
- package/dist/db/memberships.d.ts.map +1 -1
- package/dist/db/memberships.js +4 -2
- package/dist/db/memberships.js.map +1 -1
- package/dist/db/schema/workspaces.d.ts.map +1 -1
- package/dist/db/schema/workspaces.js +4 -2
- package/dist/db/schema/workspaces.js.map +1 -1
- package/dist/db/workspaces.d.ts +16 -0
- package/dist/db/workspaces.d.ts.map +1 -1
- package/dist/db/workspaces.js +43 -1
- package/dist/db/workspaces.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -3
- package/dist/index.js.map +1 -1
- package/dist/presentation/dto/membership.d.ts.map +1 -1
- package/dist/presentation/dto/membership.js +1 -0
- package/dist/presentation/dto/membership.js.map +1 -1
- package/dist/presentation/index.d.ts +1 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +1 -1
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +15 -1
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/admin-workspaces.d.ts +10 -0
- package/dist/presentation/routes/admin-workspaces.d.ts.map +1 -0
- package/dist/presentation/routes/admin-workspaces.js +84 -0
- package/dist/presentation/routes/admin-workspaces.js.map +1 -0
- package/dist/presentation/routes/index.d.ts +8 -0
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +7 -0
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0001_complex_beast.sql +1 -0
- package/drizzle/meta/0001_snapshot.json +476 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +10 -7
- package/src/core/admin-workspaces.ts +114 -0
- package/src/core/index.ts +6 -0
- package/src/core/workspaces.test.ts +19 -1
- package/src/core/workspaces.ts +7 -0
- package/src/db/index.ts +4 -0
- package/src/db/memberships.ts +8 -1
- package/src/db/schema/workspaces.ts +14 -10
- package/src/db/workspaces.test.ts +25 -0
- package/src/db/workspaces.ts +75 -1
- package/src/index.ts +27 -2
- package/src/presentation/dto/membership.ts +1 -0
- package/src/presentation/index.ts +1 -1
- package/src/presentation/inter-module.test.ts +39 -1
- package/src/presentation/inter-module.ts +19 -1
- package/src/presentation/routes/admin-workspaces.test.ts +168 -0
- package/src/presentation/routes/admin-workspaces.ts +93 -0
- package/src/presentation/routes/index.ts +12 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 50 files with swc (552.2ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# @shipfox/api-workspaces
|
|
2
2
|
|
|
3
|
+
## 10.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e9280fc: Add an observer-authorized administrator workspace lookup with bounded safe summaries,
|
|
8
|
+
best-effort job counts, and a neutral unavailable-workspace member experience for
|
|
9
|
+
suspended or deleted workspaces.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [6054364]
|
|
14
|
+
- Updated dependencies [74f9e31]
|
|
15
|
+
- Updated dependencies [e9280fc]
|
|
16
|
+
- Updated dependencies [837bf5d]
|
|
17
|
+
- Updated dependencies [3f5610b]
|
|
18
|
+
- @shipfox/api-auth-dto@10.0.0
|
|
19
|
+
- @shipfox/node-fastify@0.4.0
|
|
20
|
+
- @shipfox/api-workspaces-dto@10.0.0
|
|
21
|
+
- @shipfox/api-projects-dto@10.0.0
|
|
22
|
+
- @shipfox/api-runners-dto@10.0.0
|
|
23
|
+
- @shipfox/api-auth-context@10.0.0
|
|
24
|
+
- @shipfox/node-module@1.0.4
|
|
25
|
+
- @shipfox/api-common-dto@9.2.0
|
|
26
|
+
- @shipfox/config@1.2.4
|
|
27
|
+
- @shipfox/inter-module@0.2.2
|
|
28
|
+
- @shipfox/node-drizzle@0.3.4
|
|
29
|
+
- @shipfox/node-email@0.3.4
|
|
30
|
+
- @shipfox/node-mailer@0.2.4
|
|
31
|
+
- @shipfox/node-opentelemetry@0.6.3
|
|
32
|
+
- @shipfox/node-outbox@0.2.6
|
|
33
|
+
- @shipfox/node-postgres@0.4.4
|
|
34
|
+
- @shipfox/node-tokens@0.3.2
|
|
35
|
+
|
|
36
|
+
## 9.3.0
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- 7b6a409: Adds the checked Workspace operating-state contract for job-admission owners.
|
|
41
|
+
- Updated dependencies [4425c6d]
|
|
42
|
+
- Updated dependencies [7b6a409]
|
|
43
|
+
- @shipfox/node-opentelemetry@0.6.3
|
|
44
|
+
- @shipfox/api-workspaces-dto@9.3.0
|
|
45
|
+
- @shipfox/api-auth-context@9.3.0
|
|
46
|
+
- @shipfox/node-fastify@0.3.4
|
|
47
|
+
- @shipfox/node-mailer@0.2.4
|
|
48
|
+
- @shipfox/node-module@1.0.3
|
|
49
|
+
|
|
3
50
|
## 9.2.0
|
|
4
51
|
|
|
5
52
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Shipfox API Workspaces manages who can use a workspace and send or accept invite
|
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
- **`
|
|
7
|
+
- **`createWorkspacesModule`**: Adds table changes, API routes, outbox events, and metrics.
|
|
8
8
|
- **`ensureMembership`**: Adds a user to a workspace or returns the row that is there.
|
|
9
9
|
- **Invitation helpers**: Make, view, accept, list, and revoke invites.
|
|
10
10
|
- **Workspace helpers**: Read workspaces and check a signed-in user's access.
|
|
@@ -44,7 +44,10 @@ Invitation email uses the shared `@shipfox/node-mailer` configuration.
|
|
|
44
44
|
## Routes / API / Data Model
|
|
45
45
|
|
|
46
46
|
Routes mount under `/workspaces`. They make and list workspaces, manage members,
|
|
47
|
-
and make, list, view, accept, or revoke invites.
|
|
47
|
+
and make, list, view, accept, or revoke invites. The composed module also mounts
|
|
48
|
+
`GET /admin/workspaces`, which requires the Auth `admin-observer` role and returns
|
|
49
|
+
bounded workspace identity, lifecycle, member, project, and best-effort job-count
|
|
50
|
+
summaries. Supporting count failures are represented as `unknown`.
|
|
48
51
|
|
|
49
52
|
The module creates these tables:
|
|
50
53
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ProjectsModuleClient } from '@shipfox/api-projects-dto/inter-module';
|
|
2
|
+
import type { RunnersInterModuleClient } from '@shipfox/api-runners-dto/inter-module';
|
|
3
|
+
import type { StringIdCursor } from '@shipfox/node-drizzle';
|
|
4
|
+
export interface WorkspaceAdministratorSummary {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
status: 'active' | 'suspended' | 'deleted';
|
|
8
|
+
memberSummary: {
|
|
9
|
+
count: number;
|
|
10
|
+
};
|
|
11
|
+
projectSummary: {
|
|
12
|
+
state: 'available';
|
|
13
|
+
count: number;
|
|
14
|
+
} | {
|
|
15
|
+
state: 'unknown';
|
|
16
|
+
};
|
|
17
|
+
jobCounts: {
|
|
18
|
+
state: 'available';
|
|
19
|
+
queued: number;
|
|
20
|
+
running: number;
|
|
21
|
+
} | {
|
|
22
|
+
state: 'unknown';
|
|
23
|
+
};
|
|
24
|
+
createdAt: Date;
|
|
25
|
+
updatedAt: Date;
|
|
26
|
+
}
|
|
27
|
+
export interface ListWorkspaceAdministratorSummariesParams {
|
|
28
|
+
workspaceId?: string | undefined;
|
|
29
|
+
search?: string | undefined;
|
|
30
|
+
status?: 'active' | 'suspended' | 'deleted' | undefined;
|
|
31
|
+
limit: number;
|
|
32
|
+
cursor?: StringIdCursor | undefined;
|
|
33
|
+
projects: ProjectsModuleClient;
|
|
34
|
+
runners: RunnersInterModuleClient;
|
|
35
|
+
}
|
|
36
|
+
export interface ListWorkspaceAdministratorSummariesResult {
|
|
37
|
+
workspaces: WorkspaceAdministratorSummary[];
|
|
38
|
+
nextCursor: StringIdCursor | null;
|
|
39
|
+
}
|
|
40
|
+
export declare function listWorkspaceAdministratorSummaries(params: ListWorkspaceAdministratorSummariesParams): Promise<ListWorkspaceAdministratorSummariesResult>;
|
|
41
|
+
//# sourceMappingURL=admin-workspaces.d.ts.map
|
|
@@ -0,0 +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;AAI1D,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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
2
|
+
import { listAdminWorkspaces as listAdminWorkspaceRows } from '#db/workspaces.js';
|
|
3
|
+
export async function listWorkspaceAdministratorSummaries(params) {
|
|
4
|
+
const result = await listAdminWorkspaceRows(params);
|
|
5
|
+
const workspaceIds = result.workspaces.map(({ id })=>id);
|
|
6
|
+
const [projectCounts, jobCounts] = await Promise.all([
|
|
7
|
+
getProjectCounts(params.projects, workspaceIds),
|
|
8
|
+
getJobCounts(params.runners, workspaceIds)
|
|
9
|
+
]);
|
|
10
|
+
return {
|
|
11
|
+
workspaces: result.workspaces.map((workspace)=>({
|
|
12
|
+
id: workspace.id,
|
|
13
|
+
name: workspace.name,
|
|
14
|
+
status: workspace.status,
|
|
15
|
+
memberSummary: {
|
|
16
|
+
count: workspace.memberCount
|
|
17
|
+
},
|
|
18
|
+
projectSummary: projectCounts?.get(workspace.id) ?? {
|
|
19
|
+
state: 'unknown'
|
|
20
|
+
},
|
|
21
|
+
jobCounts: jobCounts?.get(workspace.id) ?? {
|
|
22
|
+
state: 'unknown'
|
|
23
|
+
},
|
|
24
|
+
createdAt: workspace.createdAt,
|
|
25
|
+
updatedAt: workspace.updatedAt
|
|
26
|
+
})),
|
|
27
|
+
nextCursor: result.nextCursor
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function getProjectCounts(projects, workspaceIds) {
|
|
31
|
+
if (workspaceIds.length === 0) return new Map();
|
|
32
|
+
try {
|
|
33
|
+
const result = await projects.getWorkspaceProjectCounts({
|
|
34
|
+
workspaceIds
|
|
35
|
+
});
|
|
36
|
+
const counts = new Map(result.counts.map(({ workspaceId, count })=>[
|
|
37
|
+
workspaceId,
|
|
38
|
+
{
|
|
39
|
+
state: 'available',
|
|
40
|
+
count
|
|
41
|
+
}
|
|
42
|
+
]));
|
|
43
|
+
return new Map(workspaceIds.map((workspaceId)=>[
|
|
44
|
+
workspaceId,
|
|
45
|
+
counts.get(workspaceId) ?? {
|
|
46
|
+
state: 'unknown'
|
|
47
|
+
}
|
|
48
|
+
]));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
logger().warn({
|
|
51
|
+
operation: 'admin-workspace-project-summary',
|
|
52
|
+
err: error
|
|
53
|
+
}, 'Project summary unavailable');
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function getJobCounts(runners, workspaceIds) {
|
|
58
|
+
if (workspaceIds.length === 0) return new Map();
|
|
59
|
+
try {
|
|
60
|
+
const result = await runners.getWorkspaceJobCounts({
|
|
61
|
+
workspaceIds
|
|
62
|
+
});
|
|
63
|
+
const counts = new Map(result.counts.map(({ workspaceId, queued, running })=>[
|
|
64
|
+
workspaceId,
|
|
65
|
+
{
|
|
66
|
+
state: 'available',
|
|
67
|
+
queued,
|
|
68
|
+
running
|
|
69
|
+
}
|
|
70
|
+
]));
|
|
71
|
+
return new Map(workspaceIds.map((workspaceId)=>[
|
|
72
|
+
workspaceId,
|
|
73
|
+
counts.get(workspaceId) ?? {
|
|
74
|
+
state: 'unknown'
|
|
75
|
+
}
|
|
76
|
+
]));
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger().warn({
|
|
79
|
+
operation: 'admin-workspace-job-counts',
|
|
80
|
+
err: error
|
|
81
|
+
}, 'Job counts unavailable');
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=admin-workspaces.js.map
|
|
@@ -0,0 +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"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { type ListWorkspaceAdministratorSummariesParams, type ListWorkspaceAdministratorSummariesResult, listWorkspaceAdministratorSummaries, type WorkspaceAdministratorSummary, } from './admin-workspaces.js';
|
|
1
2
|
export type { Invitation } from './entities/invitation.js';
|
|
2
3
|
export type { Membership } from './entities/membership.js';
|
|
3
4
|
export type { Workspace, WorkspaceStatus } from './entities/workspace.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,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,GACvB,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"}
|
|
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,GACvB,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,3 +1,4 @@
|
|
|
1
|
+
export { listWorkspaceAdministratorSummaries } from './admin-workspaces.js';
|
|
1
2
|
export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceNotFoundError } from './errors.js';
|
|
2
3
|
export { acceptWorkspaceInvitation, createWorkspaceInvitation, listWorkspaceInvitations, previewInvitation, revokeWorkspaceInvitation } from './invitations.js';
|
|
3
4
|
export { ensureMembership } from './memberships.js';
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export 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":["InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","LastMemberError","MembershipNotFoundError","MembershipRequiredError","OpenInvitationExistsError","SelfRemovalNotAllowedError","TokenAlreadyUsedError","TokenExpiredError","WorkspaceNotFoundError","acceptWorkspaceInvitation","createWorkspaceInvitation","listWorkspaceInvitations","previewInvitation","revokeWorkspaceInvitation","ensureMembership","createWorkspaceForUser","getWorkspace","listUserWorkspaceMemberships","listWorkspaceMembers","removeWorkspaceMember","requireWorkspaceMembership"],"mappings":"
|
|
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,QAE9B,wBAAwB;AAI/B,SACEC,4BAA4B,EAC5BC,uBAAuB,EACvBC,gCAAgC,EAChCC,eAAe,EACfC,uBAAuB,EACvBC,uBAAuB,EACvBC,yBAAyB,EACzBC,0BAA0B,EAC1BC,qBAAqB,EACrBC,iBAAiB,EACjBC,sBAAsB,QACjB,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"}
|
|
@@ -26,6 +26,9 @@ export declare function getWorkspace(params: {
|
|
|
26
26
|
export declare function getWorkspaceCreator(params: {
|
|
27
27
|
workspaceId: string;
|
|
28
28
|
}): Promise<string | null>;
|
|
29
|
+
export declare function getWorkspaceOperatingState(params: {
|
|
30
|
+
workspaceId: string;
|
|
31
|
+
}): Promise<Workspace['status']>;
|
|
29
32
|
export declare function listUserWorkspaceMemberships(params: {
|
|
30
33
|
userId: string;
|
|
31
34
|
}): Promise<MembershipWithWorkspace[]>;
|
|
@@ -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;CACnD;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,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,CAQhC;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,CAiBhB"}
|
|
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;CACnD;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,CAQhC;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,CAiBhB"}
|
package/dist/core/workspaces.js
CHANGED
|
@@ -62,6 +62,10 @@ export async function getWorkspaceCreator(params) {
|
|
|
62
62
|
const workspace = await getWorkspace(params);
|
|
63
63
|
return workspace.createdBy;
|
|
64
64
|
}
|
|
65
|
+
export async function getWorkspaceOperatingState(params) {
|
|
66
|
+
const workspace = await getWorkspace(params);
|
|
67
|
+
return workspace.status;
|
|
68
|
+
}
|
|
65
69
|
export async function listUserWorkspaceMemberships(params) {
|
|
66
70
|
return await listMembershipsByUser({
|
|
67
71
|
userId: params.userId
|
|
@@ -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 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","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;AAerB,OAAO,eAAeC,2BACpBC,MAAwC;IAExC,MAAMC,aAAaD,OAAOX,WAAW,CAACa,IAAI,CAAC,CAACC,IAAMA,EAAEC,WAAW,KAAKJ,OAAOI,WAAW;IACtF,IAAI,CAACH,YAAY;QACf,MAAM,IAAIN,wBAAwBK,OAAOI,WAAW;IACtD;IAEA,MAAMC,YAAY,MAAMZ,iBAAiBO,OAAOI,WAAW;IAC3D,IAAI,CAACC,WAAW;QACd,MAAM,IAAIP,uBAAuBE,OAAOI,WAAW;IACrD;IACA,IAAIC,UAAUC,MAAM,KAAK,UAAU;QACjC,MAAM,IAAIT,uBAAuBG,OAAOI,WAAW;IACrD;IAEA,OAAO;QAACC;QAAWD,aAAaC,UAAUE,EAAE;QAAEC,QAAQR,OAAOQ,MAAM;QAAEC,MAAMR,WAAWQ,IAAI;IAAA;AAC5F;AAEA,OAAO,eAAeC,uBAAuBV,MAK5C;IACC,OAAO,MAAMhB,KAAK2B,WAAW,CAAC,OAAOC;QACnC,MAAM,CAACC,aAAa,GAAG,MAAMD,GAC1BE,MAAM,CAACtB,YACPuB,MAAM,CAAC;YAACC,MAAMhB,OAAOgB,IAAI;YAAEC,WAAWjB,OAAOQ,MAAM;QAAA,GACnDU,SAAS;QACZ,IAAI,CAACL,cAAc,MAAM,IAAIM,MAAM;QACnC,MAAMP,GAAGE,MAAM,CAACzB,aAAa0B,MAAM,CAAC;YAClCP,QAAQR,OAAOQ,MAAM;YACrBY,WAAWpB,OAAOoB,SAAS,IAAI,CAAC,KAAK,EAAEpB,OAAOQ,MAAM,CAAC,cAAc,CAAC;YACpEa,UAAUrB,OAAOqB,QAAQ,IAAI;YAC7BjB,aAAaS,aAAaN,EAAE;QAC9B;QACA,MAAMF,YAAYd,YAAYsB;QAE9B,MAAM9B,iBAAqC6B,IAAItB,kBAAkB;YAC/DgC,MAAMxC;YACNyC,SAAS;gBACPnB,aAAaC,UAAUE,EAAE;gBACzBS,MAAMX,UAAUW,IAAI;gBACpBQ,eAAexB,OAAOQ,MAAM;YAC9B;QACF;QAEA,OAAOH;IACT;AACF;AAEA,OAAO,eAAeoB,aAAazB,MAA6B;IAC9D,MAAMK,YAAY,MAAMZ,iBAAiBO,OAAOI,WAAW;IAC3D,IAAI,CAACC,WAAW;QACd,MAAM,IAAIP,uBAAuBE,OAAOI,WAAW;IACrD;IAEA,OAAOC;AACT;AAEA,OAAO,eAAeqB,oBAAoB1B,MAA6B;IACrE,MAAMK,YAAY,MAAMoB,aAAazB;IACrC,OAAOK,UAAUY,SAAS;AAC5B;AAEA,OAAO,eAAeU,
|
|
1
|
+
{"version":3,"sources":["../../src/core/workspaces.ts"],"sourcesContent":["import type {UserContextMembership} from '@shipfox/api-auth-context';\nimport {\n WORKSPACES_WORKSPACE_CREATED,\n type WorkspaceRole,\n type WorkspacesEventMap,\n} from '@shipfox/api-workspaces-dto';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {db} from '#db/db.js';\nimport {\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n type MembershipWithUser,\n type MembershipWithWorkspace,\n removeMembership,\n} from '#db/memberships.js';\nimport {memberships} from '#db/schema/memberships.js';\nimport {workspacesOutbox} from '#db/schema/outbox.js';\nimport {toWorkspace, workspaces} from '#db/schema/workspaces.js';\nimport {getWorkspaceById} from '#db/workspaces.js';\nimport type {Workspace} from './entities/workspace.js';\nimport {\n MembershipNotFoundError,\n MembershipRequiredError,\n SelfRemovalNotAllowedError,\n WorkspaceInactiveError,\n WorkspaceNotFoundError,\n} from './errors.js';\n\nexport interface RequireWorkspaceMembershipParams {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<UserContextMembership>;\n}\n\nexport interface RequireWorkspaceMembershipResult {\n workspace: Workspace;\n workspaceId: string;\n userId: string;\n role: WorkspaceRole;\n}\n\nexport async function requireWorkspaceMembership(\n params: RequireWorkspaceMembershipParams,\n): Promise<RequireWorkspaceMembershipResult> {\n const membership = params.memberships.find((m) => m.workspaceId === params.workspaceId);\n if (!membership) {\n throw new MembershipRequiredError(params.workspaceId);\n }\n\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n if (workspace.status !== 'active') {\n throw new WorkspaceInactiveError(params.workspaceId);\n }\n\n return {workspace, workspaceId: workspace.id, userId: params.userId, role: membership.role};\n}\n\nexport async function createWorkspaceForUser(params: {\n name: string;\n userId: string;\n userEmail?: string | undefined;\n userName?: string | null | undefined;\n}): Promise<Workspace> {\n return await db().transaction(async (tx) => {\n const [workspaceRow] = await tx\n .insert(workspaces)\n .values({name: params.name, createdBy: params.userId})\n .returning();\n if (!workspaceRow) throw new Error('Insert returned no rows');\n await tx.insert(memberships).values({\n userId: params.userId,\n userEmail: params.userEmail ?? `user-${params.userId}@example.local`,\n userName: params.userName ?? null,\n workspaceId: workspaceRow.id,\n });\n const workspace = toWorkspace(workspaceRow);\n\n await writeOutboxEvent<WorkspacesEventMap>(tx, workspacesOutbox, {\n type: WORKSPACES_WORKSPACE_CREATED,\n payload: {\n workspaceId: workspace.id,\n name: workspace.name,\n creatorUserId: params.userId,\n },\n });\n\n return workspace;\n });\n}\n\nexport async function getWorkspace(params: {workspaceId: string}): Promise<Workspace> {\n const workspace = await getWorkspaceById(params.workspaceId);\n if (!workspace) {\n throw new WorkspaceNotFoundError(params.workspaceId);\n }\n\n return workspace;\n}\n\nexport async function getWorkspaceCreator(params: {workspaceId: string}): Promise<string | null> {\n const workspace = await getWorkspace(params);\n return workspace.createdBy;\n}\n\nexport async function getWorkspaceOperatingState(params: {\n workspaceId: string;\n}): Promise<Workspace['status']> {\n const workspace = await getWorkspace(params);\n return workspace.status;\n}\n\nexport async function listUserWorkspaceMemberships(params: {\n userId: string;\n}): Promise<MembershipWithWorkspace[]> {\n return await listMembershipsByUser({userId: params.userId});\n}\n\nexport async function listWorkspaceMembers(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n}): Promise<MembershipWithUser[]> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n return listMembershipsByWorkspace({workspaceId: params.workspaceId});\n}\n\nexport async function removeWorkspaceMember(params: {\n workspaceId: string;\n requesterUserId: string;\n requesterMemberships: ReadonlyArray<UserContextMembership>;\n userId: string;\n}): Promise<void> {\n await requireWorkspaceMembership({\n workspaceId: params.workspaceId,\n userId: params.requesterUserId,\n memberships: params.requesterMemberships,\n });\n\n if (params.userId === params.requesterUserId) {\n throw new SelfRemovalNotAllowedError();\n }\n\n const target = await findMembership({userId: params.userId, workspaceId: params.workspaceId});\n if (!target) {\n throw new MembershipNotFoundError(params.userId, params.workspaceId);\n }\n\n await removeMembership({userId: params.userId, workspaceId: params.workspaceId});\n}\n"],"names":["WORKSPACES_WORKSPACE_CREATED","writeOutboxEvent","db","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","memberships","workspacesOutbox","toWorkspace","workspaces","getWorkspaceById","MembershipNotFoundError","MembershipRequiredError","SelfRemovalNotAllowedError","WorkspaceInactiveError","WorkspaceNotFoundError","requireWorkspaceMembership","params","membership","find","m","workspaceId","workspace","status","id","userId","role","createWorkspaceForUser","transaction","tx","workspaceRow","insert","values","name","createdBy","returning","Error","userEmail","userName","type","payload","creatorUserId","getWorkspace","getWorkspaceCreator","getWorkspaceOperatingState","listUserWorkspaceMemberships","listWorkspaceMembers","requesterUserId","requesterMemberships","removeWorkspaceMember","target"],"mappings":"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"}
|
package/dist/db/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { createInvitation, findInvitationByToken, listOpenInvitationsByWorkspace
|
|
|
4
4
|
export type { CreateMembershipParams, MembershipWithUser, MembershipWithWorkspace, RemoveMembershipParams, } from './memberships.js';
|
|
5
5
|
export { createMembership, findMembership, listMembershipsByUser, listMembershipsByWorkspace, removeMembership, } from './memberships.js';
|
|
6
6
|
export { workspacesOutbox } from './schema/outbox.js';
|
|
7
|
-
export type { CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceServiceMetrics, } from './workspaces.js';
|
|
8
|
-
export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, updateWorkspace, } from './workspaces.js';
|
|
7
|
+
export type { AdminWorkspaceRow, CreateWorkspaceParams, ListAdminWorkspaceParams, ListAdminWorkspaceResult, UpdateWorkspaceParams, WorkspaceServiceMetrics, } from './workspaces.js';
|
|
8
|
+
export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, listAdminWorkspaces, updateWorkspace, } from './workspaces.js';
|
|
9
9
|
export declare const migrationsPath: string;
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/db/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,eAAO,MAAM,cAAc,QAAoE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,eAAO,MAAM,cAAc,QAAoE,CAAC"}
|
package/dist/db/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { closeDb, db, schema } from './db.js';
|
|
|
4
4
|
export { createInvitation, findInvitationByToken, listOpenInvitationsByWorkspace, revokeInvitation } from './invitations.js';
|
|
5
5
|
export { createMembership, findMembership, listMembershipsByUser, listMembershipsByWorkspace, removeMembership } from './memberships.js';
|
|
6
6
|
export { workspacesOutbox } from './schema/outbox.js';
|
|
7
|
-
export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, updateWorkspace } from './workspaces.js';
|
|
7
|
+
export { createWorkspace, getWorkspaceById, getWorkspaceServiceMetrics, listAdminWorkspaces, updateWorkspace } from './workspaces.js';
|
|
8
8
|
export const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');
|
|
9
9
|
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {CreateInvitationParams} from './invitations.js';\nexport {\n createInvitation,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n revokeInvitation,\n} from './invitations.js';\nexport type {\n CreateMembershipParams,\n MembershipWithUser,\n MembershipWithWorkspace,\n RemoveMembershipParams,\n} from './memberships.js';\nexport {\n createMembership,\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n removeMembership,\n} from './memberships.js';\nexport {workspacesOutbox} from './schema/outbox.js';\nexport type {\n CreateWorkspaceParams,\n UpdateWorkspaceParams,\n WorkspaceServiceMetrics,\n} from './workspaces.js';\nexport {\n createWorkspace,\n getWorkspaceById,\n getWorkspaceServiceMetrics,\n updateWorkspace,\n} from './workspaces.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createInvitation","findInvitationByToken","listOpenInvitationsByWorkspace","revokeInvitation","createMembership","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","workspacesOutbox","createWorkspace","getWorkspaceById","getWorkspaceServiceMetrics","updateWorkspace","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAE5C,SACEC,gBAAgB,EAChBC,qBAAqB,EACrBC,8BAA8B,EAC9BC,gBAAgB,QACX,mBAAmB;AAO1B,SACEC,gBAAgB,EAChBC,cAAc,EACdC,qBAAqB,EACrBC,0BAA0B,EAC1BC,gBAAgB,QACX,mBAAmB;AAC1B,SAAQC,gBAAgB,QAAO,qBAAqB;
|
|
1
|
+
{"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {CreateInvitationParams} from './invitations.js';\nexport {\n createInvitation,\n findInvitationByToken,\n listOpenInvitationsByWorkspace,\n revokeInvitation,\n} from './invitations.js';\nexport type {\n CreateMembershipParams,\n MembershipWithUser,\n MembershipWithWorkspace,\n RemoveMembershipParams,\n} from './memberships.js';\nexport {\n createMembership,\n findMembership,\n listMembershipsByUser,\n listMembershipsByWorkspace,\n removeMembership,\n} from './memberships.js';\nexport {workspacesOutbox} from './schema/outbox.js';\nexport type {\n AdminWorkspaceRow,\n CreateWorkspaceParams,\n ListAdminWorkspaceParams,\n ListAdminWorkspaceResult,\n UpdateWorkspaceParams,\n WorkspaceServiceMetrics,\n} from './workspaces.js';\nexport {\n createWorkspace,\n getWorkspaceById,\n getWorkspaceServiceMetrics,\n listAdminWorkspaces,\n updateWorkspace,\n} from './workspaces.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createInvitation","findInvitationByToken","listOpenInvitationsByWorkspace","revokeInvitation","createMembership","findMembership","listMembershipsByUser","listMembershipsByWorkspace","removeMembership","workspacesOutbox","createWorkspace","getWorkspaceById","getWorkspaceServiceMetrics","listAdminWorkspaces","updateWorkspace","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAE5C,SACEC,gBAAgB,EAChBC,qBAAqB,EACrBC,8BAA8B,EAC9BC,gBAAgB,QACX,mBAAmB;AAO1B,SACEC,gBAAgB,EAChBC,cAAc,EACdC,qBAAqB,EACrBC,0BAA0B,EAC1BC,gBAAgB,QACX,mBAAmB;AAC1B,SAAQC,gBAAgB,QAAO,qBAAqB;AASpD,SACEC,eAAe,EACfC,gBAAgB,EAChBC,0BAA0B,EAC1BC,mBAAmB,EACnBC,eAAe,QACV,kBAAkB;AAEzB,OAAO,MAAMC,iBAAiBpB,QAAQD,QAAQE,cAAc,YAAYoB,GAAG,IAAI,iBAAiB"}
|
package/dist/db/memberships.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Membership } from '#core/entities/membership.js';
|
|
2
|
+
import type { Workspace } from '#core/entities/workspace.js';
|
|
2
3
|
export interface CreateMembershipParams {
|
|
3
4
|
userId: string;
|
|
4
5
|
userEmail?: string | undefined;
|
|
@@ -21,6 +22,7 @@ export declare function createMembership(params: CreateMembershipParams): Promis
|
|
|
21
22
|
export declare function ensureMembership(params: EnsureMembershipParams): Promise<Membership>;
|
|
22
23
|
export interface MembershipWithWorkspace extends Membership {
|
|
23
24
|
workspaceName: string;
|
|
25
|
+
workspaceStatus: Workspace['status'];
|
|
24
26
|
}
|
|
25
27
|
export declare function listMembershipsByUser(params: {
|
|
26
28
|
userId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../../src/db/memberships.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../../src/db/memberships.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAO3D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB;;;;;EAO9D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAO1F;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgB1F;AAED,MAAM,WAAW,uBAAwB,SAAQ,UAAU;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAiBrC;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAOhC;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAYlC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpF"}
|
package/dist/db/memberships.js
CHANGED
|
@@ -38,11 +38,13 @@ export async function ensureMembership(params) {
|
|
|
38
38
|
export async function listMembershipsByUser(params) {
|
|
39
39
|
const rows = await db().select({
|
|
40
40
|
membership: memberships,
|
|
41
|
-
workspaceName: workspaces.name
|
|
41
|
+
workspaceName: workspaces.name,
|
|
42
|
+
workspaceStatus: workspaces.status
|
|
42
43
|
}).from(memberships).innerJoin(workspaces, eq(workspaces.id, memberships.workspaceId)).where(eq(memberships.userId, params.userId)).orderBy(workspaces.name);
|
|
43
44
|
return rows.map((row)=>({
|
|
44
45
|
...toMembership(row.membership),
|
|
45
|
-
workspaceName: row.workspaceName
|
|
46
|
+
workspaceName: row.workspaceName,
|
|
47
|
+
workspaceStatus: row.workspaceStatus
|
|
46
48
|
}));
|
|
47
49
|
}
|
|
48
50
|
export async function listMembershipsByWorkspace(params) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/memberships.ts"],"sourcesContent":["import {and, eq, sql} from 'drizzle-orm';\nimport type {Membership} from '#core/entities/membership.js';\nimport {LastMemberError} from '#core/errors.js';\nimport {recordWorkspaceMembershipChanged} from '#metrics/instance.js';\nimport {db} from './db.js';\nimport {memberships, toMembership} from './schema/memberships.js';\nimport {workspaces} from './schema/workspaces.js';\n\nexport interface CreateMembershipParams {\n userId: string;\n userEmail?: string | undefined;\n userName?: string | null | undefined;\n workspaceId: string;\n}\n\nexport interface EnsureMembershipParams {\n userId: string;\n userEmail: string;\n userName: string | null;\n workspaceId: string;\n}\n\nexport function membershipValues(params: CreateMembershipParams) {\n return {\n userId: params.userId,\n userEmail: params.userEmail ?? `user-${params.userId}@example.local`,\n userName: params.userName ?? null,\n workspaceId: params.workspaceId,\n };\n}\n\nexport async function createMembership(params: CreateMembershipParams): Promise<Membership> {\n const rows = await db().insert(memberships).values(membershipValues(params)).returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n recordWorkspaceMembershipChanged('added');\n return toMembership(row);\n}\n\nexport async function ensureMembership(params: EnsureMembershipParams): Promise<Membership> {\n const rows = await db()\n .insert(memberships)\n .values(membershipValues(params))\n .onConflictDoNothing({target: [memberships.userId, memberships.workspaceId]})\n .returning();\n\n const row = rows[0];\n if (row) {\n recordWorkspaceMembershipChanged('added');\n return toMembership(row);\n }\n\n const existing = await findMembership(params);\n if (existing) return existing;\n throw new Error('Membership conflict returned no membership');\n}\n\nexport interface MembershipWithWorkspace extends Membership {\n workspaceName: string;\n}\n\nexport async function listMembershipsByUser(params: {\n userId: string;\n}): Promise<MembershipWithWorkspace[]> {\n const rows = await db()\n .select({\n membership: memberships,\n workspaceName: workspaces.name,\n })\n .from(memberships)\n .innerJoin(workspaces, eq(workspaces.id, memberships.workspaceId))\n .where(eq(memberships.userId, params.userId))\n .orderBy(workspaces.name);\n\n return rows.map((row) => ({...toMembership(row.membership)
|
|
1
|
+
{"version":3,"sources":["../../src/db/memberships.ts"],"sourcesContent":["import {and, eq, sql} from 'drizzle-orm';\nimport type {Membership} from '#core/entities/membership.js';\nimport type {Workspace} from '#core/entities/workspace.js';\nimport {LastMemberError} from '#core/errors.js';\nimport {recordWorkspaceMembershipChanged} from '#metrics/instance.js';\nimport {db} from './db.js';\nimport {memberships, toMembership} from './schema/memberships.js';\nimport {workspaces} from './schema/workspaces.js';\n\nexport interface CreateMembershipParams {\n userId: string;\n userEmail?: string | undefined;\n userName?: string | null | undefined;\n workspaceId: string;\n}\n\nexport interface EnsureMembershipParams {\n userId: string;\n userEmail: string;\n userName: string | null;\n workspaceId: string;\n}\n\nexport function membershipValues(params: CreateMembershipParams) {\n return {\n userId: params.userId,\n userEmail: params.userEmail ?? `user-${params.userId}@example.local`,\n userName: params.userName ?? null,\n workspaceId: params.workspaceId,\n };\n}\n\nexport async function createMembership(params: CreateMembershipParams): Promise<Membership> {\n const rows = await db().insert(memberships).values(membershipValues(params)).returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n recordWorkspaceMembershipChanged('added');\n return toMembership(row);\n}\n\nexport async function ensureMembership(params: EnsureMembershipParams): Promise<Membership> {\n const rows = await db()\n .insert(memberships)\n .values(membershipValues(params))\n .onConflictDoNothing({target: [memberships.userId, memberships.workspaceId]})\n .returning();\n\n const row = rows[0];\n if (row) {\n recordWorkspaceMembershipChanged('added');\n return toMembership(row);\n }\n\n const existing = await findMembership(params);\n if (existing) return existing;\n throw new Error('Membership conflict returned no membership');\n}\n\nexport interface MembershipWithWorkspace extends Membership {\n workspaceName: string;\n workspaceStatus: Workspace['status'];\n}\n\nexport async function listMembershipsByUser(params: {\n userId: string;\n}): Promise<MembershipWithWorkspace[]> {\n const rows = await db()\n .select({\n membership: memberships,\n workspaceName: workspaces.name,\n workspaceStatus: workspaces.status,\n })\n .from(memberships)\n .innerJoin(workspaces, eq(workspaces.id, memberships.workspaceId))\n .where(eq(memberships.userId, params.userId))\n .orderBy(workspaces.name);\n\n return rows.map((row) => ({\n ...toMembership(row.membership),\n workspaceName: row.workspaceName,\n workspaceStatus: row.workspaceStatus,\n }));\n}\n\nexport interface MembershipWithUser extends Membership {\n userEmail: string;\n userName: string | null;\n}\n\nexport async function listMembershipsByWorkspace(params: {\n workspaceId: string;\n}): Promise<MembershipWithUser[]> {\n const rows = await db()\n .select()\n .from(memberships)\n .where(eq(memberships.workspaceId, params.workspaceId));\n\n return rows.map(toMembership);\n}\n\nexport async function findMembership(params: {\n userId: string;\n workspaceId: string;\n}): Promise<Membership | undefined> {\n const rows = await db()\n .select()\n .from(memberships)\n .where(\n and(eq(memberships.userId, params.userId), eq(memberships.workspaceId, params.workspaceId)),\n )\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toMembership(row);\n}\n\nexport interface RemoveMembershipParams {\n userId: string;\n workspaceId: string;\n}\n\nexport async function removeMembership(params: RemoveMembershipParams): Promise<void> {\n const removed = await db().transaction(async (tx) => {\n const countResult = await tx\n .select({count: sql<number>`count(*)::int`})\n .from(memberships)\n .where(eq(memberships.workspaceId, params.workspaceId));\n const total = countResult[0]?.count ?? 0;\n if (total <= 1) {\n throw new LastMemberError(params.workspaceId);\n }\n\n const deleted = await tx\n .delete(memberships)\n .where(\n and(eq(memberships.userId, params.userId), eq(memberships.workspaceId, params.workspaceId)),\n )\n .returning({id: memberships.id});\n\n return deleted.length > 0;\n });\n\n if (removed) recordWorkspaceMembershipChanged('removed');\n}\n"],"names":["and","eq","sql","LastMemberError","recordWorkspaceMembershipChanged","db","memberships","toMembership","workspaces","membershipValues","params","userId","userEmail","userName","workspaceId","createMembership","rows","insert","values","returning","row","Error","ensureMembership","onConflictDoNothing","target","existing","findMembership","listMembershipsByUser","select","membership","workspaceName","name","workspaceStatus","status","from","innerJoin","id","where","orderBy","map","listMembershipsByWorkspace","limit","undefined","removeMembership","removed","transaction","tx","countResult","count","total","deleted","delete","length"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/db/schema/workspaces.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,SAAS,EAAkB,MAAM,6BAA6B,CAAC;AAG5E,eAAO,MAAM,mBAAmB,0EAI9B,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/db/schema/workspaces.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,SAAS,EAAkB,MAAM,6BAA6B,CAAC;AAG5E,eAAO,MAAM,mBAAmB,0EAI9B,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AACzD,MAAM,MAAM,iBAAiB,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AAE/D,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,SAAS,CAUvD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { uuidv7PrimaryKey } from '@shipfox/node-drizzle';
|
|
2
|
-
import { jsonb, pgEnum, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
2
|
+
import { index, jsonb, pgEnum, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
3
3
|
import { pgTable } from './common.js';
|
|
4
4
|
export const workspaceStatusEnum = pgEnum('workspaces_workspace_status', [
|
|
5
5
|
'active',
|
|
@@ -18,7 +18,9 @@ export const workspaces = pgTable('workspaces', {
|
|
|
18
18
|
updatedAt: timestamp('updated_at', {
|
|
19
19
|
withTimezone: true
|
|
20
20
|
}).notNull().defaultNow()
|
|
21
|
-
})
|
|
21
|
+
}, (table)=>[
|
|
22
|
+
index('workspaces_name_id_idx').on(table.name, table.id)
|
|
23
|
+
]);
|
|
22
24
|
export function toWorkspace(row) {
|
|
23
25
|
return {
|
|
24
26
|
id: row.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/db/schema/workspaces.ts"],"sourcesContent":["import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {jsonb, pgEnum, text, timestamp, uuid} from 'drizzle-orm/pg-core';\nimport type {Workspace, WorkspaceStatus} from '#core/entities/workspace.js';\nimport {pgTable} from './common.js';\n\nexport const workspaceStatusEnum = pgEnum('workspaces_workspace_status', [\n 'active',\n 'suspended',\n 'deleted',\n]);\n\nexport const workspaces = pgTable('workspaces'
|
|
1
|
+
{"version":3,"sources":["../../../src/db/schema/workspaces.ts"],"sourcesContent":["import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {index, jsonb, pgEnum, text, timestamp, uuid} from 'drizzle-orm/pg-core';\nimport type {Workspace, WorkspaceStatus} from '#core/entities/workspace.js';\nimport {pgTable} from './common.js';\n\nexport const workspaceStatusEnum = pgEnum('workspaces_workspace_status', [\n 'active',\n 'suspended',\n 'deleted',\n]);\n\nexport const workspaces = pgTable(\n 'workspaces',\n {\n id: uuidv7PrimaryKey(),\n name: text('name').notNull(),\n status: workspaceStatusEnum('status').notNull().default('active'),\n settings: jsonb('settings').notNull().default({}),\n createdBy: uuid('created_by'),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),\n },\n (table) => [index('workspaces_name_id_idx').on(table.name, table.id)],\n);\n\nexport type WorkspaceDb = typeof workspaces.$inferSelect;\nexport type WorkspaceCreateDb = typeof workspaces.$inferInsert;\n\nexport function toWorkspace(row: WorkspaceDb): Workspace {\n return {\n id: row.id,\n name: row.name,\n status: row.status as WorkspaceStatus,\n settings: row.settings as Record<string, unknown>,\n createdBy: row.createdBy,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n"],"names":["uuidv7PrimaryKey","index","jsonb","pgEnum","text","timestamp","uuid","pgTable","workspaceStatusEnum","workspaces","id","name","notNull","status","default","settings","createdBy","createdAt","withTimezone","defaultNow","updatedAt","table","on","toWorkspace","row"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,wBAAwB;AACvD,SAAQC,KAAK,EAAEC,KAAK,EAAEC,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAEC,IAAI,QAAO,sBAAsB;AAEhF,SAAQC,OAAO,QAAO,cAAc;AAEpC,OAAO,MAAMC,sBAAsBL,OAAO,+BAA+B;IACvE;IACA;IACA;CACD,EAAE;AAEH,OAAO,MAAMM,aAAaF,QACxB,cACA;IACEG,IAAIV;IACJW,MAAMP,KAAK,QAAQQ,OAAO;IAC1BC,QAAQL,oBAAoB,UAAUI,OAAO,GAAGE,OAAO,CAAC;IACxDC,UAAUb,MAAM,YAAYU,OAAO,GAAGE,OAAO,CAAC,CAAC;IAC/CE,WAAWV,KAAK;IAChBW,WAAWZ,UAAU,cAAc;QAACa,cAAc;IAAI,GAAGN,OAAO,GAAGO,UAAU;IAC7EC,WAAWf,UAAU,cAAc;QAACa,cAAc;IAAI,GAAGN,OAAO,GAAGO,UAAU;AAC/E,GACA,CAACE,QAAU;QAACpB,MAAM,0BAA0BqB,EAAE,CAACD,MAAMV,IAAI,EAAEU,MAAMX,EAAE;KAAE,EACrE;AAKF,OAAO,SAASa,YAAYC,GAAgB;IAC1C,OAAO;QACLd,IAAIc,IAAId,EAAE;QACVC,MAAMa,IAAIb,IAAI;QACdE,QAAQW,IAAIX,MAAM;QAClBE,UAAUS,IAAIT,QAAQ;QACtBC,WAAWQ,IAAIR,SAAS;QACxBC,WAAWO,IAAIP,SAAS;QACxBG,WAAWI,IAAIJ,SAAS;IAC1B;AACF"}
|
package/dist/db/workspaces.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StringIdCursor } from '@shipfox/node-drizzle';
|
|
1
2
|
import type { Workspace, WorkspaceStatus } from '#core/entities/workspace.js';
|
|
2
3
|
export interface CreateWorkspaceParams {
|
|
3
4
|
name: string;
|
|
@@ -11,6 +12,21 @@ export interface UpdateWorkspaceParams {
|
|
|
11
12
|
}
|
|
12
13
|
export declare function updateWorkspace(params: UpdateWorkspaceParams): Promise<Workspace | undefined>;
|
|
13
14
|
export declare function getWorkspaceById(id: string): Promise<Workspace | undefined>;
|
|
15
|
+
export interface AdminWorkspaceRow extends Workspace {
|
|
16
|
+
memberCount: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ListAdminWorkspaceParams {
|
|
19
|
+
workspaceId?: string | undefined;
|
|
20
|
+
search?: string | undefined;
|
|
21
|
+
status?: WorkspaceStatus | undefined;
|
|
22
|
+
limit: number;
|
|
23
|
+
cursor?: StringIdCursor | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface ListAdminWorkspaceResult {
|
|
26
|
+
workspaces: AdminWorkspaceRow[];
|
|
27
|
+
nextCursor: StringIdCursor | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function listAdminWorkspaces(params: ListAdminWorkspaceParams): Promise<ListAdminWorkspaceResult>;
|
|
14
30
|
export interface WorkspaceServiceMetrics {
|
|
15
31
|
activeWorkspaces: number;
|
|
16
32
|
memberships: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/db/workspaces.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/db/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,6BAA6B,CAAC;AAO5E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC,CAYvF;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAehC;AAED,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAKjF;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;CACnC;AAUD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CAwCnC;AAMD,MAAM,WAAW,uBAAuB;IACtC,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAenF"}
|
package/dist/db/workspaces.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, count, eq, gt, isNull, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, asc, count, eq, gt, ilike, inArray, isNull, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { recordWorkspaceCreated } from '#metrics/instance.js';
|
|
3
3
|
import { db } from './db.js';
|
|
4
4
|
import { invitations } from './schema/invitations.js';
|
|
@@ -31,6 +31,48 @@ export async function getWorkspaceById(id) {
|
|
|
31
31
|
if (!row) return undefined;
|
|
32
32
|
return toWorkspace(row);
|
|
33
33
|
}
|
|
34
|
+
function adminWorkspaceCursorWhere(cursor) {
|
|
35
|
+
if (!cursor) return undefined;
|
|
36
|
+
return or(gt(workspaces.name, cursor.value), and(eq(workspaces.name, cursor.value), gt(workspaces.id, cursor.id)));
|
|
37
|
+
}
|
|
38
|
+
export async function listAdminWorkspaces(params) {
|
|
39
|
+
const conditions = [];
|
|
40
|
+
if (params.workspaceId) conditions.push(eq(workspaces.id, params.workspaceId));
|
|
41
|
+
if (params.search) {
|
|
42
|
+
conditions.push(ilike(workspaces.name, `%${escapeIlikePattern(params.search)}%`));
|
|
43
|
+
}
|
|
44
|
+
if (params.status) conditions.push(eq(workspaces.status, params.status));
|
|
45
|
+
const cursor = adminWorkspaceCursorWhere(params.cursor);
|
|
46
|
+
if (cursor) conditions.push(cursor);
|
|
47
|
+
const rows = await db().select({
|
|
48
|
+
workspace: workspaces
|
|
49
|
+
}).from(workspaces).where(conditions.length > 0 ? and(...conditions) : undefined).orderBy(asc(workspaces.name), asc(workspaces.id)).limit(params.limit + 1);
|
|
50
|
+
const hasMore = rows.length > params.limit;
|
|
51
|
+
const pageRows = hasMore ? rows.slice(0, params.limit) : rows;
|
|
52
|
+
const last = pageRows.at(-1);
|
|
53
|
+
const workspaceIds = pageRows.map((row)=>row.workspace.id);
|
|
54
|
+
const memberCountRows = workspaceIds.length > 0 ? await db().select({
|
|
55
|
+
workspaceId: memberships.workspaceId,
|
|
56
|
+
memberCount: count(memberships.id)
|
|
57
|
+
}).from(memberships).where(inArray(memberships.workspaceId, workspaceIds)).groupBy(memberships.workspaceId) : [];
|
|
58
|
+
const memberCounts = new Map(memberCountRows.map((row)=>[
|
|
59
|
+
row.workspaceId,
|
|
60
|
+
Number(row.memberCount)
|
|
61
|
+
]));
|
|
62
|
+
return {
|
|
63
|
+
workspaces: pageRows.map((row)=>({
|
|
64
|
+
...toWorkspace(row.workspace),
|
|
65
|
+
memberCount: memberCounts.get(row.workspace.id) ?? 0
|
|
66
|
+
})),
|
|
67
|
+
nextCursor: hasMore && last ? {
|
|
68
|
+
value: last.workspace.name,
|
|
69
|
+
id: last.workspace.id
|
|
70
|
+
} : null
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function escapeIlikePattern(value) {
|
|
74
|
+
return value.replace(/[\\%_]/g, (char)=>`\\${char}`);
|
|
75
|
+
}
|
|
34
76
|
export async function getWorkspaceServiceMetrics() {
|
|
35
77
|
const [workspaceRows, membershipRows, invitationRows] = await Promise.all([
|
|
36
78
|
db().select({
|