@shipfox/api-workspaces 9.1.0 → 9.3.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 +23 -0
- 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/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/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/core/workspaces.test.ts +19 -1
- package/src/core/workspaces.ts +7 -0
- package/src/presentation/inter-module.test.ts +39 -1
- package/src/presentation/inter-module.ts +19 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/api-workspaces",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.3.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -24,17 +24,17 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"drizzle-orm": "^0.45.2",
|
|
26
26
|
"zod": "^4.4.3",
|
|
27
|
-
"@shipfox/api-common-dto": "9.0
|
|
28
|
-
"@shipfox/api-auth-context": "9.0
|
|
29
|
-
"@shipfox/api-workspaces-dto": "9.0
|
|
27
|
+
"@shipfox/api-common-dto": "9.2.0",
|
|
28
|
+
"@shipfox/api-auth-context": "9.3.0",
|
|
29
|
+
"@shipfox/api-workspaces-dto": "9.3.0",
|
|
30
30
|
"@shipfox/config": "1.2.4",
|
|
31
31
|
"@shipfox/inter-module": "0.2.2",
|
|
32
32
|
"@shipfox/node-drizzle": "0.3.4",
|
|
33
|
-
"@shipfox/node-fastify": "0.3.
|
|
33
|
+
"@shipfox/node-fastify": "0.3.4",
|
|
34
34
|
"@shipfox/node-email": "0.3.4",
|
|
35
|
-
"@shipfox/node-mailer": "0.2.
|
|
36
|
-
"@shipfox/node-module": "1.0.
|
|
37
|
-
"@shipfox/node-opentelemetry": "0.6.
|
|
35
|
+
"@shipfox/node-mailer": "0.2.4",
|
|
36
|
+
"@shipfox/node-module": "1.0.3",
|
|
37
|
+
"@shipfox/node-opentelemetry": "0.6.3",
|
|
38
38
|
"@shipfox/node-outbox": "0.2.6",
|
|
39
39
|
"@shipfox/node-postgres": "0.4.4",
|
|
40
40
|
"@shipfox/node-tokens": "0.3.2"
|
|
@@ -3,9 +3,14 @@ import {sql} from 'drizzle-orm';
|
|
|
3
3
|
import {db} from '#db/db.js';
|
|
4
4
|
import {findMembership} from '#db/memberships.js';
|
|
5
5
|
import {workspacesOutbox} from '#db/schema/outbox.js';
|
|
6
|
+
import {updateWorkspace} from '#db/workspaces.js';
|
|
6
7
|
import {userFactory} from '#test/index.js';
|
|
7
8
|
import {MembershipRequiredError, WorkspaceNotFoundError} from './errors.js';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
createWorkspaceForUser,
|
|
11
|
+
getWorkspaceOperatingState,
|
|
12
|
+
requireWorkspaceMembership,
|
|
13
|
+
} from './workspaces.js';
|
|
9
14
|
|
|
10
15
|
describe('workspaces core', () => {
|
|
11
16
|
test('createWorkspaceForUser creates a workspace and membership for the user', async () => {
|
|
@@ -67,6 +72,19 @@ describe('workspaces core', () => {
|
|
|
67
72
|
expect(result.role).toBe('admin');
|
|
68
73
|
});
|
|
69
74
|
|
|
75
|
+
test('getWorkspaceOperatingState returns the current status without workspace details', async () => {
|
|
76
|
+
const workspace = await createWorkspaceForUser({
|
|
77
|
+
name: 'Operating State Workspace',
|
|
78
|
+
userId: crypto.randomUUID(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(await getWorkspaceOperatingState({workspaceId: workspace.id})).toBe('active');
|
|
82
|
+
|
|
83
|
+
await updateWorkspace({id: workspace.id, status: 'suspended'});
|
|
84
|
+
|
|
85
|
+
expect(await getWorkspaceOperatingState({workspaceId: workspace.id})).toBe('suspended');
|
|
86
|
+
});
|
|
87
|
+
|
|
70
88
|
test('requireWorkspaceMembership rejects when memberships do not include the workspace', async () => {
|
|
71
89
|
const owner = userFactory.build();
|
|
72
90
|
const outsider = userFactory.build();
|
package/src/core/workspaces.ts
CHANGED
|
@@ -106,6 +106,13 @@ export async function getWorkspaceCreator(params: {workspaceId: string}): Promis
|
|
|
106
106
|
return workspace.createdBy;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
export async function getWorkspaceOperatingState(params: {
|
|
110
|
+
workspaceId: string;
|
|
111
|
+
}): Promise<Workspace['status']> {
|
|
112
|
+
const workspace = await getWorkspace(params);
|
|
113
|
+
return workspace.status;
|
|
114
|
+
}
|
|
115
|
+
|
|
109
116
|
export async function listUserWorkspaceMemberships(params: {
|
|
110
117
|
userId: string;
|
|
111
118
|
}): Promise<MembershipWithWorkspace[]> {
|
|
@@ -3,7 +3,7 @@ import {isInterModuleKnownError} from '@shipfox/inter-module';
|
|
|
3
3
|
import {createInMemoryInterModuleTransport} from '@shipfox/node-module/inter-module';
|
|
4
4
|
import {createWorkspaceForUser} from '#core/workspaces.js';
|
|
5
5
|
import {createMembership, removeMembership} from '#db/memberships.js';
|
|
6
|
-
import {createWorkspace} from '#db/workspaces.js';
|
|
6
|
+
import {createWorkspace, updateWorkspace} from '#db/workspaces.js';
|
|
7
7
|
import {createWorkspacesInterModulePresentation} from './inter-module.js';
|
|
8
8
|
|
|
9
9
|
function createClient() {
|
|
@@ -54,6 +54,21 @@ describe('Workspaces inter-module presentation', () => {
|
|
|
54
54
|
expect(result).toEqual({creatorUserId: null});
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
test('returns only the current workspace operating state', async () => {
|
|
58
|
+
const client = createClient();
|
|
59
|
+
const workspace = await createWorkspace({name: 'Operating State Workspace'});
|
|
60
|
+
|
|
61
|
+
expect(await client.getWorkspaceOperatingState({workspaceId: workspace.id})).toEqual({
|
|
62
|
+
status: 'active',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await updateWorkspace({id: workspace.id, status: 'suspended'});
|
|
66
|
+
|
|
67
|
+
expect(await client.getWorkspaceOperatingState({workspaceId: workspace.id})).toEqual({
|
|
68
|
+
status: 'suspended',
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
57
72
|
test('maps a missing workspace to the published known error', async () => {
|
|
58
73
|
const client = createClient();
|
|
59
74
|
const workspaceId = crypto.randomUUID();
|
|
@@ -68,4 +83,27 @@ describe('Workspaces inter-module presentation', () => {
|
|
|
68
83
|
expect(error.details).toEqual({workspaceId});
|
|
69
84
|
}
|
|
70
85
|
});
|
|
86
|
+
|
|
87
|
+
test('maps a missing operating-state workspace to the published known error', async () => {
|
|
88
|
+
const client = createClient();
|
|
89
|
+
const workspaceId = crypto.randomUUID();
|
|
90
|
+
|
|
91
|
+
const error = await client.getWorkspaceOperatingState({workspaceId}).catch((caught) => caught);
|
|
92
|
+
|
|
93
|
+
expect(
|
|
94
|
+
isInterModuleKnownError(
|
|
95
|
+
workspacesInterModuleContract.methods.getWorkspaceOperatingState,
|
|
96
|
+
error,
|
|
97
|
+
),
|
|
98
|
+
).toBe(true);
|
|
99
|
+
if (
|
|
100
|
+
isInterModuleKnownError(
|
|
101
|
+
workspacesInterModuleContract.methods.getWorkspaceOperatingState,
|
|
102
|
+
error,
|
|
103
|
+
)
|
|
104
|
+
) {
|
|
105
|
+
expect(error.code).toBe('workspace-not-found');
|
|
106
|
+
expect(error.details).toEqual({workspaceId});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
71
109
|
});
|
|
@@ -14,7 +14,11 @@ import {
|
|
|
14
14
|
WorkspaceNotFoundError,
|
|
15
15
|
} from '#core/errors.js';
|
|
16
16
|
import {acceptWorkspaceInvitation, peekInvitationByRawToken} from '#core/invitations.js';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
getWorkspaceCreator,
|
|
19
|
+
getWorkspaceOperatingState,
|
|
20
|
+
requireWorkspaceMembership,
|
|
21
|
+
} from '#core/workspaces.js';
|
|
18
22
|
import {listMembershipsByUser} from '#db/memberships.js';
|
|
19
23
|
|
|
20
24
|
export function createWorkspacesInterModulePresentation(): InterModulePresentation<
|
|
@@ -41,6 +45,20 @@ export function createWorkspacesInterModulePresentation(): InterModulePresentati
|
|
|
41
45
|
throw error;
|
|
42
46
|
}
|
|
43
47
|
},
|
|
48
|
+
getWorkspaceOperatingState: async (input) => {
|
|
49
|
+
try {
|
|
50
|
+
return {status: await getWorkspaceOperatingState(input)};
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error instanceof WorkspaceNotFoundError) {
|
|
53
|
+
throw createInterModuleKnownError(
|
|
54
|
+
workspacesInterModuleContract.methods.getWorkspaceOperatingState,
|
|
55
|
+
'workspace-not-found',
|
|
56
|
+
{workspaceId: input.workspaceId},
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
44
62
|
preflightInvitationAcceptance: async (input) => {
|
|
45
63
|
try {
|
|
46
64
|
const invitation = await peekInvitationByRawToken({token: input.token});
|