@jskit-ai/users-core 0.1.48 → 0.1.50

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 (87) hide show
  1. package/package.descriptor.mjs +7 -7
  2. package/package.json +7 -17
  3. package/src/server/common/services/authProfileSyncService.js +28 -7
  4. package/src/server/common/support/realtimeServiceEvents.js +1 -59
  5. package/src/server/profileSyncLifecycleContributorRegistry.js +56 -0
  6. package/src/server/registerUsersBootstrap.js +0 -1
  7. package/src/server/registerUsersCore.js +2 -14
  8. package/src/server/usersBootstrapContributor.js +2 -64
  9. package/src/shared/index.js +2 -99
  10. package/src/shared/settings.js +1 -119
  11. package/test/authProfileSyncService.test.js +19 -10
  12. package/test/registerServiceRealtimeEvents.test.js +0 -86
  13. package/test/registerUsersCore.test.js +6 -15
  14. package/test/repositoryContracts.test.js +1 -9
  15. package/test/resourcesCanonical.test.js +0 -16
  16. package/test/settingsFieldRegistriesSingleton.test.js +0 -5
  17. package/test/usersBootstrapContributor.test.js +2 -26
  18. package/test/usersRouteResources.test.js +0 -16
  19. package/src/server/UsersWorkspacesServiceProvider.js +0 -44
  20. package/src/server/common/contributors/workspaceActionContextContributor.js +0 -88
  21. package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +0 -34
  22. package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +0 -78
  23. package/src/server/common/formatters/workspaceFormatter.js +0 -53
  24. package/src/server/common/repositories/workspaceInvitesRepository.js +0 -208
  25. package/src/server/common/repositories/workspaceMembershipsRepository.js +0 -190
  26. package/src/server/common/repositories/workspacesRepository.js +0 -202
  27. package/src/server/common/services/workspaceContextService.js +0 -281
  28. package/src/server/common/support/workspaceRoutePaths.js +0 -17
  29. package/src/server/common/validators/routeParamsValidator.js +0 -62
  30. package/src/server/registerWorkspaceBootstrap.js +0 -27
  31. package/src/server/registerWorkspaceCore.js +0 -73
  32. package/src/server/registerWorkspaceRepositories.js +0 -26
  33. package/src/server/support/resolveWorkspace.js +0 -16
  34. package/src/server/support/workspaceActionSurfaces.js +0 -118
  35. package/src/server/support/workspaceInvitationsPolicy.js +0 -45
  36. package/src/server/support/workspaceRouteInput.js +0 -22
  37. package/src/server/workspaceBootstrapContributor.js +0 -212
  38. package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +0 -133
  39. package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
  40. package/src/server/workspaceDirectory/workspaceDirectoryActions.js +0 -133
  41. package/src/server/workspaceMembers/bootWorkspaceMembers.js +0 -236
  42. package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -108
  43. package/src/server/workspaceMembers/workspaceMembersActions.js +0 -186
  44. package/src/server/workspaceMembers/workspaceMembersService.js +0 -222
  45. package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +0 -62
  46. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -119
  47. package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +0 -74
  48. package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +0 -138
  49. package/src/server/workspaceSettings/bootWorkspaceSettings.js +0 -76
  50. package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -62
  51. package/src/server/workspaceSettings/workspaceSettingsActions.js +0 -72
  52. package/src/server/workspaceSettings/workspaceSettingsRepository.js +0 -154
  53. package/src/server/workspaceSettings/workspaceSettingsService.js +0 -66
  54. package/src/shared/resources/workspaceMembersResource.js +0 -354
  55. package/src/shared/resources/workspacePendingInvitationsResource.js +0 -82
  56. package/src/shared/resources/workspaceResource.js +0 -176
  57. package/src/shared/resources/workspaceSettingsFields.js +0 -59
  58. package/src/shared/resources/workspaceSettingsResource.js +0 -169
  59. package/src/shared/roles.js +0 -161
  60. package/src/shared/support/usersApiPaths.js +0 -43
  61. package/src/shared/support/usersVisibility.js +0 -42
  62. package/src/shared/support/workspacePathModel.js +0 -145
  63. package/src/shared/tenancyMode.js +0 -35
  64. package/src/shared/tenancyProfile.js +0 -73
  65. package/test/registerWorkspaceDirectory.test.js +0 -31
  66. package/test/registerWorkspaceSettings.test.js +0 -40
  67. package/test/roles.test.js +0 -159
  68. package/test/tenancyProfile.test.js +0 -67
  69. package/test/usersApiPaths.test.js +0 -49
  70. package/test/usersRouteValidators.test.js +0 -49
  71. package/test/usersVisibility.test.js +0 -27
  72. package/test/workspaceActionContextContributor.test.js +0 -344
  73. package/test/workspaceActionSurfaces.test.js +0 -85
  74. package/test/workspaceAuthPolicyContextResolver.test.js +0 -119
  75. package/test/workspaceBootstrapContributor.test.js +0 -154
  76. package/test/workspaceInvitationsPolicy.test.js +0 -71
  77. package/test/workspaceInvitesRepository.test.js +0 -111
  78. package/test/workspaceMembersService.test.js +0 -398
  79. package/test/workspacePathModel.test.js +0 -93
  80. package/test/workspacePendingInvitationsResource.test.js +0 -38
  81. package/test/workspacePendingInvitationsService.test.js +0 -151
  82. package/test/workspaceRouteVisibilityResolver.test.js +0 -83
  83. package/test/workspaceService.test.js +0 -546
  84. package/test/workspaceSettingsActions.test.js +0 -52
  85. package/test/workspaceSettingsRepository.test.js +0 -202
  86. package/test/workspaceSettingsResource.test.js +0 -169
  87. package/test/workspaceSettingsService.test.js +0 -140
@@ -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.48",
4
+ version: "0.1.50",
5
5
  kind: "runtime",
6
6
  description: "Users/account runtime plus HTTP routes for account features.",
7
7
  dependsOn: [
@@ -48,7 +48,7 @@ export default Object.freeze({
48
48
  },
49
49
  {
50
50
  subpath: "./shared",
51
- summary: "Exports shared users settings and tenancy utilities."
51
+ summary: "Exports shared users settings resources and defaults."
52
52
  },
53
53
  {
54
54
  subpath: "./client",
@@ -128,11 +128,11 @@ export default Object.freeze({
128
128
  mutations: {
129
129
  dependencies: {
130
130
  runtime: {
131
- "@jskit-ai/auth-core": "0.1.37",
132
- "@jskit-ai/database-runtime": "0.1.38",
133
- "@jskit-ai/http-runtime": "0.1.37",
134
- "@jskit-ai/kernel": "0.1.38",
135
- "@jskit-ai/uploads-runtime": "0.1.16",
131
+ "@jskit-ai/auth-core": "0.1.39",
132
+ "@jskit-ai/database-runtime": "0.1.40",
133
+ "@jskit-ai/http-runtime": "0.1.39",
134
+ "@jskit-ai/kernel": "0.1.40",
135
+ "@jskit-ai/uploads-runtime": "0.1.18",
136
136
  "@fastify/type-provider-typebox": "^6.1.0",
137
137
  typebox: "^1.0.81"
138
138
  },
package/package.json CHANGED
@@ -1,33 +1,23 @@
1
1
  {
2
2
  "name": "@jskit-ai/users-core",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
7
7
  },
8
8
  "exports": {
9
- "./server/UsersWorkspacesServiceProvider": "./src/server/UsersWorkspacesServiceProvider.js",
10
- "./server/support/workspaceRouteInput": "./src/server/support/workspaceRouteInput.js",
11
- "./server/support/resolveWorkspace": "./src/server/support/resolveWorkspace.js",
12
- "./server/validators/routeParamsValidator": "./src/server/common/validators/routeParamsValidator.js",
9
+ "./server/profileSyncLifecycleContributorRegistry": "./src/server/profileSyncLifecycleContributorRegistry.js",
13
10
  "./shared/settings": "./src/shared/settings.js",
14
- "./shared/tenancyProfile": "./src/shared/tenancyProfile.js",
15
- "./shared/support/usersVisibility": "./src/shared/support/usersVisibility.js",
16
- "./shared/support/workspacePathModel": "./src/shared/support/workspacePathModel.js",
17
- "./shared/support/usersApiPaths": "./src/shared/support/usersApiPaths.js",
18
- "./shared/resources/workspaceResource": "./src/shared/resources/workspaceResource.js",
19
- "./shared/resources/workspaceSettingsResource": "./src/shared/resources/workspaceSettingsResource.js",
20
- "./shared/resources/workspaceSettingsFields": "./src/shared/resources/workspaceSettingsFields.js",
21
11
  "./shared/resources/userProfileResource": "./src/shared/resources/userProfileResource.js",
22
12
  "./shared/resources/userSettingsFields": "./src/shared/resources/userSettingsFields.js",
23
13
  "./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
24
14
  },
25
15
  "dependencies": {
26
- "@jskit-ai/auth-core": "0.1.37",
27
- "@jskit-ai/database-runtime": "0.1.38",
28
- "@jskit-ai/http-runtime": "0.1.37",
29
- "@jskit-ai/kernel": "0.1.38",
30
- "@jskit-ai/uploads-runtime": "0.1.16",
16
+ "@jskit-ai/auth-core": "0.1.39",
17
+ "@jskit-ai/database-runtime": "0.1.40",
18
+ "@jskit-ai/http-runtime": "0.1.39",
19
+ "@jskit-ai/kernel": "0.1.40",
20
+ "@jskit-ai/uploads-runtime": "0.1.18",
31
21
  "@fastify/type-provider-typebox": "^6.1.0",
32
22
  "typebox": "^1.0.81"
33
23
  }
@@ -54,7 +54,17 @@ function requireSynchronizedProfile(profile) {
54
54
  throw new Error("Profile synchronization failed.");
55
55
  }
56
56
 
57
- function createService({ usersRepository, workspaceProvisioningService = null, userSettingsRepository = null } = {}) {
57
+ function normalizeLifecycleContributors(entries = []) {
58
+ if (!Array.isArray(entries)) {
59
+ return [];
60
+ }
61
+
62
+ return entries.filter(
63
+ (entry) => entry && typeof entry === "object" && typeof entry.afterIdentityProfileSynced === "function"
64
+ );
65
+ }
66
+
67
+ function createService({ usersRepository, lifecycleContributors = [], userSettingsRepository = null } = {}) {
58
68
  if (!usersRepository || typeof usersRepository.findByIdentity !== "function") {
59
69
  throw new Error("authProfileSyncService requires usersRepository.findByIdentity().");
60
70
  }
@@ -68,6 +78,8 @@ function createService({ usersRepository, workspaceProvisioningService = null, u
68
78
  throw new Error("authProfileSyncService requires userSettingsRepository.ensureForUserId().");
69
79
  }
70
80
 
81
+ const normalizedLifecycleContributors = normalizeLifecycleContributors(lifecycleContributors);
82
+
71
83
  async function findByIdentity(identityLike, options = {}) {
72
84
  const normalized = buildNormalizedIdentityKey(identityLike);
73
85
  return usersRepository.findByIdentity(
@@ -99,21 +111,30 @@ function createService({ usersRepository, workspaceProvisioningService = null, u
99
111
  const runSync = async (trx = null) => {
100
112
  const operationOptions = trx ? { ...options, trx } : options;
101
113
  const existing = await findByIdentity(normalized, operationOptions);
114
+ let created = false;
102
115
  if (!profileNeedsUpdate(existing, normalized)) {
103
116
  const synchronizedProfile = requireSynchronizedProfile(existing);
104
117
  await userSettingsRepository.ensureForUserId(synchronizedProfile.id, operationOptions);
118
+ for (const contributor of normalizedLifecycleContributors) {
119
+ await contributor.afterIdentityProfileSynced({
120
+ profile: synchronizedProfile,
121
+ created,
122
+ options: operationOptions
123
+ });
124
+ }
105
125
  return synchronizedProfile;
106
126
  }
107
127
 
108
128
  const upserted = await upsertByIdentity(normalized, operationOptions);
109
129
  const synchronizedProfile = requireSynchronizedProfile(upserted);
110
130
  await userSettingsRepository.ensureForUserId(synchronizedProfile.id, operationOptions);
111
- if (
112
- !existing &&
113
- workspaceProvisioningService &&
114
- typeof workspaceProvisioningService.provisionWorkspaceForNewUser === "function"
115
- ) {
116
- await workspaceProvisioningService.provisionWorkspaceForNewUser(synchronizedProfile, operationOptions);
131
+ created = !existing;
132
+ for (const contributor of normalizedLifecycleContributors) {
133
+ await contributor.afterIdentityProfileSynced({
134
+ profile: synchronizedProfile,
135
+ created,
136
+ options: operationOptions
137
+ });
117
138
  }
118
139
 
119
140
  return synchronizedProfile;
@@ -5,12 +5,6 @@ function resolveActorScopedEntityId({ options } = {}) {
5
5
  return normalizeRecordId(options?.context?.actor?.id, { fallback: "" });
6
6
  }
7
7
 
8
- function resolveWorkspaceSlugPayload({ args } = {}) {
9
- return {
10
- workspaceSlug: String(args?.[0]?.slug || "").trim()
11
- };
12
- }
13
-
14
8
  const ACCOUNT_SETTINGS_AND_BOOTSTRAP_EVENTS = deepFreeze([
15
9
  {
16
10
  type: "entity.changed",
@@ -36,56 +30,4 @@ const ACCOUNT_SETTINGS_AND_BOOTSTRAP_EVENTS = deepFreeze([
36
30
  }
37
31
  ]);
38
32
 
39
- function createWorkspaceEntityAndBootstrapEvents({
40
- workspaceEntity,
41
- workspaceOperation,
42
- workspaceRealtimeEvent,
43
- workspaceEntityId = ({ args }) => args?.[0]?.id,
44
- bootstrapEntityId = ({ args }) => args?.[0]?.id,
45
- bootstrapAudience = "event_scope"
46
- } = {}) {
47
- const normalizedWorkspaceEntity = String(workspaceEntity || "").trim();
48
- const normalizedWorkspaceOperation = String(workspaceOperation || "")
49
- .trim()
50
- .toLowerCase();
51
- const normalizedWorkspaceRealtimeEvent = String(workspaceRealtimeEvent || "").trim();
52
- if (!normalizedWorkspaceEntity || !normalizedWorkspaceOperation || !normalizedWorkspaceRealtimeEvent) {
53
- throw new Error(
54
- "createWorkspaceEntityAndBootstrapEvents requires workspaceEntity, workspaceOperation, and workspaceRealtimeEvent."
55
- );
56
- }
57
- if (typeof workspaceEntityId !== "function") {
58
- throw new Error("createWorkspaceEntityAndBootstrapEvents requires workspaceEntityId to be a function.");
59
- }
60
- if (typeof bootstrapEntityId !== "function") {
61
- throw new Error("createWorkspaceEntityAndBootstrapEvents requires bootstrapEntityId to be a function.");
62
- }
63
-
64
- return deepFreeze([
65
- {
66
- type: "entity.changed",
67
- source: "workspace",
68
- entity: normalizedWorkspaceEntity,
69
- operation: normalizedWorkspaceOperation,
70
- entityId: (payload = {}) => normalizeRecordId(workspaceEntityId(payload), { fallback: "" }),
71
- realtime: {
72
- event: normalizedWorkspaceRealtimeEvent,
73
- payload: resolveWorkspaceSlugPayload,
74
- audience: "event_scope"
75
- }
76
- },
77
- {
78
- type: "entity.changed",
79
- source: "users",
80
- entity: "bootstrap",
81
- operation: "updated",
82
- entityId: (payload = {}) => normalizeRecordId(bootstrapEntityId(payload), { fallback: "" }),
83
- realtime: {
84
- event: "users.bootstrap.changed",
85
- audience: bootstrapAudience
86
- }
87
- }
88
- ]);
89
- }
90
-
91
- export { ACCOUNT_SETTINGS_AND_BOOTSTRAP_EVENTS, createWorkspaceEntityAndBootstrapEvents };
33
+ export { ACCOUNT_SETTINGS_AND_BOOTSTRAP_EVENTS };
@@ -0,0 +1,56 @@
1
+ import { registerTaggedSingleton, resolveTaggedEntries } from "@jskit-ai/kernel/server/registries";
2
+
3
+ const PROFILE_SYNC_LIFECYCLE_CONTRIBUTOR_TAG = "jskit.users.profileSync.lifecycleContributors";
4
+
5
+ function normalizeProfileSyncLifecycleContributor(entry) {
6
+ if (typeof entry === "function") {
7
+ return Object.freeze({
8
+ contributorId: String(entry.name || "anonymous"),
9
+ order: 0,
10
+ afterIdentityProfileSynced: entry
11
+ });
12
+ }
13
+
14
+ if (!entry || typeof entry !== "object" || typeof entry.afterIdentityProfileSynced !== "function") {
15
+ return null;
16
+ }
17
+
18
+ const contributorId = String(entry.contributorId || "anonymous");
19
+ const order = Number.isFinite(entry.order) ? Number(entry.order) : 0;
20
+
21
+ return Object.freeze({
22
+ ...entry,
23
+ contributorId,
24
+ order,
25
+ afterIdentityProfileSynced: entry.afterIdentityProfileSynced
26
+ });
27
+ }
28
+
29
+ function registerProfileSyncLifecycleContributor(app, token, factory) {
30
+ registerTaggedSingleton(app, token, factory, PROFILE_SYNC_LIFECYCLE_CONTRIBUTOR_TAG, {
31
+ context: "registerProfileSyncLifecycleContributor"
32
+ });
33
+ }
34
+
35
+ function resolveProfileSyncLifecycleContributors(scope) {
36
+ return resolveTaggedEntries(scope, PROFILE_SYNC_LIFECYCLE_CONTRIBUTOR_TAG)
37
+ .map((entry, index) => ({
38
+ contributor: normalizeProfileSyncLifecycleContributor(entry),
39
+ index
40
+ }))
41
+ .filter((entry) => Boolean(entry.contributor))
42
+ .sort((left, right) => {
43
+ if (left.contributor.order !== right.contributor.order) {
44
+ return left.contributor.order - right.contributor.order;
45
+ }
46
+
47
+ return left.index - right.index;
48
+ })
49
+ .map((entry) => entry.contributor);
50
+ }
51
+
52
+ export {
53
+ PROFILE_SYNC_LIFECYCLE_CONTRIBUTOR_TAG,
54
+ registerProfileSyncLifecycleContributor,
55
+ resolveProfileSyncLifecycleContributors
56
+ };
@@ -12,7 +12,6 @@ function registerUsersBootstrap(app) {
12
12
  usersRepository: scope.make("usersRepository"),
13
13
  userSettingsRepository: scope.make("userSettingsRepository"),
14
14
  appConfig: resolveAppConfig(scope),
15
- tenancyProfile: scope.make("users.tenancy.profile"),
16
15
  authService: scope.make("authService")
17
16
  });
18
17
  });
@@ -1,30 +1,18 @@
1
- import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
2
- import { resolveTenancyProfile } from "../shared/tenancyProfile.js";
3
1
  import { createService as createAuthProfileSyncService } from "./common/services/authProfileSyncService.js";
4
- import { registerUsersCoreActionSurfaceSources } from "./support/workspaceActionSurfaces.js";
2
+ import { resolveProfileSyncLifecycleContributors } from "./profileSyncLifecycleContributorRegistry.js";
5
3
 
6
4
  function registerUsersCore(app) {
7
5
  if (!app || typeof app.singleton !== "function") {
8
6
  throw new Error("registerUsersCore requires application singleton().");
9
7
  }
10
8
 
11
- registerUsersCoreActionSurfaceSources(app);
12
-
13
9
  app.singleton("users.profile.sync.service", (scope) => {
14
10
  return createAuthProfileSyncService({
15
11
  usersRepository: scope.make("usersRepository"),
16
12
  userSettingsRepository: scope.make("userSettingsRepository"),
17
- workspaceProvisioningService:
18
- typeof scope.has === "function" && scope.has("users.workspace.service")
19
- ? scope.make("users.workspace.service")
20
- : null
13
+ lifecycleContributors: resolveProfileSyncLifecycleContributors(scope)
21
14
  });
22
15
  });
23
-
24
- app.singleton("users.tenancy.profile", (scope) => {
25
- const appConfig = resolveAppConfig(scope);
26
- return resolveTenancyProfile(appConfig);
27
- });
28
16
  }
29
17
 
30
18
  export { registerUsersCore };
@@ -2,15 +2,6 @@ import { AppError } from "@jskit-ai/kernel/server/runtime";
2
2
  import { requireServiceMethod } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
3
3
  import { normalizeLowerText, normalizeText } from "@jskit-ai/kernel/shared/actions/textNormalization";
4
4
  import { normalizeObject } from "@jskit-ai/kernel/shared/support/normalize";
5
- import {
6
- TENANCY_MODE_NONE,
7
- TENANCY_MODE_PERSONAL,
8
- TENANCY_MODE_WORKSPACES,
9
- WORKSPACE_SLUG_POLICY_NONE,
10
- WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
11
- WORKSPACE_SLUG_POLICY_USER_SELECTED,
12
- resolveTenancyProfile
13
- } from "../shared/tenancyProfile.js";
14
5
  import { accountAvatarFormatter } from "./common/formatters/accountAvatarFormatter.js";
15
6
  import { authenticatedUserValidator } from "./common/validators/authenticatedUserValidator.js";
16
7
  import { userSettingsFields } from "../shared/resources/userSettingsFields.js";
@@ -56,10 +47,8 @@ function normalizeBoolean(value, fallback) {
56
47
  return fallback;
57
48
  }
58
49
 
59
- function resolveAppState(appConfig = {}, { workspaceInvitationsEnabled = false } = {}) {
50
+ function resolveAppState(appConfig = {}) {
60
51
  const features = {
61
- workspaceSwitching: normalizeBoolean(appConfig.workspaceSwitching, false),
62
- workspaceInvites: workspaceInvitationsEnabled === true,
63
52
  assistantEnabled: normalizeBoolean(appConfig.assistantEnabled, false),
64
53
  assistantRequiredPermission: normalizeText(appConfig.assistantRequiredPermission),
65
54
  socialEnabled: normalizeBoolean(appConfig.socialEnabled, false),
@@ -71,54 +60,14 @@ function resolveAppState(appConfig = {}, { workspaceInvitationsEnabled = false }
71
60
  };
72
61
  }
73
62
 
74
- function normalizeSlugPolicy(value = "") {
75
- const normalizedValue = normalizeLowerText(value);
76
- if (
77
- normalizedValue === WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME ||
78
- normalizedValue === WORKSPACE_SLUG_POLICY_USER_SELECTED
79
- ) {
80
- return normalizedValue;
81
- }
82
- return WORKSPACE_SLUG_POLICY_NONE;
83
- }
84
-
85
- function isSupportedTenancyMode(value = "") {
86
- return value === TENANCY_MODE_NONE || value === TENANCY_MODE_PERSONAL || value === TENANCY_MODE_WORKSPACES;
87
- }
88
-
89
- function resolveBootstrapTenancyProfile(tenancyProfile = null, appConfig = {}) {
90
- const fallback = resolveTenancyProfile(appConfig);
91
- const source = tenancyProfile && typeof tenancyProfile === "object" ? tenancyProfile : fallback;
92
- const mode = isSupportedTenancyMode(source?.mode) ? source.mode : fallback.mode;
93
- const workspace = source?.workspace && typeof source.workspace === "object" ? source.workspace : fallback.workspace;
94
-
95
- return Object.freeze({
96
- mode,
97
- workspace: Object.freeze({
98
- enabled: workspace.enabled === true,
99
- autoProvision: workspace.autoProvision === true,
100
- allowSelfCreate: workspace.allowSelfCreate === true,
101
- slugPolicy: normalizeSlugPolicy(workspace.slugPolicy)
102
- })
103
- });
104
- }
105
-
106
- function createAnonymousBootstrapPayload({ appState, tenancyProfile, surfaceAccess = {} }) {
63
+ function createAnonymousBootstrapPayload({ appState, surfaceAccess = {} }) {
107
64
  return {
108
65
  session: {
109
66
  authenticated: false
110
67
  },
111
68
  profile: null,
112
- tenancy: tenancyProfile,
113
69
  app: appState,
114
- workspaces: [],
115
- pendingInvites: [],
116
- activeWorkspace: null,
117
- membership: null,
118
- requestedWorkspace: null,
119
- permissions: [],
120
70
  surfaceAccess: normalizeObject(surfaceAccess),
121
- workspaceSettings: null,
122
71
  userSettings: null,
123
72
  requestMeta: {
124
73
  hasRequest: false
@@ -151,12 +100,10 @@ function createUsersBootstrapContributor({
151
100
  usersRepository,
152
101
  userSettingsRepository,
153
102
  appConfig = {},
154
- tenancyProfile = null,
155
103
  authService
156
104
  } = {}) {
157
105
  const contributorId = "users.bootstrap";
158
106
  const appState = resolveAppState(appConfig);
159
- const resolvedTenancyProfile = resolveBootstrapTenancyProfile(tenancyProfile, appConfig);
160
107
 
161
108
  requireServiceMethod(usersRepository, "findById", contributorId, {
162
109
  serviceLabel: "usersRepository"
@@ -187,7 +134,6 @@ function createUsersBootstrapContributor({
187
134
  const inheritedSurfaceAccess = normalizeObject(existingPayload?.surfaceAccess);
188
135
  let payload = createAnonymousBootstrapPayload({
189
136
  appState,
190
- tenancyProfile: resolvedTenancyProfile,
191
137
  surfaceAccess: inheritedSurfaceAccess
192
138
  });
193
139
 
@@ -205,16 +151,8 @@ function createUsersBootstrapContributor({
205
151
  email: latestProfile.email,
206
152
  avatar: accountAvatarFormatter(latestProfile, userSettings)
207
153
  },
208
- tenancy: resolvedTenancyProfile,
209
154
  app: appState,
210
- workspaces: [],
211
- pendingInvites: [],
212
- activeWorkspace: null,
213
- membership: null,
214
- requestedWorkspace: null,
215
- permissions: [],
216
155
  surfaceAccess: inheritedSurfaceAccess,
217
- workspaceSettings: null,
218
156
  userSettings: mapUserSettingsBootstrap(userSettings),
219
157
  requestMeta: {
220
158
  hasRequest: Boolean(request)
@@ -1,107 +1,10 @@
1
- import {
2
- OWNER_ROLE_ID,
3
- ADMIN_ROLE_ID,
4
- MEMBER_ROLE_ID,
5
- resolveRolePermissions,
6
- listRoleDescriptors,
7
- hasPermission
8
- } from "./roles.js";
9
-
10
- import {
11
- DEFAULT_WORKSPACE_DARK_PALETTE,
12
- DEFAULT_WORKSPACE_LIGHT_PALETTE,
13
- DEFAULT_WORKSPACE_COLOR,
14
- DEFAULT_USER_SETTINGS,
15
- coerceWorkspaceColor,
16
- coerceWorkspaceThemeColor,
17
- coerceWorkspaceSecondaryColor,
18
- coerceWorkspaceSurfaceColor,
19
- coerceWorkspaceSurfaceVariantColor,
20
- normalizeWorkspaceHexColor,
21
- normalizeWorkspaceThemeMode,
22
- resolveWorkspaceThemeDefaultPalette,
23
- resolveWorkspaceThemePalettes,
24
- WORKSPACE_THEME_MODE_DARK,
25
- WORKSPACE_THEME_MODE_LIGHT,
26
- resolveWorkspaceThemePalette
27
- } from "./settings.js";
28
- import {
29
- TENANCY_MODE_NONE,
30
- TENANCY_MODE_PERSONAL,
31
- TENANCY_MODE_WORKSPACES,
32
- normalizeTenancyMode,
33
- WORKSPACE_SLUG_POLICY_NONE,
34
- WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
35
- WORKSPACE_SLUG_POLICY_USER_SELECTED,
36
- resolveTenancyProfile,
37
- isWorkspacesTenancyMode
38
- } from "./tenancyProfile.js";
1
+ import { DEFAULT_USER_SETTINGS } from "./settings.js";
39
2
 
40
3
  const USERS_SHARED_API = Object.freeze({
41
- OWNER_ROLE_ID,
42
- ADMIN_ROLE_ID,
43
- MEMBER_ROLE_ID,
44
- resolveRolePermissions,
45
- listRoleDescriptors,
46
- hasPermission,
47
- DEFAULT_WORKSPACE_LIGHT_PALETTE,
48
- DEFAULT_WORKSPACE_DARK_PALETTE,
49
- DEFAULT_WORKSPACE_COLOR,
50
- DEFAULT_USER_SETTINGS,
51
- coerceWorkspaceColor,
52
- coerceWorkspaceThemeColor,
53
- coerceWorkspaceSecondaryColor,
54
- coerceWorkspaceSurfaceColor,
55
- coerceWorkspaceSurfaceVariantColor,
56
- WORKSPACE_THEME_MODE_LIGHT,
57
- WORKSPACE_THEME_MODE_DARK,
58
- normalizeWorkspaceThemeMode,
59
- resolveWorkspaceThemeDefaultPalette,
60
- resolveWorkspaceThemePalettes,
61
- normalizeWorkspaceHexColor,
62
- resolveWorkspaceThemePalette,
63
- TENANCY_MODE_NONE,
64
- TENANCY_MODE_PERSONAL,
65
- TENANCY_MODE_WORKSPACES,
66
- normalizeTenancyMode,
67
- WORKSPACE_SLUG_POLICY_NONE,
68
- WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
69
- WORKSPACE_SLUG_POLICY_USER_SELECTED,
70
- resolveTenancyProfile,
71
- isWorkspacesTenancyMode
4
+ DEFAULT_USER_SETTINGS
72
5
  });
73
6
 
74
7
  export {
75
- OWNER_ROLE_ID,
76
- ADMIN_ROLE_ID,
77
- MEMBER_ROLE_ID,
78
- resolveRolePermissions,
79
- listRoleDescriptors,
80
- hasPermission,
81
- DEFAULT_WORKSPACE_LIGHT_PALETTE,
82
- DEFAULT_WORKSPACE_DARK_PALETTE,
83
- DEFAULT_WORKSPACE_COLOR,
84
8
  DEFAULT_USER_SETTINGS,
85
- coerceWorkspaceColor,
86
- coerceWorkspaceThemeColor,
87
- coerceWorkspaceSecondaryColor,
88
- coerceWorkspaceSurfaceColor,
89
- coerceWorkspaceSurfaceVariantColor,
90
- WORKSPACE_THEME_MODE_LIGHT,
91
- WORKSPACE_THEME_MODE_DARK,
92
- normalizeWorkspaceThemeMode,
93
- resolveWorkspaceThemeDefaultPalette,
94
- resolveWorkspaceThemePalettes,
95
- normalizeWorkspaceHexColor,
96
- resolveWorkspaceThemePalette,
97
- TENANCY_MODE_NONE,
98
- TENANCY_MODE_PERSONAL,
99
- TENANCY_MODE_WORKSPACES,
100
- normalizeTenancyMode,
101
- WORKSPACE_SLUG_POLICY_NONE,
102
- WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
103
- WORKSPACE_SLUG_POLICY_USER_SELECTED,
104
- resolveTenancyProfile,
105
- isWorkspacesTenancyMode,
106
9
  USERS_SHARED_API
107
10
  };
@@ -1,23 +1,3 @@
1
- const WORKSPACE_THEME_MODE_LIGHT = "light";
2
- const WORKSPACE_THEME_MODE_DARK = "dark";
3
- const HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
4
-
5
- const DEFAULT_WORKSPACE_LIGHT_PALETTE = Object.freeze({
6
- color: "#1867C0",
7
- secondaryColor: "#48A9A6",
8
- surfaceColor: "#FFFFFF",
9
- surfaceVariantColor: "#424242"
10
- });
11
-
12
- const DEFAULT_WORKSPACE_DARK_PALETTE = Object.freeze({
13
- color: "#2196F3",
14
- secondaryColor: "#54B6B2",
15
- surfaceColor: "#212121",
16
- surfaceVariantColor: "#C8C8C8"
17
- });
18
-
19
- const DEFAULT_WORKSPACE_COLOR = DEFAULT_WORKSPACE_LIGHT_PALETTE.color;
20
-
21
1
  const DEFAULT_USER_SETTINGS = Object.freeze({
22
2
  theme: "system",
23
3
  locale: "en",
@@ -32,104 +12,6 @@ const DEFAULT_USER_SETTINGS = Object.freeze({
32
12
  passwordSignInEnabled: true,
33
13
  passwordSetupRequired: false
34
14
  });
35
-
36
- function normalizeWorkspaceHexColor(value) {
37
- const normalized = String(value || "").trim();
38
- if (!HEX_COLOR_PATTERN.test(normalized)) {
39
- return "";
40
- }
41
- return normalized.toUpperCase();
42
- }
43
-
44
- function coerceWorkspaceColor(value) {
45
- return normalizeWorkspaceHexColor(value) || DEFAULT_WORKSPACE_COLOR;
46
- }
47
-
48
- function normalizeWorkspaceThemeMode(value = "") {
49
- const normalized = String(value || "").trim().toLowerCase();
50
- if (normalized === WORKSPACE_THEME_MODE_DARK) {
51
- return WORKSPACE_THEME_MODE_DARK;
52
- }
53
- return WORKSPACE_THEME_MODE_LIGHT;
54
- }
55
-
56
- function resolveWorkspaceThemeDefaultPalette(mode = WORKSPACE_THEME_MODE_LIGHT) {
57
- const normalizedMode = normalizeWorkspaceThemeMode(mode);
58
- return normalizedMode === WORKSPACE_THEME_MODE_DARK
59
- ? DEFAULT_WORKSPACE_DARK_PALETTE
60
- : DEFAULT_WORKSPACE_LIGHT_PALETTE;
61
- }
62
-
63
- function coerceWorkspaceThemeColor(value, fallbackColor = DEFAULT_WORKSPACE_COLOR) {
64
- return normalizeWorkspaceHexColor(value) || normalizeWorkspaceHexColor(fallbackColor) || DEFAULT_WORKSPACE_COLOR;
65
- }
66
-
67
- function coerceWorkspaceSecondaryColor(value, { mode = WORKSPACE_THEME_MODE_LIGHT } = {}) {
68
- return coerceWorkspaceThemeColor(value, resolveWorkspaceThemeDefaultPalette(mode).secondaryColor);
69
- }
70
-
71
- function coerceWorkspaceSurfaceColor(value, { mode = WORKSPACE_THEME_MODE_LIGHT } = {}) {
72
- return coerceWorkspaceThemeColor(value, resolveWorkspaceThemeDefaultPalette(mode).surfaceColor);
73
- }
74
-
75
- function coerceWorkspaceSurfaceVariantColor(value, { mode = WORKSPACE_THEME_MODE_LIGHT } = {}) {
76
- return coerceWorkspaceThemeColor(value, resolveWorkspaceThemeDefaultPalette(mode).surfaceVariantColor);
77
- }
78
-
79
- function resolveWorkspaceThemePalette(input = {}, { mode = WORKSPACE_THEME_MODE_LIGHT } = {}) {
80
- const source = input && typeof input === "object" ? input : {};
81
- const normalizedMode = normalizeWorkspaceThemeMode(mode);
82
- const paletteDefaults = resolveWorkspaceThemeDefaultPalette(normalizedMode);
83
-
84
- if (normalizedMode === WORKSPACE_THEME_MODE_DARK) {
85
- return Object.freeze({
86
- color: coerceWorkspaceThemeColor(source.darkPrimaryColor, paletteDefaults.color),
87
- secondaryColor: coerceWorkspaceThemeColor(source.darkSecondaryColor, paletteDefaults.secondaryColor),
88
- surfaceColor: coerceWorkspaceThemeColor(source.darkSurfaceColor, paletteDefaults.surfaceColor),
89
- surfaceVariantColor: coerceWorkspaceThemeColor(
90
- source.darkSurfaceVariantColor,
91
- paletteDefaults.surfaceVariantColor
92
- )
93
- });
94
- }
95
-
96
- return Object.freeze({
97
- color: coerceWorkspaceThemeColor(source.lightPrimaryColor, paletteDefaults.color),
98
- secondaryColor: coerceWorkspaceThemeColor(source.lightSecondaryColor, paletteDefaults.secondaryColor),
99
- surfaceColor: coerceWorkspaceThemeColor(source.lightSurfaceColor, paletteDefaults.surfaceColor),
100
- surfaceVariantColor: coerceWorkspaceThemeColor(
101
- source.lightSurfaceVariantColor,
102
- paletteDefaults.surfaceVariantColor
103
- )
104
- });
105
- }
106
-
107
- function resolveWorkspaceThemePalettes(input = {}) {
108
- return Object.freeze({
109
- light: resolveWorkspaceThemePalette(input, {
110
- mode: WORKSPACE_THEME_MODE_LIGHT
111
- }),
112
- dark: resolveWorkspaceThemePalette(input, {
113
- mode: WORKSPACE_THEME_MODE_DARK
114
- })
115
- });
116
- }
117
-
118
15
  export {
119
- DEFAULT_WORKSPACE_DARK_PALETTE,
120
- DEFAULT_WORKSPACE_LIGHT_PALETTE,
121
- DEFAULT_WORKSPACE_COLOR,
122
- DEFAULT_USER_SETTINGS,
123
- coerceWorkspaceColor,
124
- coerceWorkspaceThemeColor,
125
- coerceWorkspaceSecondaryColor,
126
- coerceWorkspaceSurfaceColor,
127
- coerceWorkspaceSurfaceVariantColor,
128
- normalizeWorkspaceHexColor,
129
- normalizeWorkspaceThemeMode,
130
- resolveWorkspaceThemeDefaultPalette,
131
- resolveWorkspaceThemePalettes,
132
- WORKSPACE_THEME_MODE_DARK,
133
- WORKSPACE_THEME_MODE_LIGHT,
134
- resolveWorkspaceThemePalette
16
+ DEFAULT_USER_SETTINGS
135
17
  };