@jskit-ai/users-core 0.1.42 → 0.1.44

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 (55) hide show
  1. package/package.descriptor.mjs +6 -6
  2. package/package.json +6 -6
  3. package/src/server/accountProfile/avatarStorageService.js +3 -3
  4. package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +12 -13
  5. package/src/server/common/formatters/workspaceFormatter.js +3 -2
  6. package/src/server/common/repositories/repositoryUtils.js +12 -3
  7. package/src/server/common/repositories/userSettingsRepository.js +35 -11
  8. package/src/server/common/repositories/usersRepository.js +44 -27
  9. package/src/server/common/repositories/workspaceInvitesRepository.js +49 -13
  10. package/src/server/common/repositories/workspaceMembershipsRepository.js +55 -22
  11. package/src/server/common/repositories/workspacesRepository.js +41 -11
  12. package/src/server/common/services/accountContextService.js +3 -2
  13. package/src/server/common/services/authProfileSyncService.js +7 -5
  14. package/src/server/common/services/workspaceContextService.js +4 -1
  15. package/src/server/common/support/realtimeServiceEvents.js +4 -3
  16. package/src/server/common/validators/authenticatedUserValidator.js +5 -4
  17. package/src/server/consoleSettings/consoleService.js +3 -3
  18. package/src/server/consoleSettings/consoleSettingsRepository.js +10 -6
  19. package/src/server/usersBootstrapContributor.js +7 -3
  20. package/src/server/workspaceBootstrapContributor.js +5 -1
  21. package/src/server/workspaceMembers/registerWorkspaceMembers.js +6 -4
  22. package/src/server/workspaceMembers/workspaceMembersService.js +23 -11
  23. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +5 -4
  24. package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +3 -2
  25. package/src/server/workspaceSettings/workspaceSettingsRepository.js +29 -10
  26. package/src/server/workspaceSettings/workspaceSettingsService.js +3 -2
  27. package/src/shared/resources/workspaceMembersResource.js +25 -21
  28. package/src/shared/resources/workspacePendingInvitationsResource.js +7 -12
  29. package/src/shared/resources/workspaceResource.js +13 -9
  30. package/src/shared/resources/workspaceSettingsResource.js +7 -5
  31. package/templates/migrations/users_core_console_owner.cjs +1 -1
  32. package/templates/migrations/users_core_generic_initial.cjs +4 -4
  33. package/templates/migrations/users_core_profile_username.cjs +1 -1
  34. package/test/authProfileSyncService.test.js +7 -4
  35. package/test/avatarStorageService.test.js +3 -3
  36. package/test/consoleService.test.js +9 -9
  37. package/test/registerServiceRealtimeEvents.test.js +9 -9
  38. package/test/repositoryContracts.test.js +40 -0
  39. package/test/usersBootstrapContributor.test.js +4 -4
  40. package/test/workspaceBootstrapContributor.test.js +1 -1
  41. package/test/workspaceInvitesRepository.test.js +3 -3
  42. package/test/workspaceMembersService.test.js +34 -34
  43. package/test/workspacePendingInvitationsResource.test.js +4 -4
  44. package/test/workspacePendingInvitationsService.test.js +11 -11
  45. package/test/workspaceRouteVisibilityResolver.test.js +6 -6
  46. package/test/workspaceService.test.js +33 -33
  47. package/test/workspaceSettingsRepository.test.js +7 -6
  48. package/test/workspaceSettingsResource.test.js +2 -2
  49. package/src/server/common/README.md +0 -20
  50. package/src/server/common/contributors/README.md +0 -11
  51. package/src/server/common/formatters/README.md +0 -11
  52. package/src/server/common/repositories/README.md +0 -24
  53. package/src/server/common/routes/README.md +0 -11
  54. package/src/server/common/services/README.md +0 -12
  55. package/src/server/common/validators/README.md +0 -11
@@ -28,10 +28,10 @@ function createWorkspaceServiceFixture({
28
28
  userWorkspaceRows = null,
29
29
  membershipResolver = null,
30
30
  personalWorkspace = {
31
- id: 1,
31
+ id: "1",
32
32
  slug: "tonymobily3",
33
33
  name: "TonyMobily3",
34
- ownerUserId: 7,
34
+ ownerUserId: "7",
35
35
  isPersonal: true,
36
36
  avatarUrl: ""
37
37
  }
@@ -93,7 +93,7 @@ function createWorkspaceServiceFixture({
93
93
  }
94
94
  return [
95
95
  {
96
- id: 1,
96
+ id: "1",
97
97
  slug: "tonymobily3",
98
98
  name: "TonyMobily3",
99
99
  avatarUrl: "",
@@ -101,7 +101,7 @@ function createWorkspaceServiceFixture({
101
101
  membershipStatus: "active"
102
102
  },
103
103
  {
104
- id: 2,
104
+ id: "2",
105
105
  slug: "pending-workspace",
106
106
  name: "Pending Workspace",
107
107
  avatarUrl: "",
@@ -113,12 +113,12 @@ function createWorkspaceServiceFixture({
113
113
  async insert(payload) {
114
114
  calls.insert += 1;
115
115
  insertedPayloads.push(payload);
116
- const workspaceId = nextWorkspaceId++;
116
+ const workspaceId = String(nextWorkspaceId++);
117
117
  const inserted = {
118
118
  id: workspaceId,
119
119
  slug: String(payload.slug || ""),
120
120
  name: String(payload.name || ""),
121
- ownerUserId: Number(payload.ownerUserId),
121
+ ownerUserId: String(payload.ownerUserId || ""),
122
122
  isPersonal: payload.isPersonal === true,
123
123
  avatarUrl: String(payload.avatarUrl || "")
124
124
  };
@@ -127,9 +127,9 @@ function createWorkspaceServiceFixture({
127
127
  },
128
128
  async updateById(workspaceId, patch) {
129
129
  calls.updateById += 1;
130
- const targetId = Number(workspaceId);
130
+ const targetId = String(workspaceId || "").trim();
131
131
  for (const [slug, workspace] of workspaceBySlug.entries()) {
132
- if (Number(workspace.id) !== targetId) {
132
+ if (String(workspace.id || "").trim() !== targetId) {
133
133
  continue;
134
134
  }
135
135
  const updated = {
@@ -185,7 +185,7 @@ test("workspaceService no longer exposes bootstrap payload assembly", () => {
185
185
  test("workspaceService.listWorkspacesForUser returns only accessible workspaces", async () => {
186
186
  const { service, calls } = createWorkspaceServiceFixture();
187
187
  const workspaces = await service.listWorkspacesForUser({
188
- id: 7,
188
+ id: "7",
189
189
  email: "chiaramobily@gmail.com",
190
190
  displayName: "Chiara"
191
191
  });
@@ -204,7 +204,7 @@ test("workspaceService.listWorkspacesForUser no longer provisions personal works
204
204
  });
205
205
 
206
206
  await service.listWorkspacesForUser({
207
- id: 7,
207
+ id: "7",
208
208
  email: "chiaramobily@gmail.com",
209
209
  displayName: "Chiara"
210
210
  });
@@ -218,7 +218,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
218
218
  tenancyMode: "personal",
219
219
  userWorkspaceRows: [
220
220
  {
221
- id: 1,
221
+ id: "1",
222
222
  slug: "chiaramobily",
223
223
  name: "Chiara Personal",
224
224
  avatarUrl: "",
@@ -226,7 +226,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
226
226
  membershipStatus: "active"
227
227
  },
228
228
  {
229
- id: 2,
229
+ id: "2",
230
230
  slug: "tonymobily",
231
231
  name: "Tony Workspace",
232
232
  avatarUrl: "",
@@ -234,7 +234,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
234
234
  membershipStatus: "active"
235
235
  },
236
236
  {
237
- id: 3,
237
+ id: "3",
238
238
  slug: "pending-workspace",
239
239
  name: "Pending Workspace",
240
240
  avatarUrl: "",
@@ -245,7 +245,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
245
245
  });
246
246
 
247
247
  const workspaces = await service.listWorkspacesForUser({
248
- id: 7,
248
+ id: "7",
249
249
  email: "chiaramobily@gmail.com",
250
250
  displayName: "Chiara"
251
251
  });
@@ -265,7 +265,7 @@ test("workspaceService.provisionWorkspaceForNewUser provisions personal workspac
265
265
  });
266
266
 
267
267
  const workspace = await service.provisionWorkspaceForNewUser({
268
- id: 7,
268
+ id: "7",
269
269
  email: "chiaramobily@gmail.com",
270
270
  displayName: "Chiara"
271
271
  });
@@ -283,7 +283,7 @@ test("workspaceService.provisionWorkspaceForNewUser is a no-op outside personal
283
283
  });
284
284
 
285
285
  const result = await service.provisionWorkspaceForNewUser({
286
- id: 7,
286
+ id: "7",
287
287
  email: "chiaramobily@gmail.com",
288
288
  displayName: "Chiara"
289
289
  });
@@ -304,7 +304,7 @@ test("workspaceService.createWorkspaceForAuthenticatedUser creates non-personal
304
304
 
305
305
  const workspace = await service.createWorkspaceForAuthenticatedUser(
306
306
  {
307
- id: 7,
307
+ id: "7",
308
308
  email: "chiaramobily@gmail.com",
309
309
  displayName: "Chiara"
310
310
  },
@@ -318,7 +318,7 @@ test("workspaceService.createWorkspaceForAuthenticatedUser creates non-personal
318
318
  assert.equal(calls.insert, 1);
319
319
  assert.equal(calls.ensureOwnerMembership, 1);
320
320
  assert.equal(insertedPayloads[0].isPersonal, false);
321
- assert.equal(insertedPayloads[0].ownerUserId, 7);
321
+ assert.equal(insertedPayloads[0].ownerUserId, "7");
322
322
  });
323
323
 
324
324
  test("workspaceService.createWorkspaceForAuthenticatedUser rejects creation when self-create policy is disabled", async () => {
@@ -330,7 +330,7 @@ test("workspaceService.createWorkspaceForAuthenticatedUser rejects creation when
330
330
  () =>
331
331
  service.createWorkspaceForAuthenticatedUser(
332
332
  {
333
- id: 7,
333
+ id: "7",
334
334
  email: "chiaramobily@gmail.com",
335
335
  displayName: "Chiara"
336
336
  },
@@ -352,7 +352,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug returns workspace-no
352
352
  () =>
353
353
  service.resolveWorkspaceContextForUserBySlug(
354
354
  {
355
- id: 7,
355
+ id: "7",
356
356
  email: "chiaramobily@gmail.com",
357
357
  displayName: "Chiara"
358
358
  },
@@ -366,19 +366,19 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug allows personal tena
366
366
  const { service } = createWorkspaceServiceFixture({
367
367
  tenancyMode: "personal",
368
368
  personalWorkspace: {
369
- id: 1,
369
+ id: "1",
370
370
  slug: "my-personal",
371
371
  name: "My Personal",
372
- ownerUserId: 7,
372
+ ownerUserId: "7",
373
373
  isPersonal: true,
374
374
  avatarUrl: ""
375
375
  },
376
376
  additionalWorkspaces: [
377
377
  {
378
- id: 42,
378
+ id: "42",
379
379
  slug: "team-alpha",
380
380
  name: "Team Alpha",
381
- ownerUserId: 99,
381
+ ownerUserId: "99",
382
382
  isPersonal: false,
383
383
  avatarUrl: ""
384
384
  }
@@ -387,7 +387,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug allows personal tena
387
387
 
388
388
  const context = await service.resolveWorkspaceContextForUserBySlug(
389
389
  {
390
- id: 7,
390
+ id: "7",
391
391
  email: "chiaramobily@gmail.com",
392
392
  displayName: "Chiara"
393
393
  },
@@ -414,10 +414,10 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug grants owner access
414
414
  return null;
415
415
  }
416
416
  return {
417
- id: 1,
417
+ id: "1",
418
418
  slug: "tonymobily",
419
419
  name: "TonyMobily",
420
- ownerUserId: 7,
420
+ ownerUserId: "7",
421
421
  isPersonal: true,
422
422
  avatarUrl: ""
423
423
  };
@@ -458,7 +458,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug grants owner access
458
458
 
459
459
  const context = await service.resolveWorkspaceContextForUserBySlug(
460
460
  {
461
- id: 7,
461
+ id: "7",
462
462
  email: "chiaramobily@gmail.com",
463
463
  displayName: "Chiara"
464
464
  },
@@ -487,7 +487,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug resolves permissions
487
487
 
488
488
  const context = await service.resolveWorkspaceContextForUserBySlug(
489
489
  {
490
- id: 7,
490
+ id: "7",
491
491
  email: "chiaramobily@gmail.com",
492
492
  displayName: "Chiara"
493
493
  },
@@ -501,10 +501,10 @@ test("workspaceService.getWorkspaceForAuthenticatedUser resolves workspace from
501
501
  const { service } = createWorkspaceServiceFixture({
502
502
  additionalWorkspaces: [
503
503
  {
504
- id: 42,
504
+ id: "42",
505
505
  slug: "team-alpha",
506
506
  name: "Team Alpha",
507
- ownerUserId: 99,
507
+ ownerUserId: "99",
508
508
  isPersonal: false,
509
509
  avatarUrl: ""
510
510
  }
@@ -513,7 +513,7 @@ test("workspaceService.getWorkspaceForAuthenticatedUser resolves workspace from
513
513
 
514
514
  const workspace = await service.getWorkspaceForAuthenticatedUser(
515
515
  {
516
- id: 7,
516
+ id: "7",
517
517
  email: "chiaramobily@gmail.com",
518
518
  displayName: "Chiara"
519
519
  },
@@ -529,7 +529,7 @@ test("workspaceService.updateWorkspaceForAuthenticatedUser updates workspace pro
529
529
 
530
530
  const workspace = await service.updateWorkspaceForAuthenticatedUser(
531
531
  {
532
- id: 7,
532
+ id: "7",
533
533
  email: "chiaramobily@gmail.com",
534
534
  displayName: "Chiara"
535
535
  },
@@ -110,10 +110,10 @@ test("workspaceSettingsRepository.findByWorkspaceId maps the stored row", async
110
110
  defaultInvitesEnabled: createDefaultWorkspaceSettings()
111
111
  });
112
112
 
113
- const record = await repository.findByWorkspaceId(1);
113
+ const record = await repository.findByWorkspaceId("1");
114
114
 
115
115
  assert.deepEqual(record, {
116
- workspaceId: 1,
116
+ workspaceId: "1",
117
117
  lightPrimaryColor: DEFAULT_WORKSPACE_THEME.light.color,
118
118
  lightSecondaryColor: DEFAULT_WORKSPACE_THEME.light.secondaryColor,
119
119
  lightSurfaceColor: DEFAULT_WORKSPACE_THEME.light.surfaceColor,
@@ -134,7 +134,7 @@ test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates invitesEna
134
134
  defaultInvitesEnabled: createDefaultWorkspaceSettings()
135
135
  });
136
136
 
137
- const updated = await repository.updateSettingsByWorkspaceId(1, {
137
+ const updated = await repository.updateSettingsByWorkspaceId("1", {
138
138
  invitesEnabled: false
139
139
  });
140
140
 
@@ -149,9 +149,9 @@ test("workspaceSettingsRepository.ensureForWorkspaceId inserts the injected defa
149
149
  defaultInvitesEnabled: false
150
150
  });
151
151
 
152
- const record = await repository.ensureForWorkspaceId(5);
152
+ const record = await repository.ensureForWorkspaceId("5");
153
153
 
154
- assert.equal(state.insertedRow.workspace_id, 5);
154
+ assert.equal(state.insertedRow.workspace_id, "5");
155
155
  assert.equal(state.insertedRow.light_primary_color, DEFAULT_WORKSPACE_THEME.light.color);
156
156
  assert.equal(state.insertedRow.light_secondary_color, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
157
157
  assert.equal(state.insertedRow.light_surface_color, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
@@ -176,6 +176,7 @@ test("workspaceSettingsRepository.ensureForWorkspaceId inserts the injected defa
176
176
  assert.equal(record.darkSurfaceColor, DEFAULT_WORKSPACE_THEME.dark.surfaceColor);
177
177
  assert.equal(record.darkSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor);
178
178
  assert.equal(record.invitesEnabled, false);
179
+ assert.equal(record.workspaceId, "5");
179
180
  });
180
181
 
181
182
  test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates workspace settings columns", async () => {
@@ -184,7 +185,7 @@ test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates workspace
184
185
  defaultInvitesEnabled: true
185
186
  });
186
187
 
187
- const updated = await repository.updateSettingsByWorkspaceId(1, {
188
+ const updated = await repository.updateSettingsByWorkspaceId("1", {
188
189
  lightPrimaryColor: "#123abc"
189
190
  });
190
191
 
@@ -118,9 +118,9 @@ test("workspace settings output normalizes raw service payloads", () => {
118
118
 
119
119
  assert.deepEqual(normalized, {
120
120
  workspace: {
121
- id: 7,
121
+ id: "7",
122
122
  slug: "mercury",
123
- ownerUserId: 9
123
+ ownerUserId: "9"
124
124
  },
125
125
  settings: {
126
126
  lightPrimaryColor: "#0F6B54",
@@ -1,20 +0,0 @@
1
- # Server Common
2
-
3
- This directory contains server-only runtime pieces reused by multiple slices in `users-core`.
4
-
5
- Use these folders:
6
- - `repositories/`: shared repositories and repository-only helpers.
7
- - `services/`: shared domain services consumed by multiple slices.
8
- - `contributors/`: shared action-context/bootstrap contributors.
9
- - `validators/`: shared request/response validators used by multiple adapters.
10
- - `formatters/`: shared payload formatters/projections for transport output.
11
- - `routes/`: shared route schema maps used by more than one route adapter.
12
-
13
- Keep these files here:
14
- - `registerCommonRepositories.js`: shared repository bindings.
15
- - `registerSharedApi.js`: shared API metadata registration.
16
-
17
- Do not put these in `common/`:
18
- - feature-only actions/services/repositories/controllers
19
- - one-off route payload shapes used by a single feature
20
- - UI/client code
@@ -1,11 +0,0 @@
1
- # `contributors/`
2
-
3
- Put shared runtime contributors here (for action context or bootstrap payload composition).
4
-
5
- Allowed:
6
- - contributors reused by multiple slices/actions
7
- - contributor logic that delegates domain work to services
8
-
9
- Not allowed:
10
- - feature-specific contributors used by one slice only
11
- - direct repository access when a service already owns that domain
@@ -1,11 +0,0 @@
1
- # `formatters/`
2
-
3
- Put shared transport/output projection logic here.
4
-
5
- Allowed:
6
- - shaping domain records into API payloads used in multiple slices
7
-
8
- Not allowed:
9
- - business rules
10
- - repository reads/writes
11
- - HTTP adapter/controller code
@@ -1,24 +0,0 @@
1
- # `repositories/`
2
-
3
- Use this directory for persistence code shared by more than one server slice.
4
-
5
- What belongs here:
6
- - repository helpers that are part of persistence logic
7
- - shared repositories used by multiple features/slices
8
-
9
- Examples:
10
- - SQL/date/JSON helper functions reused by several repositories
11
- - `workspaceMembershipsRepository`
12
- - `workspaceInvitesRepository`
13
-
14
- Do not put these here:
15
- - repositories used by only one feature
16
- - business logic
17
- - action definitions
18
- - transport validation
19
- - feature-specific response mapping
20
-
21
- Rule:
22
- - if a helper is reused by multiple repository files, it can live here
23
- - if a repository is reused by multiple slices, keep it here
24
- - if a repository is owned by one slice only, keep it in that slice folder
@@ -1,11 +0,0 @@
1
- # `routes/`
2
-
3
- Put shared route schema maps here when multiple route adapters consume them.
4
-
5
- Allowed:
6
- - shared route request/response schema groupings
7
- - references to shared resources/commands
8
-
9
- Not allowed:
10
- - route registration/handlers
11
- - business logic
@@ -1,12 +0,0 @@
1
- # `services/`
2
-
3
- Put shared server services here when they are used by more than one slice.
4
-
5
- Allowed:
6
- - cross-slice service logic with clear inputs/outputs
7
- - no HTTP route validator handling
8
-
9
- Not allowed:
10
- - feature-only services
11
- - route adapters/controllers
12
- - response schema declarations
@@ -1,11 +0,0 @@
1
- # `validators/`
2
-
3
- Put shared validators here when they are reused by multiple server slices/adapters.
4
-
5
- Allowed:
6
- - validator objects (`schema` + `normalize`)
7
- - transport-level reusable validators
8
-
9
- Not allowed:
10
- - feature-only validators used by one slice
11
- - business/domain decision logic