@jskit-ai/users-core 0.1.31 → 0.1.32

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 (37) hide show
  1. package/package.descriptor.mjs +8 -6
  2. package/package.json +6 -6
  3. package/src/server/UsersCoreServiceProvider.js +1 -3
  4. package/src/server/accountProfile/avatarService.js +18 -59
  5. package/src/server/accountProfile/avatarStorageService.js +14 -95
  6. package/src/server/accountProfile/bootAccountProfileRoutes.js +10 -14
  7. package/src/server/common/formatters/workspaceFormatter.js +2 -2
  8. package/src/server/common/repositories/userProfilesRepository.js +6 -6
  9. package/src/server/common/repositories/workspaceInvitesRepository.js +2 -2
  10. package/src/server/common/repositories/workspaceMembershipsRepository.js +9 -9
  11. package/src/server/common/repositories/workspacesRepository.js +2 -2
  12. package/src/server/common/services/authProfileSyncService.js +5 -5
  13. package/src/server/common/services/workspaceContextService.js +3 -3
  14. package/src/server/common/validators/authenticatedUserValidator.js +2 -2
  15. package/src/server/workspaceBootstrapContributor.js +2 -2
  16. package/src/server/workspaceMembers/bootWorkspaceMembers.js +2 -2
  17. package/src/server/workspaceMembers/workspaceMembersActions.js +2 -2
  18. package/src/server/workspaceMembers/workspaceMembersService.js +11 -11
  19. package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +1 -1
  20. package/src/shared/resources/workspaceMembersResource.js +11 -11
  21. package/src/shared/resources/workspacePendingInvitationsResource.js +2 -2
  22. package/src/shared/resources/workspaceResource.js +2 -2
  23. package/src/shared/roles.js +8 -8
  24. package/templates/migrations/users_core_initial.cjs +5 -5
  25. package/test/authProfileSyncService.test.js +5 -5
  26. package/test/avatarService.test.js +4 -4
  27. package/test/usersRouteRequestInputValidator.test.js +4 -4
  28. package/test/workspaceActionContextContributor.test.js +9 -9
  29. package/test/workspaceAuthPolicyContextResolver.test.js +2 -2
  30. package/test/workspaceBootstrapContributor.test.js +1 -1
  31. package/test/workspaceInvitesRepository.test.js +3 -3
  32. package/test/workspaceMembersService.test.js +10 -10
  33. package/test/workspacePendingInvitationsResource.test.js +2 -2
  34. package/test/workspacePendingInvitationsService.test.js +3 -3
  35. package/test/workspaceService.test.js +10 -10
  36. package/src/server/accountProfile/registerAvatarMultipartSupport.js +0 -40
  37. package/test/registerAvatarMultipartSupport.test.js +0 -63
@@ -52,7 +52,7 @@ function createFixture() {
52
52
  return [
53
53
  {
54
54
  userId: 11,
55
- roleId: "member",
55
+ roleSid: "member",
56
56
  status: "active",
57
57
  displayName: "Alice",
58
58
  email: "alice@example.com"
@@ -65,7 +65,7 @@ function createFixture() {
65
65
  return {
66
66
  workspaceId: 7,
67
67
  userId: 11,
68
- roleId: "member",
68
+ roleSid: "member",
69
69
  status: "active"
70
70
  };
71
71
  },
@@ -73,7 +73,7 @@ function createFixture() {
73
73
  assert.equal(Number(workspaceId), 7);
74
74
  assert.equal(Number(userId), 11);
75
75
  assert.deepEqual(patch, {
76
- roleId: "admin",
76
+ roleSid: "admin",
77
77
  status: "active"
78
78
  });
79
79
  }
@@ -134,7 +134,7 @@ test("workspaceMembersService.createInvite uses configured inviteExpiresInMs", a
134
134
  { id: 11 },
135
135
  {
136
136
  email: "alice@example.com",
137
- roleId: "member"
137
+ roleSid: "member"
138
138
  },
139
139
  authorizedOptions(["workspace.members.invite"])
140
140
  );
@@ -260,13 +260,13 @@ test("workspaceMembersService.updateMemberRole returns the refreshed member list
260
260
  workspace,
261
261
  {
262
262
  memberUserId: 11,
263
- roleId: "admin"
263
+ roleSid: "admin"
264
264
  },
265
265
  authorizedOptions(["workspace.members.manage"])
266
266
  );
267
267
 
268
268
  assert.equal(response.members.length, 1);
269
- assert.equal(response.members[0].roleId, "member");
269
+ assert.equal(response.members[0].roleSid, "member");
270
270
  });
271
271
 
272
272
  test("workspaceMembersService.removeMember marks membership revoked and returns refreshed members", async () => {
@@ -287,7 +287,7 @@ test("workspaceMembersService.removeMember marks membership revoked and returns
287
287
  : [
288
288
  {
289
289
  userId: 11,
290
- roleId: "member",
290
+ roleSid: "member",
291
291
  status: "active",
292
292
  displayName: "Alice",
293
293
  email: "alice@example.com"
@@ -300,7 +300,7 @@ test("workspaceMembersService.removeMember marks membership revoked and returns
300
300
  return {
301
301
  workspaceId: 7,
302
302
  userId: 11,
303
- roleId: "member",
303
+ roleSid: "member",
304
304
  status: "active"
305
305
  };
306
306
  },
@@ -308,7 +308,7 @@ test("workspaceMembersService.removeMember marks membership revoked and returns
308
308
  assert.equal(Number(workspaceId), 7);
309
309
  assert.equal(Number(userId), 11);
310
310
  assert.deepEqual(patch, {
311
- roleId: "member",
311
+ roleSid: "member",
312
312
  status: "revoked"
313
313
  });
314
314
  removed = true;
@@ -359,7 +359,7 @@ test("workspaceMembersService.removeMember rejects removing the owner", async ()
359
359
  return {
360
360
  workspaceId: 7,
361
361
  userId: 9,
362
- roleId: "owner",
362
+ roleSid: "owner",
363
363
  status: "active"
364
364
  };
365
365
  },
@@ -14,7 +14,7 @@ test("workspacePendingInvitationsResource output normalizer shapes raw invite ro
14
14
  workspaceSlug: "tonymobily3",
15
15
  workspaceName: "",
16
16
  workspaceAvatarUrl: "",
17
- roleId: "Member",
17
+ roleSid: "Member",
18
18
  status: "Pending",
19
19
  expiresAt: "2030-01-01T00:00:00.000Z",
20
20
  tokenHash
@@ -29,7 +29,7 @@ test("workspacePendingInvitationsResource output normalizer shapes raw invite ro
29
29
  workspaceSlug: "tonymobily3",
30
30
  workspaceName: "tonymobily3",
31
31
  workspaceAvatarUrl: "",
32
- roleId: "member",
32
+ roleSid: "member",
33
33
  status: "pending",
34
34
  expiresAt: "2030-01-01T00:00:00.000Z",
35
35
  token: encodeInviteTokenHash(tokenHash)
@@ -64,7 +64,7 @@ test("listPendingInvitesForUser returns raw pending invite rows for the action l
64
64
  workspaceSlug: "tonymobily3",
65
65
  workspaceName: "TonyMobily3",
66
66
  workspaceAvatarUrl: "",
67
- roleId: "member",
67
+ roleSid: "member",
68
68
  status: "pending",
69
69
  expiresAt: "2030-01-01T00:00:00.000Z",
70
70
  tokenHash
@@ -91,7 +91,7 @@ test("acceptInviteByToken accepts opaque invite token and resolves invite by dec
91
91
  id: 44,
92
92
  workspaceId: 1,
93
93
  email: "chiaramobily@gmail.com",
94
- roleId: "member",
94
+ roleSid: "member",
95
95
  status: "pending",
96
96
  tokenHash,
97
97
  expiresAt: "2030-01-01T00:00:00.000Z"
@@ -125,7 +125,7 @@ test("refuseInviteByToken revokes the invite and returns refused", async () => {
125
125
  id: 45,
126
126
  workspaceId: 1,
127
127
  email: "chiaramobily@gmail.com",
128
- roleId: "member",
128
+ roleSid: "member",
129
129
  status: "pending",
130
130
  tokenHash,
131
131
  expiresAt: "2030-01-01T00:00:00.000Z"
@@ -95,7 +95,7 @@ function createWorkspaceServiceFixture({
95
95
  slug: "tonymobily3",
96
96
  name: "TonyMobily3",
97
97
  avatarUrl: "",
98
- roleId: "owner",
98
+ roleSid: "owner",
99
99
  membershipStatus: "active"
100
100
  },
101
101
  {
@@ -103,7 +103,7 @@ function createWorkspaceServiceFixture({
103
103
  slug: "pending-workspace",
104
104
  name: "Pending Workspace",
105
105
  avatarUrl: "",
106
- roleId: "member",
106
+ roleSid: "member",
107
107
  membershipStatus: "pending"
108
108
  }
109
109
  ];
@@ -158,7 +158,7 @@ function createWorkspaceServiceFixture({
158
158
  return {
159
159
  workspaceId,
160
160
  userId,
161
- roleId: "owner",
161
+ roleSid: "owner",
162
162
  status: "active"
163
163
  };
164
164
  }
@@ -190,7 +190,7 @@ test("workspaceService.listWorkspacesForUser returns only accessible workspaces"
190
190
 
191
191
  assert.equal(workspaces.length, 1);
192
192
  assert.equal(workspaces[0].slug, "tonymobily3");
193
- assert.equal(workspaces[0].roleId, "owner");
193
+ assert.equal(workspaces[0].roleSid, "owner");
194
194
  assert.equal(calls.listForUserId, 1);
195
195
  assert.equal(calls.insert, 0);
196
196
  });
@@ -220,7 +220,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
220
220
  slug: "chiaramobily",
221
221
  name: "Chiara Personal",
222
222
  avatarUrl: "",
223
- roleId: "owner",
223
+ roleSid: "owner",
224
224
  membershipStatus: "active"
225
225
  },
226
226
  {
@@ -228,7 +228,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
228
228
  slug: "tonymobily",
229
229
  name: "Tony Workspace",
230
230
  avatarUrl: "",
231
- roleId: "member",
231
+ roleSid: "member",
232
232
  membershipStatus: "active"
233
233
  },
234
234
  {
@@ -236,7 +236,7 @@ test("workspaceService.listWorkspacesForUser returns all active memberships in p
236
236
  slug: "pending-workspace",
237
237
  name: "Pending Workspace",
238
238
  avatarUrl: "",
239
- roleId: "member",
239
+ roleSid: "member",
240
240
  membershipStatus: "pending"
241
241
  }
242
242
  ]
@@ -393,7 +393,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug allows personal tena
393
393
  );
394
394
 
395
395
  assert.equal(context.workspace.slug, "team-alpha");
396
- assert.equal(context.membership.roleId, "owner");
396
+ assert.equal(context.membership.roleSid, "owner");
397
397
  assert.deepEqual(context.permissions, ["*"]);
398
398
  });
399
399
 
@@ -439,7 +439,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug grants owner access
439
439
  membershipRecord = {
440
440
  workspaceId,
441
441
  userId,
442
- roleId: "owner",
442
+ roleSid: "owner",
443
443
  status: "active"
444
444
  };
445
445
  return membershipRecord;
@@ -464,7 +464,7 @@ test("workspaceService.resolveWorkspaceContextForUserBySlug grants owner access
464
464
  );
465
465
 
466
466
  assert.equal(ensuredMembershipCount, 1);
467
- assert.equal(context.membership.roleId, "owner");
467
+ assert.equal(context.membership.roleSid, "owner");
468
468
  assert.deepEqual(context.permissions, ["*"]);
469
469
  });
470
470
 
@@ -1,40 +0,0 @@
1
- import fastifyMultipart from "@fastify/multipart";
2
-
3
- async function registerAvatarMultipartSupport(app) {
4
- if (!app || typeof app.has !== "function" || typeof app.make !== "function") {
5
- throw new Error("registerAvatarMultipartSupport requires application has()/make().");
6
- }
7
-
8
- if (!app.has("jskit.fastify")) {
9
- return;
10
- }
11
-
12
- const fastify = app.make("jskit.fastify");
13
- if (!fastify || typeof fastify.register !== "function") {
14
- throw new Error("registerAvatarMultipartSupport requires Fastify register().");
15
- }
16
-
17
- if (fastify["jskit.users-core.avatar.multipart.support"] === true) {
18
- return;
19
- }
20
-
21
- if (typeof fastify.hasContentTypeParser === "function" && fastify.hasContentTypeParser("multipart")) {
22
- Object.defineProperty(fastify, "jskit.users-core.avatar.multipart.support", {
23
- value: true,
24
- configurable: false,
25
- enumerable: false,
26
- writable: false
27
- });
28
- return;
29
- }
30
-
31
- await fastify.register(fastifyMultipart);
32
- Object.defineProperty(fastify, "jskit.users-core.avatar.multipart.support", {
33
- value: true,
34
- configurable: false,
35
- enumerable: false,
36
- writable: false
37
- });
38
- }
39
-
40
- export { registerAvatarMultipartSupport };
@@ -1,63 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { registerAvatarMultipartSupport } from "../src/server/accountProfile/registerAvatarMultipartSupport.js";
4
-
5
- function createAppStub({ hasFastify = true, fastify = null } = {}) {
6
- const resolvedFastify =
7
- fastify ||
8
- {
9
- register: async () => {},
10
- hasContentTypeParser: () => false
11
- };
12
-
13
- return {
14
- has(token) {
15
- if (token === "jskit.fastify") {
16
- return hasFastify;
17
- }
18
- return false;
19
- },
20
- make(token) {
21
- if (token === "jskit.fastify") {
22
- return resolvedFastify;
23
- }
24
- return null;
25
- }
26
- };
27
- }
28
-
29
- test("registerAvatarMultipartSupport returns early when Fastify is not available", async () => {
30
- const app = createAppStub({ hasFastify: false });
31
- await assert.doesNotReject(async () => registerAvatarMultipartSupport(app));
32
- });
33
-
34
- test("registerAvatarMultipartSupport registers multipart parser only once", async () => {
35
- let registerCount = 0;
36
- const fastify = {
37
- register: async () => {
38
- registerCount += 1;
39
- },
40
- hasContentTypeParser: () => false
41
- };
42
- const app = createAppStub({ fastify });
43
-
44
- await registerAvatarMultipartSupport(app);
45
- await registerAvatarMultipartSupport(app);
46
-
47
- assert.equal(registerCount, 1);
48
- });
49
-
50
- test("registerAvatarMultipartSupport skips registration when parser already exists", async () => {
51
- let registerCount = 0;
52
- const fastify = {
53
- register: async () => {
54
- registerCount += 1;
55
- },
56
- hasContentTypeParser: (contentType) => String(contentType || "").trim().toLowerCase() === "multipart"
57
- };
58
- const app = createAppStub({ fastify });
59
-
60
- await registerAvatarMultipartSupport(app);
61
-
62
- assert.equal(registerCount, 0);
63
- });