@jskit-ai/users-core 0.1.48 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/package.descriptor.mjs +7 -7
  2. package/package.json +7 -17
  3. package/src/server/common/services/authProfileSyncService.js +28 -7
  4. package/src/server/common/support/realtimeServiceEvents.js +1 -59
  5. package/src/server/profileSyncLifecycleContributorRegistry.js +56 -0
  6. package/src/server/registerUsersBootstrap.js +0 -1
  7. package/src/server/registerUsersCore.js +2 -14
  8. package/src/server/usersBootstrapContributor.js +2 -64
  9. package/src/shared/index.js +2 -99
  10. package/src/shared/settings.js +1 -119
  11. package/test/authProfileSyncService.test.js +19 -10
  12. package/test/registerServiceRealtimeEvents.test.js +0 -86
  13. package/test/registerUsersCore.test.js +6 -15
  14. package/test/repositoryContracts.test.js +1 -9
  15. package/test/resourcesCanonical.test.js +0 -16
  16. package/test/settingsFieldRegistriesSingleton.test.js +0 -5
  17. package/test/usersBootstrapContributor.test.js +2 -26
  18. package/test/usersRouteResources.test.js +0 -16
  19. package/src/server/UsersWorkspacesServiceProvider.js +0 -44
  20. package/src/server/common/contributors/workspaceActionContextContributor.js +0 -88
  21. package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +0 -34
  22. package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +0 -78
  23. package/src/server/common/formatters/workspaceFormatter.js +0 -53
  24. package/src/server/common/repositories/workspaceInvitesRepository.js +0 -208
  25. package/src/server/common/repositories/workspaceMembershipsRepository.js +0 -190
  26. package/src/server/common/repositories/workspacesRepository.js +0 -202
  27. package/src/server/common/services/workspaceContextService.js +0 -281
  28. package/src/server/common/support/workspaceRoutePaths.js +0 -17
  29. package/src/server/common/validators/routeParamsValidator.js +0 -62
  30. package/src/server/registerWorkspaceBootstrap.js +0 -27
  31. package/src/server/registerWorkspaceCore.js +0 -73
  32. package/src/server/registerWorkspaceRepositories.js +0 -26
  33. package/src/server/support/resolveWorkspace.js +0 -16
  34. package/src/server/support/workspaceActionSurfaces.js +0 -118
  35. package/src/server/support/workspaceInvitationsPolicy.js +0 -45
  36. package/src/server/support/workspaceRouteInput.js +0 -22
  37. package/src/server/workspaceBootstrapContributor.js +0 -212
  38. package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +0 -133
  39. package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
  40. package/src/server/workspaceDirectory/workspaceDirectoryActions.js +0 -133
  41. package/src/server/workspaceMembers/bootWorkspaceMembers.js +0 -236
  42. package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -108
  43. package/src/server/workspaceMembers/workspaceMembersActions.js +0 -186
  44. package/src/server/workspaceMembers/workspaceMembersService.js +0 -222
  45. package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +0 -62
  46. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -119
  47. package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +0 -74
  48. package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +0 -138
  49. package/src/server/workspaceSettings/bootWorkspaceSettings.js +0 -76
  50. package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -62
  51. package/src/server/workspaceSettings/workspaceSettingsActions.js +0 -72
  52. package/src/server/workspaceSettings/workspaceSettingsRepository.js +0 -154
  53. package/src/server/workspaceSettings/workspaceSettingsService.js +0 -66
  54. package/src/shared/resources/workspaceMembersResource.js +0 -354
  55. package/src/shared/resources/workspacePendingInvitationsResource.js +0 -82
  56. package/src/shared/resources/workspaceResource.js +0 -176
  57. package/src/shared/resources/workspaceSettingsFields.js +0 -59
  58. package/src/shared/resources/workspaceSettingsResource.js +0 -169
  59. package/src/shared/roles.js +0 -161
  60. package/src/shared/support/usersApiPaths.js +0 -43
  61. package/src/shared/support/usersVisibility.js +0 -42
  62. package/src/shared/support/workspacePathModel.js +0 -145
  63. package/src/shared/tenancyMode.js +0 -35
  64. package/src/shared/tenancyProfile.js +0 -73
  65. package/test/registerWorkspaceDirectory.test.js +0 -31
  66. package/test/registerWorkspaceSettings.test.js +0 -40
  67. package/test/roles.test.js +0 -159
  68. package/test/tenancyProfile.test.js +0 -67
  69. package/test/usersApiPaths.test.js +0 -49
  70. package/test/usersRouteValidators.test.js +0 -49
  71. package/test/usersVisibility.test.js +0 -27
  72. package/test/workspaceActionContextContributor.test.js +0 -344
  73. package/test/workspaceActionSurfaces.test.js +0 -85
  74. package/test/workspaceAuthPolicyContextResolver.test.js +0 -119
  75. package/test/workspaceBootstrapContributor.test.js +0 -154
  76. package/test/workspaceInvitationsPolicy.test.js +0 -71
  77. package/test/workspaceInvitesRepository.test.js +0 -111
  78. package/test/workspaceMembersService.test.js +0 -398
  79. package/test/workspacePathModel.test.js +0 -93
  80. package/test/workspacePendingInvitationsResource.test.js +0 -38
  81. package/test/workspacePendingInvitationsService.test.js +0 -151
  82. package/test/workspaceRouteVisibilityResolver.test.js +0 -83
  83. package/test/workspaceService.test.js +0 -546
  84. package/test/workspaceSettingsActions.test.js +0 -52
  85. package/test/workspaceSettingsRepository.test.js +0 -202
  86. package/test/workspaceSettingsResource.test.js +0 -169
  87. package/test/workspaceSettingsService.test.js +0 -140
@@ -1,27 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import {
4
- isWorkspaceVisibility,
5
- checkRouteVisibility
6
- } from "../src/shared/support/usersVisibility.js";
7
-
8
- test("checkRouteVisibility normalizes valid users visibility levels and throws on invalid input", () => {
9
- assert.equal(checkRouteVisibility("WORKSPACE"), "workspace");
10
- assert.equal(checkRouteVisibility("workspace_user"), "workspace_user");
11
- assert.equal(checkRouteVisibility("user"), "user");
12
- assert.throws(
13
- () => checkRouteVisibility(""),
14
- /must be one of/
15
- );
16
- assert.throws(
17
- () => checkRouteVisibility("unknown"),
18
- /must be one of/
19
- );
20
- });
21
-
22
- test("isWorkspaceVisibility recognizes workspace-only visibility levels", () => {
23
- assert.equal(isWorkspaceVisibility("workspace"), true);
24
- assert.equal(isWorkspaceVisibility("workspace_user"), true);
25
- assert.equal(isWorkspaceVisibility("public"), false);
26
- assert.equal(isWorkspaceVisibility("user"), false);
27
- });
@@ -1,344 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createWorkspaceActionContextContributor } from "../src/server/common/contributors/workspaceActionContextContributor.js";
4
-
5
- test("workspace action context contributor resolves workspace context for workspace actions", async () => {
6
- const calls = [];
7
- const contributor = createWorkspaceActionContextContributor({
8
- workspaceService: {
9
- async resolveWorkspaceContextForUserBySlug(user, workspaceSlug, options) {
10
- calls.push({
11
- user,
12
- workspaceSlug,
13
- options
14
- });
15
-
16
- return {
17
- workspace: {
18
- id: 10,
19
- slug: "acme"
20
- },
21
- membership: {
22
- roleSid: "owner"
23
- },
24
- permissions: ["workspace.settings.update"]
25
- };
26
- }
27
- },
28
- workspaceSurfaceIds: ["admin", "app"]
29
- });
30
-
31
- const request = {
32
- user: {
33
- id: 42,
34
- email: "user@example.com"
35
- }
36
- };
37
-
38
- const contribution = await contributor.contribute({
39
- definition: {
40
- id: "workspace.settings.update",
41
- surfaces: ["admin", "app"]
42
- },
43
- input: {
44
- workspaceSlug: "Acme"
45
- },
46
- context: {
47
- requestMeta: {
48
- request
49
- }
50
- },
51
- request
52
- });
53
-
54
- assert.deepEqual(calls, [
55
- {
56
- user: request.user,
57
- workspaceSlug: "Acme",
58
- options: {
59
- request
60
- }
61
- }
62
- ]);
63
- assert.deepEqual(contribution, {
64
- requestMeta: {
65
- resolvedWorkspaceContext: {
66
- workspace: {
67
- id: 10,
68
- slug: "acme"
69
- },
70
- membership: {
71
- roleSid: "owner"
72
- },
73
- permissions: ["workspace.settings.update"]
74
- }
75
- },
76
- workspace: {
77
- id: 10,
78
- slug: "acme"
79
- },
80
- membership: {
81
- roleSid: "owner"
82
- },
83
- permissions: ["workspace.settings.update"]
84
- });
85
- });
86
-
87
- test("workspace action context contributor ignores actions that do not require workspace context", async () => {
88
- const contributor = createWorkspaceActionContextContributor({
89
- workspaceService: {
90
- async resolveWorkspaceContextForUserBySlug() {
91
- throw new Error("should not be called");
92
- }
93
- }
94
- });
95
-
96
- const contribution = await contributor.contribute({
97
- actionId: "workspace.workspaces.list",
98
- input: {
99
- workspaceSlug: "acme"
100
- },
101
- context: {}
102
- });
103
-
104
- assert.deepEqual(contribution, {});
105
- });
106
-
107
- test("workspace action context contributor always resolves and stores resolved context", async () => {
108
- const calls = [];
109
- const contributor = createWorkspaceActionContextContributor({
110
- workspaceService: {
111
- async resolveWorkspaceContextForUserBySlug(user, workspaceSlug, options) {
112
- calls.push({ user, workspaceSlug, options });
113
- return {
114
- workspace: {
115
- id: 10,
116
- slug: "acme",
117
- ownerUserId: 77
118
- },
119
- membership: {
120
- roleSid: "owner"
121
- },
122
- permissions: ["workspace.settings.update"]
123
- };
124
- }
125
- },
126
- workspaceSurfaceIds: ["admin", "app"]
127
- });
128
-
129
- const request = {
130
- user: {
131
- id: 42
132
- }
133
- };
134
-
135
- const contribution = await contributor.contribute({
136
- definition: {
137
- id: "workspace.members.list",
138
- surfaces: ["admin", "app"]
139
- },
140
- input: {
141
- workspaceSlug: "acme"
142
- },
143
- context: {
144
- workspace: {
145
- id: 1
146
- },
147
- requestMeta: {
148
- request
149
- }
150
- },
151
- request
152
- });
153
-
154
- assert.deepEqual(calls, [
155
- {
156
- user: request.user,
157
- workspaceSlug: "acme",
158
- options: {
159
- request
160
- }
161
- }
162
- ]);
163
- assert.deepEqual(contribution, {
164
- requestMeta: {
165
- resolvedWorkspaceContext: {
166
- workspace: {
167
- id: 10,
168
- slug: "acme",
169
- ownerUserId: 77
170
- },
171
- membership: {
172
- roleSid: "owner"
173
- },
174
- permissions: ["workspace.settings.update"]
175
- }
176
- },
177
- membership: {
178
- roleSid: "owner"
179
- },
180
- permissions: ["workspace.settings.update"]
181
- });
182
- });
183
-
184
- test("workspace action context contributor resolves context for workspace-visible routes outside legacy action list", async () => {
185
- const calls = [];
186
- const contributor = createWorkspaceActionContextContributor({
187
- workspaceService: {
188
- async resolveWorkspaceContextForUserBySlug(user, workspaceSlug, options) {
189
- calls.push({ user, workspaceSlug, options });
190
- return {
191
- workspace: {
192
- id: 33,
193
- slug: "acme"
194
- },
195
- membership: {
196
- roleSid: "admin"
197
- },
198
- permissions: ["assistant.chat.use"]
199
- };
200
- }
201
- }
202
- });
203
-
204
- const request = {
205
- user: {
206
- id: 42
207
- },
208
- routeOptions: {
209
- config: {
210
- visibility: "workspace"
211
- }
212
- }
213
- };
214
-
215
- const contribution = await contributor.contribute({
216
- definition: {
217
- id: "assistant.conversations.list",
218
- surfaces: ["admin"]
219
- },
220
- input: {
221
- workspaceSlug: "acme"
222
- },
223
- context: {
224
- requestMeta: {
225
- request
226
- }
227
- },
228
- request
229
- });
230
-
231
- assert.deepEqual(calls, [
232
- {
233
- user: request.user,
234
- workspaceSlug: "acme",
235
- options: {
236
- request
237
- }
238
- }
239
- ]);
240
- assert.deepEqual(contribution, {
241
- requestMeta: {
242
- resolvedWorkspaceContext: {
243
- workspace: {
244
- id: 33,
245
- slug: "acme"
246
- },
247
- membership: {
248
- roleSid: "admin"
249
- },
250
- permissions: ["assistant.chat.use"]
251
- }
252
- },
253
- workspace: {
254
- id: 33,
255
- slug: "acme"
256
- },
257
- membership: {
258
- roleSid: "admin"
259
- },
260
- permissions: ["assistant.chat.use"]
261
- });
262
- });
263
-
264
- test("workspace action context contributor resolves context for workspace surfaces even when route visibility is public", async () => {
265
- const calls = [];
266
- const contributor = createWorkspaceActionContextContributor({
267
- workspaceService: {
268
- async resolveWorkspaceContextForUserBySlug(user, workspaceSlug, options) {
269
- calls.push({ user, workspaceSlug, options });
270
- return {
271
- workspace: {
272
- id: 77,
273
- slug: "acme"
274
- },
275
- membership: {
276
- roleSid: "member"
277
- },
278
- permissions: ["crud.breeds.list"]
279
- };
280
- }
281
- },
282
- workspaceSurfaceIds: ["admin", "app"]
283
- });
284
-
285
- const request = {
286
- user: {
287
- id: 42
288
- },
289
- routeOptions: {
290
- config: {
291
- surface: "admin",
292
- visibility: "public"
293
- }
294
- }
295
- };
296
-
297
- const contribution = await contributor.contribute({
298
- definition: {
299
- id: "crud.breeds.list",
300
- surfaces: ["admin"]
301
- },
302
- input: {
303
- workspaceSlug: "acme"
304
- },
305
- context: {
306
- requestMeta: {
307
- request
308
- }
309
- },
310
- request
311
- });
312
-
313
- assert.deepEqual(calls, [
314
- {
315
- user: request.user,
316
- workspaceSlug: "acme",
317
- options: {
318
- request
319
- }
320
- }
321
- ]);
322
- assert.deepEqual(contribution, {
323
- requestMeta: {
324
- resolvedWorkspaceContext: {
325
- workspace: {
326
- id: 77,
327
- slug: "acme"
328
- },
329
- membership: {
330
- roleSid: "member"
331
- },
332
- permissions: ["crud.breeds.list"]
333
- }
334
- },
335
- workspace: {
336
- id: 77,
337
- slug: "acme"
338
- },
339
- membership: {
340
- roleSid: "member"
341
- },
342
- permissions: ["crud.breeds.list"]
343
- });
344
- });
@@ -1,85 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import {
4
- materializeWorkspaceActionSurfacesFromAppConfig,
5
- resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig
6
- } from "../src/server/support/workspaceActionSurfaces.js";
7
-
8
- test("materializeWorkspaceActionSurfacesFromAppConfig resolves workspace surfaces from appConfig", () => {
9
- const actionDefinitions = [
10
- {
11
- id: "workspace.settings.read",
12
- surfacesFrom: "workspace"
13
- },
14
- {
15
- id: "auth.session.read",
16
- surfacesFrom: "enabled"
17
- }
18
- ];
19
-
20
- const materialized = materializeWorkspaceActionSurfacesFromAppConfig(actionDefinitions, {
21
- appConfig: {
22
- surfaceDefinitions: {
23
- app: { id: "app", enabled: true, requiresWorkspace: true },
24
- admin: { id: "admin", enabled: true, requiresWorkspace: true },
25
- ops: { id: "ops", enabled: true, requiresWorkspace: false }
26
- }
27
- }
28
- });
29
-
30
- assert.deepEqual(materialized, [
31
- {
32
- id: "workspace.settings.read",
33
- surfaces: ["app", "admin"]
34
- },
35
- {
36
- id: "auth.session.read",
37
- surfacesFrom: "enabled"
38
- }
39
- ]);
40
- });
41
-
42
- test("materializeWorkspaceActionSurfacesFromAppConfig drops workspace actions when no workspace surfaces are enabled", () => {
43
- const actionDefinitions = [
44
- {
45
- id: "workspace.settings.read",
46
- surfacesFrom: "workspace"
47
- }
48
- ];
49
-
50
- const materialized = materializeWorkspaceActionSurfacesFromAppConfig(actionDefinitions, {
51
- appConfig: {
52
- surfaceDefinitions: {
53
- app: { id: "app", enabled: true, requiresWorkspace: false },
54
- ops: { id: "ops", enabled: true, requiresWorkspace: false }
55
- }
56
- }
57
- });
58
-
59
- assert.deepEqual(materialized, []);
60
- });
61
-
62
- test("resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig picks a workspace surface when app default is non-workspace", () => {
63
- const surfaceId = resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig({
64
- surfaceDefaultId: "home",
65
- surfaceDefinitions: {
66
- home: { id: "home", enabled: true, requiresWorkspace: false },
67
- app: { id: "app", enabled: true, requiresWorkspace: true },
68
- admin: { id: "admin", enabled: true, requiresWorkspace: true }
69
- }
70
- });
71
-
72
- assert.equal(surfaceId, "app");
73
- });
74
-
75
- test("resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig falls back to app default when no workspace surfaces exist", () => {
76
- const surfaceId = resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig({
77
- surfaceDefaultId: "home",
78
- surfaceDefinitions: {
79
- home: { id: "home", enabled: true, requiresWorkspace: false },
80
- ops: { id: "ops", enabled: true, requiresWorkspace: false }
81
- }
82
- });
83
-
84
- assert.equal(surfaceId, "home");
85
- });
@@ -1,119 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createWorkspaceAuthPolicyContextResolver } from "../src/server/common/contributors/workspaceAuthPolicyContextResolver.js";
4
-
5
- test("workspace auth policy context resolver returns empty context when policy does not require workspace context", async () => {
6
- const resolver = createWorkspaceAuthPolicyContextResolver({
7
- workspaceService: {
8
- async resolveWorkspaceContextForUserBySlug() {
9
- throw new Error("must not be called");
10
- }
11
- }
12
- });
13
-
14
- const resolved = await resolver({
15
- request: {
16
- params: {
17
- workspaceSlug: "acme"
18
- }
19
- },
20
- actor: {
21
- id: 7
22
- },
23
- meta: {
24
- contextPolicy: "none",
25
- permission: ""
26
- }
27
- });
28
-
29
- assert.deepEqual(resolved, {});
30
- });
31
-
32
- test("workspace auth policy context resolver resolves workspace context from users workspace service", async () => {
33
- const calls = [];
34
- const resolver = createWorkspaceAuthPolicyContextResolver({
35
- workspaceService: {
36
- async resolveWorkspaceContextForUserBySlug(actor, workspaceSlug, options) {
37
- calls.push({
38
- actor,
39
- workspaceSlug,
40
- options
41
- });
42
- return {
43
- workspace: {
44
- id: 11,
45
- slug: workspaceSlug
46
- },
47
- membership: {
48
- roleSid: "owner"
49
- },
50
- permissions: ["projects.read"]
51
- };
52
- }
53
- }
54
- });
55
-
56
- const request = {
57
- params: {
58
- workspaceSlug: "ACME"
59
- }
60
- };
61
- const actor = {
62
- id: 7
63
- };
64
-
65
- const resolved = await resolver({
66
- request,
67
- actor,
68
- meta: {
69
- contextPolicy: "required"
70
- }
71
- });
72
-
73
- assert.deepEqual(calls, [
74
- {
75
- actor,
76
- workspaceSlug: "acme",
77
- options: {
78
- request
79
- }
80
- }
81
- ]);
82
- assert.deepEqual(resolved, {
83
- workspace: {
84
- id: 11,
85
- slug: "acme"
86
- },
87
- membership: {
88
- roleSid: "owner"
89
- },
90
- permissions: ["projects.read"]
91
- });
92
- });
93
-
94
- test("workspace auth policy context resolver skips workspace lookup when workspace slug is absent", async () => {
95
- let called = false;
96
- const resolver = createWorkspaceAuthPolicyContextResolver({
97
- workspaceService: {
98
- async resolveWorkspaceContextForUserBySlug() {
99
- called = true;
100
- return {};
101
- }
102
- }
103
- });
104
-
105
- const resolved = await resolver({
106
- request: {
107
- params: {}
108
- },
109
- actor: {
110
- id: 7
111
- },
112
- meta: {
113
- contextPolicy: "required"
114
- }
115
- });
116
-
117
- assert.equal(called, false);
118
- assert.deepEqual(resolved, {});
119
- });