@jskit-ai/users-core 0.1.25 → 0.1.27

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 (39) hide show
  1. package/package.descriptor.mjs +15 -22
  2. package/package.json +5 -6
  3. package/src/server/UsersCoreServiceProvider.js +2 -6
  4. package/src/server/accountNotifications/bootAccountNotificationsRoutes.js +1 -2
  5. package/src/server/accountNotifications/registerAccountNotifications.js +2 -4
  6. package/src/server/accountPreferences/bootAccountPreferencesRoutes.js +1 -2
  7. package/src/server/accountPreferences/registerAccountPreferences.js +2 -4
  8. package/src/server/accountProfile/bootAccountProfileRoutes.js +2 -4
  9. package/src/server/accountProfile/registerAccountProfile.js +8 -14
  10. package/src/server/accountProfile/registerAvatarMultipartSupport.js +5 -8
  11. package/src/server/accountSecurity/bootAccountSecurityRoutes.js +1 -2
  12. package/src/server/accountSecurity/registerAccountSecurity.js +2 -4
  13. package/src/server/common/README.md +0 -1
  14. package/src/server/common/registerCommonRepositories.js +6 -7
  15. package/src/server/common/support/realtimeServiceEvents.js +3 -7
  16. package/src/server/consoleSettings/bootConsoleSettingsRoutes.js +1 -2
  17. package/src/server/consoleSettings/registerConsoleSettings.js +1 -2
  18. package/src/server/registerWorkspaceBootstrap.js +4 -10
  19. package/src/server/registerWorkspaceCore.js +14 -25
  20. package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +3 -7
  21. package/src/server/workspaceMembers/bootWorkspaceMembers.js +3 -5
  22. package/src/server/workspaceMembers/registerWorkspaceMembers.js +7 -13
  23. package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +1 -2
  24. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +7 -17
  25. package/src/server/workspaceSettings/bootWorkspaceSettings.js +1 -2
  26. package/src/server/workspaceSettings/registerWorkspaceSettings.js +3 -8
  27. package/src/shared/index.js +1 -24
  28. package/src/shared/resources/consoleSettingsFields.js +1 -2
  29. package/src/shared/resources/userSettingsFields.js +1 -2
  30. package/src/shared/resources/workspaceSettingsFields.js +1 -2
  31. package/src/shared/support/usersApiPaths.js +1 -1
  32. package/test/registerAvatarMultipartSupport.test.js +2 -3
  33. package/test/registerServiceRealtimeEvents.test.js +29 -38
  34. package/test/registerWorkspaceSettings.test.js +2 -6
  35. package/test/usersApiPaths.test.js +2 -2
  36. package/test/usersRouteRequestInputValidator.test.js +38 -39
  37. package/test/workspaceSettingsRepository.test.js +6 -4
  38. package/src/server/common/diTokens.js +0 -21
  39. package/src/shared/events/usersEvents.js +0 -19
@@ -18,7 +18,7 @@ test("resolveApiBasePath resolves workspace and non-workspace API base paths", (
18
18
  surfaceRequiresWorkspace: true,
19
19
  relativePath: "/customers"
20
20
  }),
21
- "/api/w/:workspaceSlug/workspace/customers"
21
+ "/api/w/:workspaceSlug/customers"
22
22
  );
23
23
 
24
24
  assert.equal(
@@ -36,7 +36,7 @@ test("resolveApiBasePath preserves query strings and hash fragments", () => {
36
36
  surfaceRequiresWorkspace: true,
37
37
  relativePath: "/customers?search=buddy#top"
38
38
  }),
39
- "/api/w/:workspaceSlug/workspace/customers?search=buddy#top"
39
+ "/api/w/:workspaceSlug/customers?search=buddy#top"
40
40
  );
41
41
 
42
42
  assert.equal(
@@ -1,6 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
- import { KERNEL_TOKENS } from "@jskit-ai/kernel/shared/support/tokens";
4
3
  import { UsersCoreServiceProvider } from "../src/server/UsersCoreServiceProvider.js";
5
4
  import { resolveTenancyProfile } from "../src/shared/tenancyProfile.js";
6
5
 
@@ -49,7 +48,7 @@ async function registerRoutes({
49
48
  };
50
49
 
51
50
  const bindings = new Map([
52
- [KERNEL_TOKENS.HttpRouter, router],
51
+ ["jskit.http.router", router],
53
52
  ["authService", authService],
54
53
  [
55
54
  "users.accountProfile.service",
@@ -124,27 +123,27 @@ test("workspace and settings routes attach only the shared transport normalizers
124
123
 
125
124
  const workspaceSettings = findRoute(routes, {
126
125
  method: "GET",
127
- path: "/api/w/:workspaceSlug/workspace/settings"
126
+ path: "/api/w/:workspaceSlug/settings"
128
127
  });
129
128
  const workspacePatch = findRoute(routes, {
130
129
  method: "PATCH",
131
- path: "/api/w/:workspaceSlug/workspace"
130
+ path: "/api/w/:workspaceSlug"
132
131
  });
133
132
  const workspaceSettingsPatch = findRoute(routes, {
134
133
  method: "PATCH",
135
- path: "/api/w/:workspaceSlug/workspace/settings"
134
+ path: "/api/w/:workspaceSlug/settings"
136
135
  });
137
136
  const workspaceMemberRole = findRoute(routes, {
138
137
  method: "PATCH",
139
- path: "/api/w/:workspaceSlug/workspace/members/:memberUserId/role"
138
+ path: "/api/w/:workspaceSlug/members/:memberUserId/role"
140
139
  });
141
140
  const workspaceMemberDelete = findRoute(routes, {
142
141
  method: "DELETE",
143
- path: "/api/w/:workspaceSlug/workspace/members/:memberUserId"
142
+ path: "/api/w/:workspaceSlug/members/:memberUserId"
144
143
  });
145
144
  const workspaceInviteDelete = findRoute(routes, {
146
145
  method: "DELETE",
147
- path: "/api/w/:workspaceSlug/workspace/invites/:inviteId"
146
+ path: "/api/w/:workspaceSlug/invites/:inviteId"
148
147
  });
149
148
  const settingsProfilePatch = findRoute(routes, {
150
149
  method: "PATCH",
@@ -176,19 +175,19 @@ test("workspace core/settings routes mount one canonical workspace endpoint", as
176
175
  const routes = await registerRoutes();
177
176
  const workspace = findRoute(routes, {
178
177
  method: "GET",
179
- path: "/api/w/:workspaceSlug/workspace"
178
+ path: "/api/w/:workspaceSlug"
180
179
  });
181
180
  const workspacePatch = findRoute(routes, {
182
181
  method: "PATCH",
183
- path: "/api/w/:workspaceSlug/workspace"
182
+ path: "/api/w/:workspaceSlug"
184
183
  });
185
184
  const workspaceSettings = findRoute(routes, {
186
185
  method: "GET",
187
- path: "/api/w/:workspaceSlug/workspace/settings"
186
+ path: "/api/w/:workspaceSlug/settings"
188
187
  });
189
188
  const workspaceSettingsPatch = findRoute(routes, {
190
189
  method: "PATCH",
191
- path: "/api/w/:workspaceSlug/workspace/settings"
190
+ path: "/api/w/:workspaceSlug/settings"
192
191
  });
193
192
  const adminWorkspaceSettings = findRoute(routes, {
194
193
  method: "GET",
@@ -223,9 +222,9 @@ test("users-core boot skips workspace routes when workspace policy is disabled",
223
222
 
224
223
  assert.equal(findRoute(routes, { method: "GET", path: "/api/workspaces" }), null);
225
224
  assert.equal(findRoute(routes, { method: "POST", path: "/api/workspaces" }), null);
226
- assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/workspace" }), null);
227
- assert.equal(findRoute(routes, { method: "PATCH", path: "/api/w/:workspaceSlug/workspace" }), null);
228
- assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/workspace/settings" }), 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
+ assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/settings" }), null);
229
228
  assert.equal(findRoute(routes, { method: "GET", path: "/api/settings" })?.path, "/api/settings");
230
229
  });
231
230
 
@@ -262,24 +261,24 @@ test("users-core route registration follows tenancy mode matrix", async () => {
262
261
 
263
262
  assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/workspaces" }), null);
264
263
  assert.equal(findRoute(noneRoutes, { method: "POST", path: "/api/workspaces" }), null);
265
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace" }), null);
266
- assert.equal(findRoute(noneRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug/workspace" }), null);
267
- assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace/settings" }), 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);
268
267
  assert.equal(findRoute(noneRoutes, { method: "GET", path: "/api/workspace/invitations/pending" }), null);
269
268
 
270
269
  assert.equal(findRoute(personalRoutes, { method: "GET", path: "/api/workspaces" })?.path, "/api/workspaces");
271
270
  assert.equal(findRoute(personalRoutes, { method: "POST", path: "/api/workspaces" }), null);
272
271
  assert.equal(
273
- findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace" })?.path,
274
- "/api/w/:workspaceSlug/workspace"
272
+ findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug" })?.path,
273
+ "/api/w/:workspaceSlug"
275
274
  );
276
275
  assert.equal(
277
- findRoute(personalRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug/workspace" })?.path,
278
- "/api/w/:workspaceSlug/workspace"
276
+ findRoute(personalRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug" })?.path,
277
+ "/api/w/:workspaceSlug"
279
278
  );
280
279
  assert.equal(
281
- findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace/settings" })?.path,
282
- "/api/w/:workspaceSlug/workspace/settings"
280
+ findRoute(personalRoutes, { method: "GET", path: "/api/w/:workspaceSlug/settings" })?.path,
281
+ "/api/w/:workspaceSlug/settings"
283
282
  );
284
283
  assert.equal(
285
284
  findRoute(personalRoutes, { method: "GET", path: "/api/workspace/invitations/pending" })?.path,
@@ -289,16 +288,16 @@ test("users-core route registration follows tenancy mode matrix", async () => {
289
288
  assert.equal(findRoute(workspaceRoutes, { method: "GET", path: "/api/workspaces" })?.path, "/api/workspaces");
290
289
  assert.equal(findRoute(workspaceRoutes, { method: "POST", path: "/api/workspaces" }), null);
291
290
  assert.equal(
292
- findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace" })?.path,
293
- "/api/w/:workspaceSlug/workspace"
291
+ findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug" })?.path,
292
+ "/api/w/:workspaceSlug"
294
293
  );
295
294
  assert.equal(
296
- findRoute(workspaceRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug/workspace" })?.path,
297
- "/api/w/:workspaceSlug/workspace"
295
+ findRoute(workspaceRoutes, { method: "PATCH", path: "/api/w/:workspaceSlug" })?.path,
296
+ "/api/w/:workspaceSlug"
298
297
  );
299
298
  assert.equal(
300
- findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug/workspace/settings" })?.path,
301
- "/api/w/:workspaceSlug/workspace/settings"
299
+ findRoute(workspaceRoutes, { method: "GET", path: "/api/w/:workspaceSlug/settings" })?.path,
300
+ "/api/w/:workspaceSlug/settings"
302
301
  );
303
302
  assert.equal(
304
303
  findRoute(workspaceRoutes, { method: "GET", path: "/api/workspace/invitations/pending" })?.path,
@@ -321,9 +320,9 @@ test("users-core boot skips invitation redeem/list routes when workspace invitat
321
320
 
322
321
  assert.equal(findRoute(routes, { method: "GET", path: "/api/workspace/invitations/pending" }), null);
323
322
  assert.equal(findRoute(routes, { method: "POST", path: "/api/workspace/invitations/redeem" }), null);
324
- assert.equal(findRoute(routes, { method: "GET", path: "/api/w/:workspaceSlug/workspace/invites" }), null);
325
- assert.equal(findRoute(routes, { method: "POST", path: "/api/w/:workspaceSlug/workspace/invites" }), null);
326
- assert.equal(findRoute(routes, { method: "DELETE", path: "/api/w/:workspaceSlug/workspace/invites/:inviteId" }), 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);
327
326
  });
328
327
 
329
328
  test("workspace invite and member handlers build action input from request.input", async () => {
@@ -338,19 +337,19 @@ test("workspace invite and member handlers build action input from request.input
338
337
  });
339
338
  const workspaceMemberRolePatch = findRoute(routes, {
340
339
  method: "PATCH",
341
- path: "/api/w/:workspaceSlug/workspace/members/:memberUserId/role"
340
+ path: "/api/w/:workspaceSlug/members/:memberUserId/role"
342
341
  });
343
342
  const workspaceMemberDelete = findRoute(routes, {
344
343
  method: "DELETE",
345
- path: "/api/w/:workspaceSlug/workspace/members/:memberUserId"
344
+ path: "/api/w/:workspaceSlug/members/:memberUserId"
346
345
  });
347
346
  const workspaceInviteCreate = findRoute(routes, {
348
347
  method: "POST",
349
- path: "/api/w/:workspaceSlug/workspace/invites"
348
+ path: "/api/w/:workspaceSlug/invites"
350
349
  });
351
350
  const workspaceInviteDelete = findRoute(routes, {
352
351
  method: "DELETE",
353
- path: "/api/w/:workspaceSlug/workspace/invites/:inviteId"
352
+ path: "/api/w/:workspaceSlug/invites/:inviteId"
354
353
  });
355
354
  const calls = [];
356
355
  const executeAction = async (payload) => {
@@ -430,7 +429,7 @@ test("workspace settings route handlers build action input from request.input",
430
429
  const routes = await registerRoutes();
431
430
  const workspaceSettingsPatch = findRoute(routes, {
432
431
  method: "PATCH",
433
- path: "/api/w/:workspaceSlug/workspace/settings"
432
+ path: "/api/w/:workspaceSlug/settings"
434
433
  });
435
434
  const calls = [];
436
435
  const executeAction = async (payload) => {
@@ -459,7 +458,7 @@ test("workspace route handlers build action input from request.input", async ()
459
458
  const routes = await registerRoutes();
460
459
  const workspacePatch = findRoute(routes, {
461
460
  method: "PATCH",
462
- path: "/api/w/:workspaceSlug/workspace"
461
+ path: "/api/w/:workspaceSlug"
463
462
  });
464
463
  const calls = [];
465
464
  const executeAction = async (payload) => {
@@ -1,6 +1,7 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import "../test-support/registerDefaultSettingsFields.js";
4
+ import { toIsoString } from "@jskit-ai/database-runtime/shared";
4
5
  import { resolveWorkspaceThemePalettes } from "../src/shared/settings.js";
5
6
  import { createRepository } from "../src/server/workspaceSettings/workspaceSettingsRepository.js";
6
7
 
@@ -9,6 +10,7 @@ function createDefaultWorkspaceSettings() {
9
10
  }
10
11
 
11
12
  const DEFAULT_WORKSPACE_THEME = resolveWorkspaceThemePalettes({});
13
+ const STUB_CREATED_AT = "2026-03-09 00:26:35.710";
12
14
 
13
15
  function createKnexStub(rowOverrides = {}) {
14
16
  const state = {
@@ -25,8 +27,8 @@ function createKnexStub(rowOverrides = {}) {
25
27
  dark_surface_color: DEFAULT_WORKSPACE_THEME.dark.surfaceColor,
26
28
  dark_surface_variant_color: DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor,
27
29
  invites_enabled: 1,
28
- created_at: "2026-03-09 00:26:35.710",
29
- updated_at: "2026-03-09 00:26:35.710",
30
+ created_at: STUB_CREATED_AT,
31
+ updated_at: STUB_CREATED_AT,
30
32
  ...rowOverrides
31
33
  }
32
34
  };
@@ -121,8 +123,8 @@ test("workspaceSettingsRepository.findByWorkspaceId maps the stored row", async
121
123
  darkSurfaceColor: DEFAULT_WORKSPACE_THEME.dark.surfaceColor,
122
124
  darkSurfaceVariantColor: DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor,
123
125
  invitesEnabled: true,
124
- createdAt: "2026-03-08T16:26:35.710Z",
125
- updatedAt: "2026-03-08T16:26:35.710Z"
126
+ createdAt: toIsoString(STUB_CREATED_AT),
127
+ updatedAt: toIsoString(STUB_CREATED_AT)
126
128
  });
127
129
  });
128
130
 
@@ -1,21 +0,0 @@
1
- const USERS_WORKSPACE_PENDING_INVITATIONS_SERVICE_TOKEN = "users.workspace.pending-invitations.service";
2
- const USERS_WORKSPACE_ENABLED_TOKEN = "users.workspace.enabled";
3
- const USERS_WORKSPACE_TENANCY_ENABLED_TOKEN = "users.workspace.tenancy.enabled";
4
- const USERS_WORKSPACE_INVITATIONS_ENABLED_TOKEN = "users.workspace.invitations.enabled";
5
- const USERS_WORKSPACE_SELF_CREATE_ENABLED_TOKEN = "users.workspace.self-create.enabled";
6
- const USERS_TENANCY_PROFILE_TOKEN = "users.tenancy.profile";
7
- const USERS_AVATAR_STORAGE_SERVICE_TOKEN = "users.avatar.storage.service";
8
- const USERS_AVATAR_SERVICE_TOKEN = "users.avatar.service";
9
- const USERS_PROFILE_SYNC_SERVICE_TOKEN = "users.profile.sync.service";
10
-
11
- export {
12
- USERS_WORKSPACE_PENDING_INVITATIONS_SERVICE_TOKEN,
13
- USERS_WORKSPACE_ENABLED_TOKEN,
14
- USERS_WORKSPACE_TENANCY_ENABLED_TOKEN,
15
- USERS_WORKSPACE_INVITATIONS_ENABLED_TOKEN,
16
- USERS_WORKSPACE_SELF_CREATE_ENABLED_TOKEN,
17
- USERS_TENANCY_PROFILE_TOKEN,
18
- USERS_AVATAR_STORAGE_SERVICE_TOKEN,
19
- USERS_AVATAR_SERVICE_TOKEN,
20
- USERS_PROFILE_SYNC_SERVICE_TOKEN
21
- };
@@ -1,19 +0,0 @@
1
- const ACCOUNT_SETTINGS_CHANGED_EVENT = "account.settings.changed";
2
- const CONSOLE_SETTINGS_CHANGED_EVENT = "console.settings.changed";
3
- const USERS_BOOTSTRAP_CHANGED_EVENT = "users.bootstrap.changed";
4
- const WORKSPACE_SETTINGS_CHANGED_EVENT = "workspace.settings.changed";
5
- const WORKSPACE_MEMBERS_CHANGED_EVENT = "workspace.members.changed";
6
- const WORKSPACE_INVITES_CHANGED_EVENT = "workspace.invites.changed";
7
- const WORKSPACES_CHANGED_EVENT = "workspaces.changed";
8
- const WORKSPACE_PENDING_INVITATIONS_CHANGED_EVENT = "workspace.invitations.pending.changed";
9
-
10
- export {
11
- ACCOUNT_SETTINGS_CHANGED_EVENT,
12
- CONSOLE_SETTINGS_CHANGED_EVENT,
13
- USERS_BOOTSTRAP_CHANGED_EVENT,
14
- WORKSPACE_SETTINGS_CHANGED_EVENT,
15
- WORKSPACE_MEMBERS_CHANGED_EVENT,
16
- WORKSPACE_INVITES_CHANGED_EVENT,
17
- WORKSPACES_CHANGED_EVENT,
18
- WORKSPACE_PENDING_INVITATIONS_CHANGED_EVENT
19
- };