@jskit-ai/users-core 0.1.47 → 0.1.49
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.
- package/package.descriptor.mjs +9 -46
- package/package.json +8 -19
- package/src/server/UsersCoreServiceProvider.js +0 -4
- package/src/server/common/registerCommonRepositories.js +0 -5
- package/src/server/common/services/authProfileSyncService.js +28 -7
- package/src/server/common/support/realtimeServiceEvents.js +1 -59
- package/src/server/profileSyncLifecycleContributorRegistry.js +56 -0
- package/src/server/registerUsersBootstrap.js +1 -3
- package/src/server/registerUsersCore.js +2 -14
- package/src/server/usersBootstrapContributor.js +10 -85
- package/src/shared/index.js +2 -99
- package/src/shared/settings.js +1 -119
- package/templates/migrations/users_core_generic_initial.cjs +0 -16
- package/test/authProfileSyncService.test.js +19 -10
- package/test/registerServiceRealtimeEvents.test.js +0 -94
- package/test/registerUsersCore.test.js +6 -19
- package/test/repositoryContracts.test.js +1 -11
- package/test/resourcesCanonical.test.js +1 -19
- package/test/settingsFieldRegistriesSingleton.test.js +0 -10
- package/test/usersBootstrapContributor.test.js +20 -38
- package/test/usersRouteRequestInputValidator.test.js +2 -43
- package/test/usersRouteResources.test.js +2 -20
- package/test-support/registerDefaultSettingsFields.js +0 -1
- package/src/server/UsersWorkspacesServiceProvider.js +0 -44
- package/src/server/common/contributors/workspaceActionContextContributor.js +0 -88
- package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +0 -34
- package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +0 -78
- package/src/server/common/formatters/workspaceFormatter.js +0 -53
- package/src/server/common/repositories/workspaceInvitesRepository.js +0 -208
- package/src/server/common/repositories/workspaceMembershipsRepository.js +0 -190
- package/src/server/common/repositories/workspacesRepository.js +0 -202
- package/src/server/common/services/workspaceContextService.js +0 -281
- package/src/server/common/support/workspaceRoutePaths.js +0 -17
- package/src/server/common/validators/routeParamsValidator.js +0 -62
- package/src/server/consoleSettings/bootConsoleSettingsRoutes.js +0 -63
- package/src/server/consoleSettings/consoleService.js +0 -36
- package/src/server/consoleSettings/consoleSettingsActions.js +0 -55
- package/src/server/consoleSettings/consoleSettingsRepository.js +0 -115
- package/src/server/consoleSettings/consoleSettingsService.js +0 -40
- package/src/server/consoleSettings/registerConsoleSettings.js +0 -56
- package/src/server/registerWorkspaceBootstrap.js +0 -27
- package/src/server/registerWorkspaceCore.js +0 -73
- package/src/server/registerWorkspaceRepositories.js +0 -26
- package/src/server/support/resolveWorkspace.js +0 -16
- package/src/server/support/workspaceActionSurfaces.js +0 -135
- package/src/server/support/workspaceInvitationsPolicy.js +0 -45
- package/src/server/support/workspaceRouteInput.js +0 -22
- package/src/server/workspaceBootstrapContributor.js +0 -211
- package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +0 -133
- package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
- package/src/server/workspaceDirectory/workspaceDirectoryActions.js +0 -133
- package/src/server/workspaceMembers/bootWorkspaceMembers.js +0 -236
- package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -108
- package/src/server/workspaceMembers/workspaceMembersActions.js +0 -186
- package/src/server/workspaceMembers/workspaceMembersService.js +0 -222
- package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +0 -62
- package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -119
- package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +0 -74
- package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +0 -138
- package/src/server/workspaceSettings/bootWorkspaceSettings.js +0 -76
- package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -62
- package/src/server/workspaceSettings/workspaceSettingsActions.js +0 -72
- package/src/server/workspaceSettings/workspaceSettingsRepository.js +0 -154
- package/src/server/workspaceSettings/workspaceSettingsService.js +0 -66
- package/src/shared/resources/consoleSettingsFields.js +0 -54
- package/src/shared/resources/consoleSettingsResource.js +0 -119
- package/src/shared/resources/workspaceMembersResource.js +0 -354
- package/src/shared/resources/workspacePendingInvitationsResource.js +0 -82
- package/src/shared/resources/workspaceResource.js +0 -176
- package/src/shared/resources/workspaceSettingsFields.js +0 -59
- package/src/shared/resources/workspaceSettingsResource.js +0 -169
- package/src/shared/roles.js +0 -161
- package/src/shared/support/usersApiPaths.js +0 -43
- package/src/shared/support/usersVisibility.js +0 -42
- package/src/shared/support/workspacePathModel.js +0 -145
- package/src/shared/tenancyMode.js +0 -35
- package/src/shared/tenancyProfile.js +0 -73
- package/templates/migrations/users_core_console_owner.cjs +0 -37
- package/templates/packages/main/src/shared/resources/consoleSettingsFields.js +0 -11
- package/test/consoleService.test.js +0 -57
- package/test/consoleSettingsService.test.js +0 -86
- package/test/registerWorkspaceDirectory.test.js +0 -31
- package/test/registerWorkspaceSettings.test.js +0 -40
- package/test/roles.test.js +0 -159
- package/test/tenancyProfile.test.js +0 -67
- package/test/usersApiPaths.test.js +0 -49
- package/test/usersRouteValidators.test.js +0 -49
- package/test/usersVisibility.test.js +0 -27
- package/test/workspaceActionContextContributor.test.js +0 -344
- package/test/workspaceActionSurfaces.test.js +0 -105
- package/test/workspaceAuthPolicyContextResolver.test.js +0 -119
- package/test/workspaceBootstrapContributor.test.js +0 -154
- package/test/workspaceInvitationsPolicy.test.js +0 -71
- package/test/workspaceInvitesRepository.test.js +0 -111
- package/test/workspaceMembersService.test.js +0 -398
- package/test/workspacePathModel.test.js +0 -93
- package/test/workspacePendingInvitationsResource.test.js +0 -38
- package/test/workspacePendingInvitationsService.test.js +0 -151
- package/test/workspaceRouteVisibilityResolver.test.js +0 -83
- package/test/workspaceService.test.js +0 -546
- package/test/workspaceSettingsActions.test.js +0 -52
- package/test/workspaceSettingsRepository.test.js +0 -202
- package/test/workspaceSettingsResource.test.js +0 -169
- package/test/workspaceSettingsService.test.js +0 -140
package/package.descriptor.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/users-core",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.49",
|
|
5
5
|
kind: "runtime",
|
|
6
|
-
description: "Users/account runtime plus HTTP routes for account
|
|
6
|
+
description: "Users/account runtime plus HTTP routes for account features.",
|
|
7
7
|
dependsOn: [
|
|
8
8
|
"@jskit-ai/auth-core",
|
|
9
9
|
"@jskit-ai/database-runtime",
|
|
@@ -44,11 +44,11 @@ export default Object.freeze({
|
|
|
44
44
|
{
|
|
45
45
|
subpath: "./server",
|
|
46
46
|
summary:
|
|
47
|
-
"Exports UsersCoreServiceProvider
|
|
47
|
+
"Exports UsersCoreServiceProvider plus account feature route registration modules and action definitions."
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
subpath: "./shared",
|
|
51
|
-
summary: "Exports shared users settings and
|
|
51
|
+
summary: "Exports shared users settings resources and defaults."
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
subpath: "./client",
|
|
@@ -121,16 +121,6 @@ export default Object.freeze({
|
|
|
121
121
|
method: "POST",
|
|
122
122
|
path: "/api/settings/security/logout-others",
|
|
123
123
|
summary: "Sign out from other active sessions."
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
method: "GET",
|
|
127
|
-
path: "/api/console/settings",
|
|
128
|
-
summary: "Get console settings."
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
method: "PATCH",
|
|
132
|
-
path: "/api/console/settings",
|
|
133
|
-
summary: "Update console settings."
|
|
134
124
|
}
|
|
135
125
|
]
|
|
136
126
|
}
|
|
@@ -138,11 +128,11 @@ export default Object.freeze({
|
|
|
138
128
|
mutations: {
|
|
139
129
|
dependencies: {
|
|
140
130
|
runtime: {
|
|
141
|
-
"@jskit-ai/auth-core": "0.1.
|
|
142
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
143
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
144
|
-
"@jskit-ai/kernel": "0.1.
|
|
145
|
-
"@jskit-ai/uploads-runtime": "0.1.
|
|
131
|
+
"@jskit-ai/auth-core": "0.1.38",
|
|
132
|
+
"@jskit-ai/database-runtime": "0.1.39",
|
|
133
|
+
"@jskit-ai/http-runtime": "0.1.38",
|
|
134
|
+
"@jskit-ai/kernel": "0.1.39",
|
|
135
|
+
"@jskit-ai/uploads-runtime": "0.1.17",
|
|
146
136
|
"@fastify/type-provider-typebox": "^6.1.0",
|
|
147
137
|
typebox: "^1.0.81"
|
|
148
138
|
},
|
|
@@ -171,23 +161,6 @@ export default Object.freeze({
|
|
|
171
161
|
category: "migration",
|
|
172
162
|
id: "users-core-profile-username-schema"
|
|
173
163
|
},
|
|
174
|
-
{
|
|
175
|
-
op: "install-migration",
|
|
176
|
-
from: "templates/migrations/users_core_console_owner.cjs",
|
|
177
|
-
toDir: "migrations",
|
|
178
|
-
extension: ".cjs",
|
|
179
|
-
reason: "Install console owner migration.",
|
|
180
|
-
category: "migration",
|
|
181
|
-
id: "users-core-console-owner-schema"
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
from: "templates/packages/main/src/shared/resources/consoleSettingsFields.js",
|
|
185
|
-
to: "packages/main/src/shared/resources/consoleSettingsFields.js",
|
|
186
|
-
preserveOnRemove: true,
|
|
187
|
-
reason: "Install app-owned console settings field definitions.",
|
|
188
|
-
category: "users-core",
|
|
189
|
-
id: "users-core-app-owned-console-settings-fields"
|
|
190
|
-
},
|
|
191
164
|
{
|
|
192
165
|
from: "templates/packages/main/src/shared/resources/userSettingsFields.js",
|
|
193
166
|
to: "packages/main/src/shared/resources/userSettingsFields.js",
|
|
@@ -207,16 +180,6 @@ export default Object.freeze({
|
|
|
207
180
|
category: "runtime-config",
|
|
208
181
|
id: "users-core-auth-profile-mode"
|
|
209
182
|
},
|
|
210
|
-
{
|
|
211
|
-
op: "append-text",
|
|
212
|
-
file: "packages/main/src/shared/index.js",
|
|
213
|
-
position: "top",
|
|
214
|
-
skipIfContains: "import \"./resources/consoleSettingsFields.js\";",
|
|
215
|
-
value: "import \"./resources/consoleSettingsFields.js\";\n",
|
|
216
|
-
reason: "Load app-owned console settings field definitions inside the main shared module.",
|
|
217
|
-
category: "users-core",
|
|
218
|
-
id: "users-core-main-shared-console-settings-field-import"
|
|
219
|
-
},
|
|
220
183
|
{
|
|
221
184
|
op: "append-text",
|
|
222
185
|
file: "packages/main/src/shared/index.js",
|
package/package.json
CHANGED
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
|
-
"./server/
|
|
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
|
-
"./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
|
|
24
|
-
"./shared/resources/consoleSettingsFields": "./src/shared/resources/consoleSettingsFields.js"
|
|
13
|
+
"./shared/resources/userSettingsResource": "./src/shared/resources/userSettingsResource.js"
|
|
25
14
|
},
|
|
26
15
|
"dependencies": {
|
|
27
|
-
"@jskit-ai/auth-core": "0.1.
|
|
28
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
29
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
30
|
-
"@jskit-ai/kernel": "0.1.
|
|
31
|
-
"@jskit-ai/uploads-runtime": "0.1.
|
|
16
|
+
"@jskit-ai/auth-core": "0.1.38",
|
|
17
|
+
"@jskit-ai/database-runtime": "0.1.39",
|
|
18
|
+
"@jskit-ai/http-runtime": "0.1.38",
|
|
19
|
+
"@jskit-ai/kernel": "0.1.39",
|
|
20
|
+
"@jskit-ai/uploads-runtime": "0.1.17",
|
|
32
21
|
"@fastify/type-provider-typebox": "^6.1.0",
|
|
33
22
|
"typebox": "^1.0.81"
|
|
34
23
|
}
|
|
@@ -3,7 +3,6 @@ import { bootAccountProfileRoutes } from "./accountProfile/bootAccountProfileRou
|
|
|
3
3
|
import { bootAccountPreferencesRoutes } from "./accountPreferences/bootAccountPreferencesRoutes.js";
|
|
4
4
|
import { bootAccountNotificationsRoutes } from "./accountNotifications/bootAccountNotificationsRoutes.js";
|
|
5
5
|
import { bootAccountSecurityRoutes } from "./accountSecurity/bootAccountSecurityRoutes.js";
|
|
6
|
-
import { bootConsoleSettingsRoutes } from "./consoleSettings/bootConsoleSettingsRoutes.js";
|
|
7
6
|
import { registerSharedApi } from "./common/registerSharedApi.js";
|
|
8
7
|
import { registerCommonRepositories } from "./common/registerCommonRepositories.js";
|
|
9
8
|
import { registerUsersCore } from "./registerUsersCore.js";
|
|
@@ -12,7 +11,6 @@ import { registerAccountPreferences } from "./accountPreferences/registerAccount
|
|
|
12
11
|
import { registerAccountNotifications } from "./accountNotifications/registerAccountNotifications.js";
|
|
13
12
|
import { registerAccountProfile } from "./accountProfile/registerAccountProfile.js";
|
|
14
13
|
import { registerAccountSecurity } from "./accountSecurity/registerAccountSecurity.js";
|
|
15
|
-
import { registerConsoleSettings } from "./consoleSettings/registerConsoleSettings.js";
|
|
16
14
|
|
|
17
15
|
class UsersCoreServiceProvider {
|
|
18
16
|
static id = "users.core";
|
|
@@ -29,7 +27,6 @@ class UsersCoreServiceProvider {
|
|
|
29
27
|
registerAccountPreferences(app);
|
|
30
28
|
registerAccountNotifications(app);
|
|
31
29
|
registerAccountSecurity(app);
|
|
32
|
-
registerConsoleSettings(app);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
async boot(app) {
|
|
@@ -37,7 +34,6 @@ class UsersCoreServiceProvider {
|
|
|
37
34
|
bootAccountPreferencesRoutes(app);
|
|
38
35
|
bootAccountNotificationsRoutes(app);
|
|
39
36
|
bootAccountSecurityRoutes(app);
|
|
40
|
-
bootConsoleSettingsRoutes(app);
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
39
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createRepository as createUsersRepository } from "./repositories/usersRepository.js";
|
|
2
2
|
import { createRepository as createUserSettingsRepository } from "./repositories/userSettingsRepository.js";
|
|
3
|
-
import { createRepository as createConsoleSettingsRepository } from "../consoleSettings/consoleSettingsRepository.js";
|
|
4
3
|
|
|
5
4
|
function registerCommonRepositories(app) {
|
|
6
5
|
if (!app || typeof app.singleton !== "function") {
|
|
@@ -16,10 +15,6 @@ function registerCommonRepositories(app) {
|
|
|
16
15
|
const knex = scope.make("jskit.database.knex");
|
|
17
16
|
return createUserSettingsRepository(knex);
|
|
18
17
|
});
|
|
19
|
-
app.singleton("consoleSettingsRepository", (scope) => {
|
|
20
|
-
const knex = scope.make("jskit.database.knex");
|
|
21
|
-
return createConsoleSettingsRepository(knex);
|
|
22
|
-
});
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
export { registerCommonRepositories };
|
|
@@ -54,7 +54,17 @@ function requireSynchronizedProfile(profile) {
|
|
|
54
54
|
throw new Error("Profile synchronization failed.");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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,9 +12,7 @@ function registerUsersBootstrap(app) {
|
|
|
12
12
|
usersRepository: scope.make("usersRepository"),
|
|
13
13
|
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
14
14
|
appConfig: resolveAppConfig(scope),
|
|
15
|
-
|
|
16
|
-
authService: scope.make("authService"),
|
|
17
|
-
consoleService: scope.has("consoleService") ? scope.make("consoleService") : null
|
|
15
|
+
authService: scope.make("authService")
|
|
18
16
|
});
|
|
19
17
|
});
|
|
20
18
|
}
|
|
@@ -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 {
|
|
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
|
-
|
|
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 };
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
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
|
-
import {
|
|
5
|
-
TENANCY_MODE_NONE,
|
|
6
|
-
TENANCY_MODE_PERSONAL,
|
|
7
|
-
TENANCY_MODE_WORKSPACES,
|
|
8
|
-
WORKSPACE_SLUG_POLICY_NONE,
|
|
9
|
-
WORKSPACE_SLUG_POLICY_IMMUTABLE_USERNAME,
|
|
10
|
-
WORKSPACE_SLUG_POLICY_USER_SELECTED,
|
|
11
|
-
resolveTenancyProfile
|
|
12
|
-
} from "../shared/tenancyProfile.js";
|
|
4
|
+
import { normalizeObject } from "@jskit-ai/kernel/shared/support/normalize";
|
|
13
5
|
import { accountAvatarFormatter } from "./common/formatters/accountAvatarFormatter.js";
|
|
14
6
|
import { authenticatedUserValidator } from "./common/validators/authenticatedUserValidator.js";
|
|
15
7
|
import { userSettingsFields } from "../shared/resources/userSettingsFields.js";
|
|
16
|
-
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
17
8
|
|
|
18
9
|
function getOAuthProviderCatalogPayload(authService) {
|
|
19
10
|
if (!authService || typeof authService.getOAuthProviderCatalog !== "function") {
|
|
@@ -56,10 +47,8 @@ function normalizeBoolean(value, fallback) {
|
|
|
56
47
|
return fallback;
|
|
57
48
|
}
|
|
58
49
|
|
|
59
|
-
function resolveAppState(appConfig = {}
|
|
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,56 +60,14 @@ function resolveAppState(appConfig = {}, { workspaceInvitationsEnabled = false }
|
|
|
71
60
|
};
|
|
72
61
|
}
|
|
73
62
|
|
|
74
|
-
function
|
|
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 }) {
|
|
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
|
-
|
|
115
|
-
pendingInvites: [],
|
|
116
|
-
activeWorkspace: null,
|
|
117
|
-
membership: null,
|
|
118
|
-
requestedWorkspace: null,
|
|
119
|
-
permissions: [],
|
|
120
|
-
surfaceAccess: {
|
|
121
|
-
consoleowner: false
|
|
122
|
-
},
|
|
123
|
-
workspaceSettings: null,
|
|
70
|
+
surfaceAccess: normalizeObject(surfaceAccess),
|
|
124
71
|
userSettings: null,
|
|
125
72
|
requestMeta: {
|
|
126
73
|
hasRequest: false
|
|
@@ -153,13 +100,10 @@ function createUsersBootstrapContributor({
|
|
|
153
100
|
usersRepository,
|
|
154
101
|
userSettingsRepository,
|
|
155
102
|
appConfig = {},
|
|
156
|
-
|
|
157
|
-
authService,
|
|
158
|
-
consoleService = null
|
|
103
|
+
authService
|
|
159
104
|
} = {}) {
|
|
160
105
|
const contributorId = "users.bootstrap";
|
|
161
106
|
const appState = resolveAppState(appConfig);
|
|
162
|
-
const resolvedTenancyProfile = resolveBootstrapTenancyProfile(tenancyProfile, appConfig);
|
|
163
107
|
|
|
164
108
|
requireServiceMethod(usersRepository, "findById", contributorId, {
|
|
165
109
|
serviceLabel: "usersRepository"
|
|
@@ -170,7 +114,8 @@ function createUsersBootstrapContributor({
|
|
|
170
114
|
|
|
171
115
|
return Object.freeze({
|
|
172
116
|
contributorId,
|
|
173
|
-
|
|
117
|
+
order: 100,
|
|
118
|
+
async contribute({ request = null, reply = null, payload: existingPayload = {} } = {}) {
|
|
174
119
|
const authResult = await request.executeAction({
|
|
175
120
|
actionId: "auth.session.read"
|
|
176
121
|
});
|
|
@@ -186,26 +131,16 @@ function createUsersBootstrapContributor({
|
|
|
186
131
|
}
|
|
187
132
|
|
|
188
133
|
const normalizedUser = authenticatedUserValidator.normalize(authResult?.authenticated ? authResult?.profile : null);
|
|
134
|
+
const inheritedSurfaceAccess = normalizeObject(existingPayload?.surfaceAccess);
|
|
189
135
|
let payload = createAnonymousBootstrapPayload({
|
|
190
136
|
appState,
|
|
191
|
-
|
|
137
|
+
surfaceAccess: inheritedSurfaceAccess
|
|
192
138
|
});
|
|
193
139
|
|
|
194
140
|
if (normalizedUser) {
|
|
195
141
|
const latestProfile = (await usersRepository.findById(normalizedUser.id)) || normalizedUser;
|
|
196
142
|
const userSettings = await userSettingsRepository.ensureForUserId(latestProfile.id);
|
|
197
143
|
|
|
198
|
-
let seededConsoleOwnerUserId = null;
|
|
199
|
-
if (
|
|
200
|
-
consoleService &&
|
|
201
|
-
typeof consoleService.ensureInitialConsoleMember === "function"
|
|
202
|
-
) {
|
|
203
|
-
seededConsoleOwnerUserId = normalizeRecordId(
|
|
204
|
-
await consoleService.ensureInitialConsoleMember(latestProfile.id),
|
|
205
|
-
{ fallback: null }
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
144
|
payload = {
|
|
210
145
|
session: {
|
|
211
146
|
authenticated: true,
|
|
@@ -216,18 +151,8 @@ function createUsersBootstrapContributor({
|
|
|
216
151
|
email: latestProfile.email,
|
|
217
152
|
avatar: accountAvatarFormatter(latestProfile, userSettings)
|
|
218
153
|
},
|
|
219
|
-
tenancy: resolvedTenancyProfile,
|
|
220
154
|
app: appState,
|
|
221
|
-
|
|
222
|
-
pendingInvites: [],
|
|
223
|
-
activeWorkspace: null,
|
|
224
|
-
membership: null,
|
|
225
|
-
requestedWorkspace: null,
|
|
226
|
-
permissions: [],
|
|
227
|
-
surfaceAccess: {
|
|
228
|
-
consoleowner: Boolean(seededConsoleOwnerUserId) && seededConsoleOwnerUserId === String(latestProfile.id)
|
|
229
|
-
},
|
|
230
|
-
workspaceSettings: null,
|
|
155
|
+
surfaceAccess: inheritedSurfaceAccess,
|
|
231
156
|
userSettings: mapUserSettingsBootstrap(userSettings),
|
|
232
157
|
requestMeta: {
|
|
233
158
|
hasRequest: Boolean(request)
|