@jskit-ai/users-core 0.1.33 → 0.1.36

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.
@@ -1,7 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import { UsersCoreServiceProvider } from "../src/server/UsersCoreServiceProvider.js";
4
- import { resolveTenancyProfile } from "../src/shared/tenancyProfile.js";
5
4
 
6
5
  function createReplyDouble() {
7
6
  return {
@@ -29,11 +28,7 @@ function findRoute(routes, { method, path }) {
29
28
 
30
29
  async function registerRoutes({
31
30
  authService = {},
32
- consoleService = null,
33
- workspaceEnabled = true,
34
- workspaceTenancyEnabled = true,
35
- workspaceInvitationsEnabled = true,
36
- workspaceSelfCreateEnabled = true
31
+ consoleService = null
37
32
  } = {}) {
38
33
  const registeredRoutes = [];
39
34
  const router = {
@@ -61,11 +56,7 @@ async function registerRoutes({
61
56
  }
62
57
  }
63
58
  ],
64
- ["actionExecutor", {}],
65
- ["users.workspace.enabled", workspaceEnabled],
66
- ["users.workspace.tenancy.enabled", workspaceTenancyEnabled],
67
- ["users.workspace.invitations.enabled", workspaceInvitationsEnabled],
68
- ["users.workspace.self-create.enabled", workspaceSelfCreateEnabled]
59
+ ["actionExecutor", {}]
69
60
  ]);
70
61
 
71
62
  if (consoleService) {
@@ -90,23 +81,6 @@ async function registerRoutes({
90
81
  return registeredRoutes;
91
82
  }
92
83
 
93
- async function registerRoutesForMode({
94
- tenancyMode = "none",
95
- tenancyPolicy = {}
96
- } = {}) {
97
- const tenancyProfile = resolveTenancyProfile({
98
- tenancyMode,
99
- tenancyPolicy
100
- });
101
- return registerRoutes({
102
- workspaceEnabled: tenancyProfile.workspace.enabled === true,
103
- workspaceTenancyEnabled: tenancyProfile.mode === "workspace",
104
- workspaceInvitationsEnabled:
105
- tenancyProfile.workspace.enabled === true && tenancyProfile.mode !== "none",
106
- workspaceSelfCreateEnabled: tenancyProfile.workspace.allowSelfCreate === true
107
- });
108
- }
109
-
110
84
  function createActionRequest({ input = {}, executeAction, file = null }) {
111
85
  return {
112
86
  input,
@@ -118,372 +92,15 @@ function createActionRequest({ input = {}, executeAction, file = null }) {
118
92
  };
119
93
  }
120
94
 
121
- test("workspace and settings routes attach only the shared transport normalizers they actually use", async () => {
95
+ test("users-core boot mounts account and console routes without workspace routes", async () => {
122
96
  const routes = await registerRoutes();
123
97
 
124
- const workspaceSettings = findRoute(routes, {
125
- method: "GET",
126
- path: "/api/w/:workspaceSlug/settings"
127
- });
128
- const workspacePatch = findRoute(routes, {
129
- method: "PATCH",
130
- path: "/api/w/:workspaceSlug"
131
- });
132
- const workspaceSettingsPatch = findRoute(routes, {
133
- method: "PATCH",
134
- path: "/api/w/:workspaceSlug/settings"
135
- });
136
- const workspaceMemberRole = findRoute(routes, {
137
- method: "PATCH",
138
- path: "/api/w/:workspaceSlug/members/:memberUserId/role"
139
- });
140
- const workspaceMemberDelete = findRoute(routes, {
141
- method: "DELETE",
142
- path: "/api/w/:workspaceSlug/members/:memberUserId"
143
- });
144
- const workspaceInviteDelete = findRoute(routes, {
145
- method: "DELETE",
146
- path: "/api/w/:workspaceSlug/invites/:inviteId"
147
- });
148
- const settingsProfilePatch = findRoute(routes, {
149
- method: "PATCH",
150
- path: "/api/settings/profile"
151
- });
152
- const settingsOAuthStart = findRoute(routes, {
153
- method: "GET",
154
- path: "/api/settings/security/oauth/:provider/start"
155
- });
156
- const consoleSettingsPatch = findRoute(routes, {
157
- method: "PATCH",
158
- path: "/api/console/settings"
159
- });
160
-
161
- assert.equal(typeof workspaceSettings?.paramsValidator?.normalize, "function");
162
- assert.equal(typeof workspacePatch?.bodyValidator?.normalize, "function");
163
- assert.equal(typeof workspaceSettingsPatch?.bodyValidator?.normalize, "function");
164
- assert.equal(typeof workspaceMemberRole?.paramsValidator?.normalize, "function");
165
- assert.equal(typeof workspaceMemberRole?.bodyValidator?.normalize, "function");
166
- assert.equal(typeof workspaceMemberDelete?.paramsValidator?.normalize, "function");
167
- assert.equal(typeof workspaceInviteDelete?.paramsValidator?.normalize, "function");
168
- assert.equal(typeof settingsProfilePatch?.bodyValidator?.normalize, "function");
169
- assert.equal(typeof settingsOAuthStart?.paramsValidator?.normalize, "function");
170
- assert.equal(typeof settingsOAuthStart?.queryValidator?.normalize, "function");
171
- assert.equal(typeof consoleSettingsPatch?.bodyValidator?.normalize, "function");
172
- });
173
-
174
- test("workspace core/settings routes mount one canonical workspace endpoint", async () => {
175
- const routes = await registerRoutes();
176
- const workspace = findRoute(routes, {
177
- method: "GET",
178
- path: "/api/w/:workspaceSlug"
179
- });
180
- const workspacePatch = findRoute(routes, {
181
- method: "PATCH",
182
- path: "/api/w/:workspaceSlug"
183
- });
184
- const workspaceSettings = findRoute(routes, {
185
- method: "GET",
186
- path: "/api/w/:workspaceSlug/settings"
187
- });
188
- const workspaceSettingsPatch = findRoute(routes, {
189
- method: "PATCH",
190
- path: "/api/w/:workspaceSlug/settings"
191
- });
192
- const adminWorkspaceSettings = findRoute(routes, {
193
- method: "GET",
194
- path: "/api/admin/w/:workspaceSlug/workspace/settings"
195
- });
196
- const consoleWorkspaceSettings = findRoute(routes, {
197
- method: "GET",
198
- path: "/api/console/w/:workspaceSlug/workspace/settings"
199
- });
200
-
201
- assert.ok(workspace);
202
- assert.equal(workspace?.visibility, "workspace");
203
- assert.equal(workspacePatch?.visibility, "workspace");
204
- assert.equal(workspace?.surface, "");
205
- assert.equal(workspacePatch?.surface, "");
206
- assert.ok(workspaceSettings);
207
- assert.equal(workspaceSettings?.visibility, "workspace");
208
- assert.equal(workspaceSettingsPatch?.visibility, "workspace");
209
- assert.equal(workspaceSettings?.surface, "");
210
- assert.equal(workspaceSettingsPatch?.surface, "");
211
- assert.equal(adminWorkspaceSettings, null);
212
- assert.equal(consoleWorkspaceSettings, null);
213
- });
214
-
215
- test("users-core boot skips workspace routes when workspace policy is disabled", async () => {
216
- const routes = await registerRoutes({
217
- workspaceEnabled: false,
218
- workspaceTenancyEnabled: false,
219
- workspaceInvitationsEnabled: false,
220
- workspaceSelfCreateEnabled: false
221
- });
222
-
98
+ assert.equal(findRoute(routes, { method: "GET", path: "/api/settings" })?.path, "/api/settings");
99
+ assert.equal(findRoute(routes, { method: "PATCH", path: "/api/settings/profile" })?.path, "/api/settings/profile");
100
+ assert.equal(findRoute(routes, { method: "GET", path: "/api/console/settings" })?.path, "/api/console/settings");
101
+ assert.equal(findRoute(routes, { method: "PATCH", path: "/api/console/settings" })?.path, "/api/console/settings");
223
102
  assert.equal(findRoute(routes, { method: "GET", path: "/api/workspaces" }), null);
224
- assert.equal(findRoute(routes, { method: "POST", path: "/api/workspaces" }), null);
225
- assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug" }), null);
226
- assert.equal(findRoute(routes, { method: "PATCH", path: "/api/w/:workspaceSlug" }), null);
227
103
  assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/settings" }), null);
228
- assert.equal(findRoute(routes, { method: "GET", path: "/api/settings" })?.path, "/api/settings");
229
- });
230
-
231
- test("users-core boot skips workspace create route when self-create policy is disabled", async () => {
232
- const routes = await registerRoutes({
233
- workspaceEnabled: true,
234
- workspaceTenancyEnabled: true,
235
- workspaceInvitationsEnabled: true,
236
- workspaceSelfCreateEnabled: false
237
- });
238
-
239
- assert.equal(findRoute(routes, { method: "POST", path: "/api/workspaces" }), null);
240
- assert.equal(findRoute(routes, { method: "GET", path: "/api/workspaces" })?.path, "/api/workspaces");
241
- });
242
-
243
- test("users-core route registration follows tenancy mode matrix", async () => {
244
- const noneRoutes = await registerRoutesForMode({
245
- tenancyMode: "none"
246
- });
247
- const personalRoutes = await registerRoutesForMode({
248
- tenancyMode: "personal"
249
- });
250
- const workspaceRoutes = await registerRoutesForMode({
251
- tenancyMode: "workspaces"
252
- });
253
- const workspaceSelfCreateRoutes = await registerRoutesForMode({
254
- tenancyMode: "workspaces",
255
- tenancyPolicy: {
256
- workspace: {
257
- allowSelfCreate: true
258
- }
259
- }
260
- });
261
-
262
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/workspaces" }), null);
263
- assert.equal(findRoute(noneRoutes, { method: "POST", path: "/api/workspaces" }), null);
264
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/w/:workspaceSlug" }), null);
265
- assert.equal(findRoute(noneRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug" }), null);
266
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/w/:workspaceSlug/settings" }), null);
267
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/workspace/invitations/pending" }), null);
268
-
269
- assert.equal(findRoute(personalRoutes, { method: "GET", path: "/api/workspaces" })?.path, "/api/workspaces");
270
- assert.equal(findRoute(personalRoutes, { method: "POST", path: "/api/workspaces" }), null);
271
- assert.equal(
272
- findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug" })?.path,
273
- "/api/w/:workspaceSlug"
274
- );
275
- assert.equal(
276
- findRoute(personalRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug" })?.path,
277
- "/api/w/:workspaceSlug"
278
- );
279
- assert.equal(
280
- findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug/settings" })?.path,
281
- "/api/w/:workspaceSlug/settings"
282
- );
283
- assert.equal(
284
- findRoute(personalRoutes, { method: "GET", path: "/api/workspace/invitations/pending" })?.path,
285
- "/api/workspace/invitations/pending"
286
- );
287
-
288
- assert.equal(findRoute(workspaceRoutes, { method: "GET", path: "/api/workspaces" })?.path, "/api/workspaces");
289
- assert.equal(findRoute(workspaceRoutes, { method: "POST", path: "/api/workspaces" }), null);
290
- assert.equal(
291
- findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug" })?.path,
292
- "/api/w/:workspaceSlug"
293
- );
294
- assert.equal(
295
- findRoute(workspaceRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug" })?.path,
296
- "/api/w/:workspaceSlug"
297
- );
298
- assert.equal(
299
- findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug/settings" })?.path,
300
- "/api/w/:workspaceSlug/settings"
301
- );
302
- assert.equal(
303
- findRoute(workspaceRoutes, { method: "GET", path: "/api/workspace/invitations/pending" })?.path,
304
- "/api/workspace/invitations/pending"
305
- );
306
-
307
- assert.equal(
308
- findRoute(workspaceSelfCreateRoutes, { method: "POST", path: "/api/workspaces" })?.path,
309
- "/api/workspaces"
310
- );
311
- });
312
-
313
- test("users-core boot skips invitation redeem/list routes when workspace invitations are disabled", async () => {
314
- const routes = await registerRoutes({
315
- workspaceEnabled: true,
316
- workspaceTenancyEnabled: true,
317
- workspaceInvitationsEnabled: false,
318
- workspaceSelfCreateEnabled: false
319
- });
320
-
321
- assert.equal(findRoute(routes, { method: "GET", path: "/api/workspace/invitations/pending" }), null);
322
- assert.equal(findRoute(routes, { method: "POST", path: "/api/workspace/invitations/redeem" }), null);
323
- assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/invites" }), null);
324
- assert.equal(findRoute(routes, { method: "POST", path: "/api/w/:workspaceSlug/invites" }), null);
325
- assert.equal(findRoute(routes, { method: "DELETE", path: "/api/w/:workspaceSlug/invites/:inviteId" }), null);
326
- });
327
-
328
- test("workspace invite and member handlers build action input from request.input", async () => {
329
- const routes = await registerRoutes();
330
- const workspaceCreate = findRoute(routes, {
331
- method: "POST",
332
- path: "/api/workspaces"
333
- });
334
- const workspaceInviteRedeem = findRoute(routes, {
335
- method: "POST",
336
- path: "/api/workspace/invitations/redeem"
337
- });
338
- const workspaceMemberRolePatch = findRoute(routes, {
339
- method: "PATCH",
340
- path: "/api/w/:workspaceSlug/members/:memberUserId/role"
341
- });
342
- const workspaceMemberDelete = findRoute(routes, {
343
- method: "DELETE",
344
- path: "/api/w/:workspaceSlug/members/:memberUserId"
345
- });
346
- const workspaceInviteCreate = findRoute(routes, {
347
- method: "POST",
348
- path: "/api/w/:workspaceSlug/invites"
349
- });
350
- const workspaceInviteDelete = findRoute(routes, {
351
- method: "DELETE",
352
- path: "/api/w/:workspaceSlug/invites/:inviteId"
353
- });
354
- const calls = [];
355
- const executeAction = async (payload) => {
356
- calls.push(payload);
357
- return {};
358
- };
359
-
360
- await workspaceCreate.handler(
361
- createActionRequest({
362
- input: {
363
- body: { name: "Operations", slug: "operations" }
364
- },
365
- executeAction
366
- }),
367
- createReplyDouble()
368
- );
369
- await workspaceInviteRedeem.handler(
370
- createActionRequest({
371
- input: {
372
- body: { token: "token-1", decision: "accept" }
373
- },
374
- executeAction
375
- }),
376
- createReplyDouble()
377
- );
378
- await workspaceMemberRolePatch.handler(
379
- createActionRequest({
380
- input: {
381
- params: { workspaceSlug: "acme", memberUserId: "12" },
382
- body: { roleSid: "admin" }
383
- },
384
- executeAction
385
- }),
386
- createReplyDouble()
387
- );
388
- await workspaceInviteCreate.handler(
389
- createActionRequest({
390
- input: {
391
- params: { workspaceSlug: "acme" },
392
- body: { email: "user@example.com", roleSid: "member" }
393
- },
394
- executeAction
395
- }),
396
- createReplyDouble()
397
- );
398
- await workspaceMemberDelete.handler(
399
- createActionRequest({
400
- input: {
401
- params: { workspaceSlug: "acme", memberUserId: "44" }
402
- },
403
- executeAction
404
- }),
405
- createReplyDouble()
406
- );
407
- await workspaceInviteDelete.handler(
408
- createActionRequest({
409
- input: {
410
- params: { workspaceSlug: "acme", inviteId: "55" }
411
- },
412
- executeAction
413
- }),
414
- createReplyDouble()
415
- );
416
-
417
- assert.deepEqual(calls[0], {
418
- actionId: "workspace.workspaces.create",
419
- input: { name: "Operations", slug: "operations" }
420
- });
421
- assert.deepEqual(calls[1].input, { payload: { token: "token-1", decision: "accept" } });
422
- assert.deepEqual(calls[2].input, { workspaceSlug: "acme", memberUserId: "12", roleSid: "admin" });
423
- assert.deepEqual(calls[3].input, { workspaceSlug: "acme", email: "user@example.com", roleSid: "member" });
424
- assert.deepEqual(calls[4].input, { workspaceSlug: "acme", memberUserId: "44" });
425
- assert.deepEqual(calls[5].input, { workspaceSlug: "acme", inviteId: "55" });
426
- });
427
-
428
- test("workspace settings route handlers build action input from request.input", async () => {
429
- const routes = await registerRoutes();
430
- const workspaceSettingsPatch = findRoute(routes, {
431
- method: "PATCH",
432
- path: "/api/w/:workspaceSlug/settings"
433
- });
434
- const calls = [];
435
- const executeAction = async (payload) => {
436
- calls.push(payload);
437
- return {};
438
- };
439
-
440
- await workspaceSettingsPatch.handler(
441
- createActionRequest({
442
- input: {
443
- params: { workspaceSlug: "acme" },
444
- body: { lightPrimaryColor: "#0F6B54" }
445
- },
446
- executeAction
447
- }),
448
- createReplyDouble()
449
- );
450
-
451
- assert.deepEqual(calls[0], {
452
- actionId: "workspace.settings.update",
453
- input: { workspaceSlug: "acme", patch: { lightPrimaryColor: "#0F6B54" } }
454
- });
455
- });
456
-
457
- test("workspace route handlers build action input from request.input", async () => {
458
- const routes = await registerRoutes();
459
- const workspacePatch = findRoute(routes, {
460
- method: "PATCH",
461
- path: "/api/w/:workspaceSlug"
462
- });
463
- const calls = [];
464
- const executeAction = async (payload) => {
465
- calls.push(payload);
466
- return {};
467
- };
468
-
469
- await workspacePatch.handler(
470
- createActionRequest({
471
- input: {
472
- params: { workspaceSlug: "acme" },
473
- body: { name: "Acme", avatarUrl: "https://example.com/acme.png" }
474
- },
475
- executeAction
476
- }),
477
- createReplyDouble()
478
- );
479
-
480
- assert.deepEqual(calls[0], {
481
- actionId: "workspace.workspaces.update",
482
- input: {
483
- workspaceSlug: "acme",
484
- patch: { name: "Acme", avatarUrl: "https://example.com/acme.png" }
485
- }
486
- });
487
104
  });
488
105
 
489
106
  test("account route handlers build action input from request.input", async () => {