@jskit-ai/users-core 0.1.55 → 0.1.57

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 (47) hide show
  1. package/package.descriptor.mjs +175 -6
  2. package/package.json +6 -6
  3. package/src/server/accountNotifications/accountNotificationsService.js +3 -3
  4. package/src/server/accountNotifications/registerAccountNotifications.js +2 -2
  5. package/src/server/accountPreferences/accountPreferencesService.js +3 -3
  6. package/src/server/accountPreferences/registerAccountPreferences.js +2 -2
  7. package/src/server/accountProfile/accountProfileService.js +5 -5
  8. package/src/server/accountProfile/avatarService.js +6 -6
  9. package/src/server/accountProfile/registerAccountProfile.js +3 -3
  10. package/src/server/accountSecurity/accountSecurityService.js +3 -3
  11. package/src/server/accountSecurity/registerAccountSecurity.js +2 -2
  12. package/src/server/common/registerCommonRepositories.js +5 -5
  13. package/src/server/common/repositories/{usersRepository.js → userProfilesRepository.js} +117 -95
  14. package/src/server/common/repositories/userSettingsRepository.js +12 -11
  15. package/src/server/common/resources/userProfilesResource.js +203 -0
  16. package/src/server/common/services/accountContextService.js +4 -4
  17. package/src/server/common/services/authProfileSyncService.js +11 -11
  18. package/src/server/common/support/identity.js +17 -0
  19. package/src/server/registerUsersBootstrap.js +2 -2
  20. package/src/server/registerUsersCore.js +2 -2
  21. package/src/server/usersBootstrapContributor.js +5 -5
  22. package/src/shared/resources/userProfileResource.js +1 -1
  23. package/src/shared/resources/userSettingsFields.js +10 -4
  24. package/src/shared/resources/userSettingsResource.js +1 -1
  25. package/templates/packages/main/src/shared/resources/userSettingsFields.js +10 -10
  26. package/templates/packages/users/package.descriptor.mjs +65 -0
  27. package/templates/packages/users/package.json +10 -0
  28. package/templates/packages/users/src/server/UsersProvider.js +91 -0
  29. package/templates/packages/users/src/server/actionIds.js +6 -0
  30. package/templates/packages/users/src/server/actions.js +73 -0
  31. package/templates/packages/users/src/server/listConfig.js +16 -0
  32. package/templates/packages/users/src/server/registerRoutes.js +87 -0
  33. package/templates/packages/users/src/server/repository.js +41 -0
  34. package/templates/packages/users/src/server/service.js +28 -0
  35. package/templates/packages/users/src/shared/index.js +1 -0
  36. package/templates/packages/users/src/shared/userResource.js +74 -0
  37. package/templates/packages/users-workspace/package.descriptor.mjs +66 -0
  38. package/templates/packages/users-workspace/src/server/UsersProvider.js +92 -0
  39. package/templates/packages/users-workspace/src/server/actions.js +74 -0
  40. package/templates/packages/users-workspace/src/server/registerRoutes.js +93 -0
  41. package/test/authProfileSyncService.test.js +3 -3
  42. package/test/avatarService.test.js +2 -2
  43. package/test/registerCommonRepositories.test.js +37 -0
  44. package/test/repositoryContracts.test.js +48 -5
  45. package/test/usersBootstrapContributor.test.js +2 -2
  46. package/test/usersPackageScaffoldContract.test.js +98 -0
  47. package/test/usersRouteResources.test.js +1 -1
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  packageVersion: 1,
3
3
  packageId: "@jskit-ai/users-core",
4
- version: "0.1.55",
4
+ version: "0.1.57",
5
5
  kind: "runtime",
6
6
  description: "Users/account runtime plus HTTP routes for account features.",
7
7
  dependsOn: [
@@ -128,11 +128,13 @@ export default Object.freeze({
128
128
  mutations: {
129
129
  dependencies: {
130
130
  runtime: {
131
- "@jskit-ai/auth-core": "0.1.44",
132
- "@jskit-ai/database-runtime": "0.1.45",
133
- "@jskit-ai/http-runtime": "0.1.44",
134
- "@jskit-ai/kernel": "0.1.45",
135
- "@jskit-ai/uploads-runtime": "0.1.23",
131
+ "@jskit-ai/auth-core": "0.1.46",
132
+ "@jskit-ai/crud-core": "0.1.55",
133
+ "@jskit-ai/database-runtime": "0.1.47",
134
+ "@jskit-ai/http-runtime": "0.1.46",
135
+ "@jskit-ai/kernel": "0.1.47",
136
+ "@local/users": "file:packages/users",
137
+ "@jskit-ai/uploads-runtime": "0.1.25",
136
138
  "@fastify/type-provider-typebox": "^6.1.0",
137
139
  typebox: "^1.0.81"
138
140
  },
@@ -168,6 +170,173 @@ export default Object.freeze({
168
170
  reason: "Install app-owned user settings field definitions.",
169
171
  category: "users-core",
170
172
  id: "users-core-app-owned-user-settings-fields"
173
+ },
174
+ {
175
+ from: "templates/packages/users/package.json",
176
+ to: "packages/users/package.json",
177
+ ownership: "app",
178
+ preserveOnRemove: true,
179
+ reason: "Install app-owned users package manifest.",
180
+ category: "users-core",
181
+ id: "users-core-users-package-json"
182
+ },
183
+ {
184
+ from: "templates/packages/users/package.descriptor.mjs",
185
+ to: "packages/users/package.descriptor.mjs",
186
+ ownership: "app",
187
+ preserveOnRemove: true,
188
+ reason: "Install app-owned users package descriptor for non-workspace tenancy.",
189
+ category: "users-core",
190
+ id: "users-core-users-package-descriptor-base",
191
+ when: {
192
+ config: "tenancyMode",
193
+ notIn: ["personal", "workspaces"]
194
+ }
195
+ },
196
+ {
197
+ from: "templates/packages/users-workspace/package.descriptor.mjs",
198
+ to: "packages/users/package.descriptor.mjs",
199
+ ownership: "app",
200
+ preserveOnRemove: true,
201
+ reason: "Install app-owned users package descriptor for workspace tenancy.",
202
+ category: "users-core",
203
+ id: "users-core-users-package-descriptor-workspace",
204
+ when: {
205
+ config: "tenancyMode",
206
+ in: ["personal", "workspaces"]
207
+ }
208
+ },
209
+ {
210
+ from: "templates/packages/users/src/server/UsersProvider.js",
211
+ to: "packages/users/src/server/UsersProvider.js",
212
+ ownership: "app",
213
+ preserveOnRemove: true,
214
+ reason: "Install app-owned users CRUD provider for non-workspace tenancy.",
215
+ category: "users-core",
216
+ id: "users-core-users-provider-base",
217
+ when: {
218
+ config: "tenancyMode",
219
+ notIn: ["personal", "workspaces"]
220
+ }
221
+ },
222
+ {
223
+ from: "templates/packages/users-workspace/src/server/UsersProvider.js",
224
+ to: "packages/users/src/server/UsersProvider.js",
225
+ ownership: "app",
226
+ preserveOnRemove: true,
227
+ reason: "Install app-owned users CRUD provider for workspace tenancy.",
228
+ category: "users-core",
229
+ id: "users-core-users-provider-workspace",
230
+ when: {
231
+ config: "tenancyMode",
232
+ in: ["personal", "workspaces"]
233
+ }
234
+ },
235
+ {
236
+ from: "templates/packages/users/src/server/actionIds.js",
237
+ to: "packages/users/src/server/actionIds.js",
238
+ ownership: "app",
239
+ preserveOnRemove: true,
240
+ reason: "Install app-owned users CRUD action IDs.",
241
+ category: "users-core",
242
+ id: "users-core-users-action-ids"
243
+ },
244
+ {
245
+ from: "templates/packages/users/src/server/actions.js",
246
+ to: "packages/users/src/server/actions.js",
247
+ ownership: "app",
248
+ preserveOnRemove: true,
249
+ reason: "Install app-owned users CRUD actions for non-workspace tenancy.",
250
+ category: "users-core",
251
+ id: "users-core-users-actions-base",
252
+ when: {
253
+ config: "tenancyMode",
254
+ notIn: ["personal", "workspaces"]
255
+ }
256
+ },
257
+ {
258
+ from: "templates/packages/users-workspace/src/server/actions.js",
259
+ to: "packages/users/src/server/actions.js",
260
+ ownership: "app",
261
+ preserveOnRemove: true,
262
+ reason: "Install app-owned users CRUD actions for workspace tenancy.",
263
+ category: "users-core",
264
+ id: "users-core-users-actions-workspace",
265
+ when: {
266
+ config: "tenancyMode",
267
+ in: ["personal", "workspaces"]
268
+ }
269
+ },
270
+ {
271
+ from: "templates/packages/users/src/server/listConfig.js",
272
+ to: "packages/users/src/server/listConfig.js",
273
+ ownership: "app",
274
+ preserveOnRemove: true,
275
+ reason: "Install app-owned users CRUD list configuration.",
276
+ category: "users-core",
277
+ id: "users-core-users-list-config"
278
+ },
279
+ {
280
+ from: "templates/packages/users/src/server/registerRoutes.js",
281
+ to: "packages/users/src/server/registerRoutes.js",
282
+ ownership: "app",
283
+ preserveOnRemove: true,
284
+ reason: "Install app-owned users CRUD routes for non-workspace tenancy.",
285
+ category: "users-core",
286
+ id: "users-core-users-routes-base",
287
+ when: {
288
+ config: "tenancyMode",
289
+ notIn: ["personal", "workspaces"]
290
+ }
291
+ },
292
+ {
293
+ from: "templates/packages/users-workspace/src/server/registerRoutes.js",
294
+ to: "packages/users/src/server/registerRoutes.js",
295
+ ownership: "app",
296
+ preserveOnRemove: true,
297
+ reason: "Install app-owned users CRUD routes for workspace tenancy.",
298
+ category: "users-core",
299
+ id: "users-core-users-routes-workspace",
300
+ when: {
301
+ config: "tenancyMode",
302
+ in: ["personal", "workspaces"]
303
+ }
304
+ },
305
+ {
306
+ from: "templates/packages/users/src/server/repository.js",
307
+ to: "packages/users/src/server/repository.js",
308
+ ownership: "app",
309
+ preserveOnRemove: true,
310
+ reason: "Install app-owned users CRUD repository.",
311
+ category: "users-core",
312
+ id: "users-core-users-repository"
313
+ },
314
+ {
315
+ from: "templates/packages/users/src/server/service.js",
316
+ to: "packages/users/src/server/service.js",
317
+ ownership: "app",
318
+ preserveOnRemove: true,
319
+ reason: "Install app-owned users CRUD service.",
320
+ category: "users-core",
321
+ id: "users-core-users-service"
322
+ },
323
+ {
324
+ from: "templates/packages/users/src/shared/index.js",
325
+ to: "packages/users/src/shared/index.js",
326
+ ownership: "app",
327
+ preserveOnRemove: true,
328
+ reason: "Install app-owned users shared entrypoint.",
329
+ category: "users-core",
330
+ id: "users-core-users-shared-index"
331
+ },
332
+ {
333
+ from: "templates/packages/users/src/shared/userResource.js",
334
+ to: "packages/users/src/shared/userResource.js",
335
+ ownership: "app",
336
+ preserveOnRemove: true,
337
+ reason: "Install app-owned users shared resource.",
338
+ category: "users-core",
339
+ id: "users-core-users-resource"
171
340
  }
172
341
  ],
173
342
  text: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/users-core",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -13,11 +13,11 @@
13
13
  "./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
14
14
  },
15
15
  "dependencies": {
16
- "@jskit-ai/auth-core": "0.1.44",
17
- "@jskit-ai/database-runtime": "0.1.45",
18
- "@jskit-ai/http-runtime": "0.1.44",
19
- "@jskit-ai/kernel": "0.1.45",
20
- "@jskit-ai/uploads-runtime": "0.1.23",
16
+ "@jskit-ai/auth-core": "0.1.46",
17
+ "@jskit-ai/database-runtime": "0.1.47",
18
+ "@jskit-ai/http-runtime": "0.1.46",
19
+ "@jskit-ai/kernel": "0.1.47",
20
+ "@jskit-ai/uploads-runtime": "0.1.25",
21
21
  "@fastify/type-provider-typebox": "^6.1.0",
22
22
  "typebox": "^1.0.81"
23
23
  }
@@ -9,15 +9,15 @@ import {
9
9
 
10
10
  function createService({
11
11
  userSettingsRepository,
12
- usersRepository,
12
+ userProfilesRepository,
13
13
  authService
14
14
  } = {}) {
15
- if (!userSettingsRepository || !usersRepository) {
15
+ if (!userSettingsRepository || !userProfilesRepository) {
16
16
  throw new Error("accountNotificationsService requires repositories.");
17
17
  }
18
18
 
19
19
  async function updateNotifications(request, user, payload = {}, options = {}) {
20
- const profile = await resolveUserProfile(usersRepository, user);
20
+ const profile = await resolveUserProfile(userProfilesRepository, user);
21
21
  if (!profile) {
22
22
  throw new AppError(404, "User profile was not found.");
23
23
  }
@@ -13,8 +13,8 @@ function registerAccountNotifications(app) {
13
13
  "users.accountNotifications.service",
14
14
  (scope) =>
15
15
  createAccountNotificationsService({
16
- userSettingsRepository: scope.make("userSettingsRepository"),
17
- usersRepository: scope.make("usersRepository"),
16
+ userSettingsRepository: scope.make("internal.repository.user-settings"),
17
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
18
18
  authService: scope.make("authService")
19
19
  }),
20
20
  {
@@ -9,15 +9,15 @@ import {
9
9
 
10
10
  function createService({
11
11
  userSettingsRepository,
12
- usersRepository,
12
+ userProfilesRepository,
13
13
  authService
14
14
  } = {}) {
15
- if (!userSettingsRepository || !usersRepository) {
15
+ if (!userSettingsRepository || !userProfilesRepository) {
16
16
  throw new Error("accountPreferencesService requires repositories.");
17
17
  }
18
18
 
19
19
  async function updatePreferences(request, user, payload = {}, options = {}) {
20
- const profile = await resolveUserProfile(usersRepository, user);
20
+ const profile = await resolveUserProfile(userProfilesRepository, user);
21
21
  if (!profile) {
22
22
  throw new AppError(404, "User profile was not found.");
23
23
  }
@@ -13,8 +13,8 @@ function registerAccountPreferences(app) {
13
13
  "users.accountPreferences.service",
14
14
  (scope) =>
15
15
  createAccountPreferencesService({
16
- userSettingsRepository: scope.make("userSettingsRepository"),
17
- usersRepository: scope.make("usersRepository"),
16
+ userSettingsRepository: scope.make("internal.repository.user-settings"),
17
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
18
18
  authService: scope.make("authService")
19
19
  }),
20
20
  {
@@ -9,16 +9,16 @@ import {
9
9
 
10
10
  function createService({
11
11
  userSettingsRepository,
12
- usersRepository,
12
+ userProfilesRepository,
13
13
  authService,
14
14
  avatarService
15
15
  } = {}) {
16
- if (!userSettingsRepository || !usersRepository || !avatarService) {
16
+ if (!userSettingsRepository || !userProfilesRepository || !avatarService) {
17
17
  throw new Error("accountProfileService requires repositories and avatarService.");
18
18
  }
19
19
 
20
20
  async function getForUser(request, user, options = {}) {
21
- const profile = await resolveUserProfile(usersRepository, user);
21
+ const profile = await resolveUserProfile(userProfilesRepository, user);
22
22
  if (!profile) {
23
23
  throw new AppError(404, "User profile was not found.");
24
24
  }
@@ -35,7 +35,7 @@ function createService({
35
35
  }
36
36
 
37
37
  async function updateProfile(request, user, payload = {}, options = {}) {
38
- const profile = await resolveUserProfile(usersRepository, user);
38
+ const profile = await resolveUserProfile(userProfilesRepository, user);
39
39
  if (!profile) {
40
40
  throw new AppError(404, "User profile was not found.");
41
41
  }
@@ -49,7 +49,7 @@ function createService({
49
49
  }
50
50
 
51
51
  if (!updatedProfile) {
52
- updatedProfile = await usersRepository.updateDisplayNameById(profile.id, payload.displayName);
52
+ updatedProfile = await userProfilesRepository.updateDisplayNameById(profile.id, payload.displayName);
53
53
  }
54
54
 
55
55
  const settings = await userSettingsRepository.ensureForUserId(updatedProfile.id);
@@ -21,9 +21,9 @@ async function readAvatarBuffer(stream, { maxBytes = DEFAULT_AVATAR_POLICY.maxUp
21
21
  });
22
22
  }
23
23
 
24
- function createService({ usersRepository, avatarStorageService, avatarPolicy } = {}) {
25
- if (!usersRepository) {
26
- throw new TypeError("avatarService requires usersRepository.");
24
+ function createService({ userProfilesRepository, avatarStorageService, avatarPolicy } = {}) {
25
+ if (!userProfilesRepository) {
26
+ throw new TypeError("avatarService requires userProfilesRepository.");
27
27
  }
28
28
  if (!avatarStorageService) {
29
29
  throw new TypeError("avatarService requires avatarStorageService.");
@@ -32,7 +32,7 @@ function createService({ usersRepository, avatarStorageService, avatarPolicy } =
32
32
  const resolvedAvatarPolicy = resolveAvatarPolicy(avatarPolicy);
33
33
 
34
34
  async function resolveProfile(user) {
35
- const profile = await resolveUserProfile(usersRepository, user);
35
+ const profile = await resolveUserProfile(userProfilesRepository, user);
36
36
  if (!profile) {
37
37
  throw new AppError(404, "User profile was not found.");
38
38
  }
@@ -57,7 +57,7 @@ function createService({ usersRepository, avatarStorageService, avatarPolicy } =
57
57
  buffer
58
58
  });
59
59
 
60
- const updatedProfile = await usersRepository.updateAvatarById(profile.id, {
60
+ const updatedProfile = await userProfilesRepository.updateAvatarById(profile.id, {
61
61
  avatarStorageKey: savedAvatar.storageKey,
62
62
  avatarVersion,
63
63
  avatarUpdatedAt: new Date(avatarVersionMs)
@@ -73,7 +73,7 @@ function createService({ usersRepository, avatarStorageService, avatarPolicy } =
73
73
  if (profile.avatarStorageKey) {
74
74
  await avatarStorageService.deleteAvatar(profile.avatarStorageKey);
75
75
  }
76
- return usersRepository.clearAvatarById(profile.id);
76
+ return userProfilesRepository.clearAvatarById(profile.id);
77
77
  }
78
78
 
79
79
  async function readForUser(user) {
@@ -20,7 +20,7 @@ function registerAccountProfile(app) {
20
20
 
21
21
  app.singleton("users.avatar.service", (scope) =>
22
22
  createAvatarService({
23
- usersRepository: scope.make("usersRepository"),
23
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
24
24
  avatarStorageService: scope.make("users.avatar.storage.service")
25
25
  })
26
26
  );
@@ -29,8 +29,8 @@ function registerAccountProfile(app) {
29
29
  "users.accountProfile.service",
30
30
  (scope) =>
31
31
  createAccountProfileService({
32
- userSettingsRepository: scope.make("userSettingsRepository"),
33
- usersRepository: scope.make("usersRepository"),
32
+ userSettingsRepository: scope.make("internal.repository.user-settings"),
33
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
34
34
  authService: scope.make("authService"),
35
35
  avatarService: scope.make("users.avatar.service")
36
36
  }),
@@ -10,10 +10,10 @@ import {
10
10
 
11
11
  function createService({
12
12
  userSettingsRepository,
13
- usersRepository,
13
+ userProfilesRepository,
14
14
  authService
15
15
  } = {}) {
16
- if (!userSettingsRepository || !usersRepository) {
16
+ if (!userSettingsRepository || !userProfilesRepository) {
17
17
  throw new Error("accountSecurityService requires repositories.");
18
18
  }
19
19
 
@@ -40,7 +40,7 @@ function createService({
40
40
  throw new AppError(501, "Password method toggle is not available.");
41
41
  }
42
42
 
43
- const profile = await resolveUserProfile(usersRepository, user);
43
+ const profile = await resolveUserProfile(userProfilesRepository, user);
44
44
  if (!profile) {
45
45
  throw new AppError(404, "User profile was not found.");
46
46
  }
@@ -10,8 +10,8 @@ function registerAccountSecurity(app) {
10
10
  app.singleton("users.accountSecurity.service", (scope) => {
11
11
  const authService = scope.has("authService") ? scope.make("authService") : null;
12
12
  return createAccountSecurityService({
13
- userSettingsRepository: scope.make("userSettingsRepository"),
14
- usersRepository: scope.make("usersRepository"),
13
+ userSettingsRepository: scope.make("internal.repository.user-settings"),
14
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
15
15
  authService
16
16
  });
17
17
  });
@@ -1,4 +1,4 @@
1
- import { createRepository as createUsersRepository } from "./repositories/usersRepository.js";
1
+ import { createRepository as createUserProfilesRepository } from "./repositories/userProfilesRepository.js";
2
2
  import { createRepository as createUserSettingsRepository } from "./repositories/userSettingsRepository.js";
3
3
 
4
4
  function registerCommonRepositories(app) {
@@ -6,14 +6,14 @@ function registerCommonRepositories(app) {
6
6
  throw new Error("registerCommonRepositories requires application singleton().");
7
7
  }
8
8
 
9
- app.singleton("usersRepository", (scope) => {
9
+ app.singleton("internal.repository.user-settings", (scope) => {
10
10
  const knex = scope.make("jskit.database.knex");
11
- return createUsersRepository(knex);
11
+ return createUserSettingsRepository(knex);
12
12
  });
13
13
 
14
- app.singleton("userSettingsRepository", (scope) => {
14
+ app.singleton("internal.repository.user-profiles", (scope) => {
15
15
  const knex = scope.make("jskit.database.knex");
16
- return createUserSettingsRepository(knex);
16
+ return createUserProfilesRepository(knex);
17
17
  });
18
18
  }
19
19