@jskit-ai/users-core 0.1.32 → 0.1.35
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 +16 -245
- package/package.json +7 -7
- package/src/server/UsersCoreServiceProvider.js +4 -28
- package/src/server/UsersWorkspacesServiceProvider.js +44 -0
- package/src/server/accountNotifications/accountNotificationsService.js +3 -3
- package/src/server/accountNotifications/registerAccountNotifications.js +1 -1
- package/src/server/accountPreferences/accountPreferencesService.js +3 -3
- package/src/server/accountPreferences/registerAccountPreferences.js +1 -1
- package/src/server/accountProfile/accountProfileActions.js +8 -2
- package/src/server/accountProfile/accountProfileService.js +10 -10
- package/src/server/accountProfile/avatarService.js +9 -9
- package/src/server/accountProfile/bootAccountProfileRoutes.js +5 -3
- package/src/server/accountProfile/registerAccountProfile.js +2 -2
- package/src/server/accountSecurity/accountSecurityService.js +3 -3
- package/src/server/accountSecurity/registerAccountSecurity.js +1 -1
- package/src/server/common/contributors/workspaceActionContextContributor.js +24 -17
- package/src/server/common/registerCommonRepositories.js +3 -22
- package/src/server/common/repositories/userSettingsRepository.js +1 -12
- package/src/server/common/repositories/{userProfilesRepository.js → usersRepository.js} +1 -1
- package/src/server/common/services/accountContextService.js +4 -4
- package/src/server/common/services/authProfileSyncService.js +10 -10
- package/src/server/registerUsersBootstrap.js +22 -0
- package/src/server/registerUsersCore.js +30 -0
- package/src/server/registerWorkspaceBootstrap.js +3 -6
- package/src/server/registerWorkspaceCore.js +5 -17
- package/src/server/registerWorkspaceRepositories.js +26 -0
- package/src/server/usersBootstrapContributor.js +248 -0
- package/src/server/workspaceBootstrapContributor.js +65 -259
- package/src/shared/roles.js +31 -6
- package/src/shared/settings.js +1 -2
- package/templates/migrations/users_core_generic_initial.cjs +69 -0
- package/test/authProfileSyncService.test.js +3 -3
- package/test/avatarService.test.js +2 -2
- package/test/registerUsersCore.test.js +42 -0
- package/test/roles.test.js +90 -5
- package/test/usersBootstrapContributor.test.js +172 -0
- package/test/usersRouteRequestInputValidator.test.js +7 -390
- package/test/workspaceActionContextContributor.test.js +98 -5
- package/test/workspaceBootstrapContributor.test.js +34 -346
- package/test/workspaceMembersService.test.js +4 -2
- package/test/workspaceService.test.js +12 -8
- package/test/workspaceSettingsResource.test.js +4 -2
- package/test-support/registerDefaultSettingsFields.js +1 -1
- package/templates/config/workspaceRoles.js +0 -30
- package/templates/migrations/users_core_initial.cjs +0 -123
- package/templates/migrations/users_core_workspace_settings_single_name_source.cjs +0 -71
- package/templates/migrations/users_core_workspaces_drop_color.cjs +0 -85
- package/templates/packages/main/src/shared/resources/workspaceSettingsFields.js +0 -197
|
@@ -21,9 +21,9 @@ async function readAvatarBuffer(stream, { maxBytes = DEFAULT_AVATAR_POLICY.maxUp
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function createService({
|
|
25
|
-
if (!
|
|
26
|
-
throw new TypeError("avatarService requires
|
|
24
|
+
function createService({ usersRepository, avatarStorageService, avatarPolicy } = {}) {
|
|
25
|
+
if (!usersRepository) {
|
|
26
|
+
throw new TypeError("avatarService requires usersRepository.");
|
|
27
27
|
}
|
|
28
28
|
if (!avatarStorageService) {
|
|
29
29
|
throw new TypeError("avatarService requires avatarStorageService.");
|
|
@@ -32,21 +32,21 @@ function createService({ userProfilesRepository, avatarStorageService, avatarPol
|
|
|
32
32
|
const resolvedAvatarPolicy = resolveAvatarPolicy(avatarPolicy);
|
|
33
33
|
|
|
34
34
|
async function resolveProfile(user) {
|
|
35
|
-
const profile = await resolveUserProfile(
|
|
35
|
+
const profile = await resolveUserProfile(usersRepository, user);
|
|
36
36
|
if (!profile) {
|
|
37
37
|
throw new AppError(404, "User profile was not found.");
|
|
38
38
|
}
|
|
39
39
|
return profile;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
async function uploadForUser(user,
|
|
42
|
+
async function uploadForUser(user, avatarUpload = {}) {
|
|
43
43
|
const profile = await resolveProfile(user);
|
|
44
|
-
validateUploadMimeType(
|
|
44
|
+
validateUploadMimeType(avatarUpload?.mimeType, resolvedAvatarPolicy, {
|
|
45
45
|
fieldName: "avatar",
|
|
46
46
|
label: "Avatar"
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
const buffer = await readAvatarBuffer(
|
|
49
|
+
const buffer = await readAvatarBuffer(avatarUpload?.stream, {
|
|
50
50
|
maxBytes: resolvedAvatarPolicy.maxUploadBytes
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -57,7 +57,7 @@ function createService({ userProfilesRepository, avatarStorageService, avatarPol
|
|
|
57
57
|
buffer
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
const updatedProfile = await
|
|
60
|
+
const updatedProfile = await usersRepository.updateAvatarById(profile.id, {
|
|
61
61
|
avatarStorageKey: savedAvatar.storageKey,
|
|
62
62
|
avatarVersion,
|
|
63
63
|
avatarUpdatedAt: new Date(avatarVersionMs)
|
|
@@ -73,7 +73,7 @@ function createService({ userProfilesRepository, avatarStorageService, avatarPol
|
|
|
73
73
|
if (profile.avatarStorageKey) {
|
|
74
74
|
await avatarStorageService.deleteAvatar(profile.avatarStorageKey);
|
|
75
75
|
}
|
|
76
|
-
return
|
|
76
|
+
return usersRepository.clearAvatarById(profile.id);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
async function readForUser(user) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { withStandardErrorResponses } from "@jskit-ai/http-runtime/shared/validators/errorResponses";
|
|
2
|
+
import { DEFAULT_IMAGE_UPLOAD_MAX_BYTES } from "@jskit-ai/uploads-runtime/shared";
|
|
2
3
|
import { readSingleMultipartFile } from "@jskit-ai/uploads-runtime/server/multipart/readSingleMultipartFile";
|
|
3
4
|
import { userSettingsResource } from "../../shared/resources/userSettingsResource.js";
|
|
4
5
|
import { userProfileResource } from "../../shared/resources/userProfileResource.js";
|
|
@@ -77,7 +78,7 @@ function bootAccountProfileRoutes(app) {
|
|
|
77
78
|
}
|
|
78
79
|
},
|
|
79
80
|
async function (request, reply) {
|
|
80
|
-
const avatar = await accountProfileService.readAvatar(request, request.user, {
|
|
81
|
+
const avatar = await accountProfileService.readAvatar(request, request.user, {
|
|
81
82
|
context: {
|
|
82
83
|
actor: request.user
|
|
83
84
|
}
|
|
@@ -114,10 +115,11 @@ function bootAccountProfileRoutes(app) {
|
|
|
114
115
|
},
|
|
115
116
|
async function (request, reply) {
|
|
116
117
|
const filePart = await readSingleMultipartFile(request, {
|
|
117
|
-
|
|
118
|
+
fieldName: "avatar",
|
|
118
119
|
required: true,
|
|
119
120
|
fieldErrorKey: "avatar",
|
|
120
|
-
label: "Avatar"
|
|
121
|
+
label: "Avatar",
|
|
122
|
+
maxBytes: DEFAULT_IMAGE_UPLOAD_MAX_BYTES
|
|
121
123
|
});
|
|
122
124
|
|
|
123
125
|
const uploadDimension = filePart.fields?.uploadDimension?.value;
|
|
@@ -20,7 +20,7 @@ function registerAccountProfile(app) {
|
|
|
20
20
|
|
|
21
21
|
app.singleton("users.avatar.service", (scope) =>
|
|
22
22
|
createAvatarService({
|
|
23
|
-
|
|
23
|
+
usersRepository: scope.make("usersRepository"),
|
|
24
24
|
avatarStorageService: scope.make("users.avatar.storage.service")
|
|
25
25
|
})
|
|
26
26
|
);
|
|
@@ -30,7 +30,7 @@ function registerAccountProfile(app) {
|
|
|
30
30
|
(scope) =>
|
|
31
31
|
createAccountProfileService({
|
|
32
32
|
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
33
|
-
|
|
33
|
+
usersRepository: scope.make("usersRepository"),
|
|
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
|
-
|
|
13
|
+
usersRepository,
|
|
14
14
|
authService
|
|
15
15
|
} = {}) {
|
|
16
|
-
if (!userSettingsRepository || !
|
|
16
|
+
if (!userSettingsRepository || !usersRepository) {
|
|
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(
|
|
43
|
+
const profile = await resolveUserProfile(usersRepository, user);
|
|
44
44
|
if (!profile) {
|
|
45
45
|
throw new AppError(404, "User profile was not found.");
|
|
46
46
|
}
|
|
@@ -11,7 +11,7 @@ function registerAccountSecurity(app) {
|
|
|
11
11
|
const authService = scope.has("authService") ? scope.make("authService") : null;
|
|
12
12
|
return createAccountSecurityService({
|
|
13
13
|
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
14
|
-
|
|
14
|
+
usersRepository: scope.make("usersRepository"),
|
|
15
15
|
authService
|
|
16
16
|
});
|
|
17
17
|
});
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
normalizeObject,
|
|
3
3
|
requireServiceMethod
|
|
4
4
|
} from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
|
|
5
|
+
import { normalizeSurfaceId } from "@jskit-ai/kernel/shared/surface/registry";
|
|
5
6
|
import {
|
|
6
7
|
checkRouteVisibility,
|
|
7
8
|
USERS_ROUTE_VISIBILITY_PUBLIC,
|
|
@@ -9,45 +10,51 @@ import {
|
|
|
9
10
|
USERS_ROUTE_VISIBILITY_WORKSPACE_USER
|
|
10
11
|
} from "../../../shared/support/usersVisibility.js";
|
|
11
12
|
import { resolveActionUser } from "../support/resolveActionUser.js";
|
|
12
|
-
|
|
13
|
-
const WORKSPACE_CONTEXT_ACTION_IDS = Object.freeze([
|
|
14
|
-
"workspace.roles.list",
|
|
15
|
-
"workspace.settings.read",
|
|
16
|
-
"workspace.settings.update",
|
|
17
|
-
"workspace.members.list",
|
|
18
|
-
"workspace.member.role.update",
|
|
19
|
-
"workspace.member.remove",
|
|
20
|
-
"workspace.invites.list",
|
|
21
|
-
"workspace.invite.create",
|
|
22
|
-
"workspace.invite.revoke"
|
|
23
|
-
]);
|
|
24
13
|
const WORKSPACE_VISIBILITY_ACTION_CONTEXT_SET = new Set([
|
|
25
14
|
USERS_ROUTE_VISIBILITY_WORKSPACE,
|
|
26
15
|
USERS_ROUTE_VISIBILITY_WORKSPACE_USER
|
|
27
16
|
]);
|
|
28
17
|
|
|
29
|
-
function
|
|
18
|
+
function normalizeWorkspaceSurfaceIds(surfaceIds = []) {
|
|
19
|
+
const source = Array.isArray(surfaceIds) ? surfaceIds : [];
|
|
20
|
+
const normalized = new Set();
|
|
21
|
+
|
|
22
|
+
for (const entry of source) {
|
|
23
|
+
const surfaceId = normalizeSurfaceId(entry);
|
|
24
|
+
if (!surfaceId) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
normalized.add(surfaceId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return normalized;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function createWorkspaceActionContextContributor({ workspaceService, workspaceSurfaceIds = [] } = {}) {
|
|
30
34
|
const contributorId = "users.workspace.context";
|
|
35
|
+
const workspaceSurfaceIdSet = normalizeWorkspaceSurfaceIds(workspaceSurfaceIds);
|
|
31
36
|
|
|
32
37
|
requireServiceMethod(workspaceService, "resolveWorkspaceContextForUserBySlug", contributorId);
|
|
33
38
|
|
|
34
39
|
return Object.freeze({
|
|
35
40
|
contributorId,
|
|
36
|
-
async contribute({
|
|
41
|
+
async contribute({ definition = null, input, context, request } = {}) {
|
|
37
42
|
const payload = normalizeObject(input);
|
|
38
43
|
if (!Object.hasOwn(payload, "workspaceSlug")) {
|
|
39
44
|
return {};
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
const
|
|
43
|
-
const
|
|
47
|
+
const actionSurfaces = Array.isArray(definition?.surfaces) ? definition.surfaces : [];
|
|
48
|
+
const hasWorkspaceActionSurface = actionSurfaces.some((surfaceId) => workspaceSurfaceIdSet.has(surfaceId));
|
|
49
|
+
const routeSurfaceId = normalizeSurfaceId(request?.routeOptions?.config?.surface);
|
|
50
|
+
const hasWorkspaceSurface = workspaceSurfaceIdSet.has(routeSurfaceId);
|
|
44
51
|
const routeVisibilityInput =
|
|
45
52
|
request && request.routeOptions && request.routeOptions.config
|
|
46
53
|
? request.routeOptions.config.visibility
|
|
47
54
|
: USERS_ROUTE_VISIBILITY_PUBLIC;
|
|
48
55
|
const routeVisibility = checkRouteVisibility(routeVisibilityInput);
|
|
49
56
|
const hasWorkspaceRouteVisibility = WORKSPACE_VISIBILITY_ACTION_CONTEXT_SET.has(routeVisibility);
|
|
50
|
-
if (!
|
|
57
|
+
if (!hasWorkspaceActionSurface && !hasWorkspaceRouteVisibility && !hasWorkspaceSurface) {
|
|
51
58
|
return {};
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { createRepository as
|
|
1
|
+
import { createRepository as createUsersRepository } from "./repositories/usersRepository.js";
|
|
2
2
|
import { createRepository as createUserSettingsRepository } from "./repositories/userSettingsRepository.js";
|
|
3
|
-
import { createRepository as createWorkspacesRepository } from "./repositories/workspacesRepository.js";
|
|
4
|
-
import { createRepository as createWorkspaceMembershipsRepository } from "./repositories/workspaceMembershipsRepository.js";
|
|
5
|
-
import { createRepository as createWorkspaceInvitesRepository } from "./repositories/workspaceInvitesRepository.js";
|
|
6
3
|
import { createRepository as createConsoleSettingsRepository } from "../consoleSettings/consoleSettingsRepository.js";
|
|
7
4
|
|
|
8
5
|
function registerCommonRepositories(app) {
|
|
@@ -10,31 +7,15 @@ function registerCommonRepositories(app) {
|
|
|
10
7
|
throw new Error("registerCommonRepositories requires application singleton().");
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
app.singleton("
|
|
10
|
+
app.singleton("usersRepository", (scope) => {
|
|
14
11
|
const knex = scope.make("jskit.database.knex");
|
|
15
|
-
return
|
|
12
|
+
return createUsersRepository(knex);
|
|
16
13
|
});
|
|
17
14
|
|
|
18
15
|
app.singleton("userSettingsRepository", (scope) => {
|
|
19
16
|
const knex = scope.make("jskit.database.knex");
|
|
20
17
|
return createUserSettingsRepository(knex);
|
|
21
18
|
});
|
|
22
|
-
|
|
23
|
-
app.singleton("workspacesRepository", (scope) => {
|
|
24
|
-
const knex = scope.make("jskit.database.knex");
|
|
25
|
-
return createWorkspacesRepository(knex);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
app.singleton("workspaceMembershipsRepository", (scope) => {
|
|
29
|
-
const knex = scope.make("jskit.database.knex");
|
|
30
|
-
return createWorkspaceMembershipsRepository(knex);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
app.singleton("workspaceInvitesRepository", (scope) => {
|
|
34
|
-
const knex = scope.make("jskit.database.knex");
|
|
35
|
-
return createWorkspaceInvitesRepository(knex);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
19
|
app.singleton("consoleSettingsRepository", (scope) => {
|
|
39
20
|
const knex = scope.make("jskit.database.knex");
|
|
40
21
|
return createConsoleSettingsRepository(knex);
|
|
@@ -15,7 +15,6 @@ function mapRow(row) {
|
|
|
15
15
|
|
|
16
16
|
const mapped = {
|
|
17
17
|
userId: Number(row.user_id),
|
|
18
|
-
lastActiveWorkspaceId: row.last_active_workspace_id == null ? null : Number(row.last_active_workspace_id),
|
|
19
18
|
passwordSignInEnabled: row.password_sign_in_enabled == null ? true : Boolean(row.password_sign_in_enabled),
|
|
20
19
|
passwordSetupRequired: row.password_setup_required == null ? false : Boolean(row.password_setup_required),
|
|
21
20
|
createdAt: toIsoString(row.created_at),
|
|
@@ -48,7 +47,6 @@ function normalizeBoolean(value, fallback = false) {
|
|
|
48
47
|
function createInsertPayload(userId) {
|
|
49
48
|
const payload = {
|
|
50
49
|
user_id: Number(userId),
|
|
51
|
-
last_active_workspace_id: null,
|
|
52
50
|
password_sign_in_enabled: DEFAULT_USER_SETTINGS.passwordSignInEnabled,
|
|
53
51
|
password_setup_required: DEFAULT_USER_SETTINGS.passwordSetupRequired,
|
|
54
52
|
created_at: nowDb(),
|
|
@@ -127,10 +125,6 @@ function createRepository(knex) {
|
|
|
127
125
|
if (Object.hasOwn(source, "passwordSetupRequired")) {
|
|
128
126
|
dbPatch.password_setup_required = normalizeBoolean(source.passwordSetupRequired, ensured.passwordSetupRequired);
|
|
129
127
|
}
|
|
130
|
-
if (Object.hasOwn(source, "lastActiveWorkspaceId")) {
|
|
131
|
-
dbPatch.last_active_workspace_id = source.lastActiveWorkspaceId == null ? null : Number(source.lastActiveWorkspaceId);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
128
|
await client("user_settings").where({ user_id: Number(userId) }).update(dbPatch);
|
|
135
129
|
return findByUserId(userId, { trx: client });
|
|
136
130
|
}
|
|
@@ -160,10 +154,6 @@ function createRepository(knex) {
|
|
|
160
154
|
return patchUserSettings(userId, { passwordSetupRequired: required }, options);
|
|
161
155
|
}
|
|
162
156
|
|
|
163
|
-
async function updateLastActiveWorkspaceId(userId, workspaceId, options = {}) {
|
|
164
|
-
return patchUserSettings(userId, { lastActiveWorkspaceId: workspaceId }, options);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
157
|
return Object.freeze({
|
|
168
158
|
findByUserId,
|
|
169
159
|
ensureForUserId,
|
|
@@ -171,8 +161,7 @@ function createRepository(knex) {
|
|
|
171
161
|
updatePreferences,
|
|
172
162
|
updateNotifications,
|
|
173
163
|
updatePasswordSignInEnabled,
|
|
174
|
-
updatePasswordSetupRequired
|
|
175
|
-
updateLastActiveWorkspaceId
|
|
164
|
+
updatePasswordSetupRequired
|
|
176
165
|
});
|
|
177
166
|
}
|
|
178
167
|
|
|
@@ -104,7 +104,7 @@ async function resolveUniqueUsername(client, baseUsername, { excludeUserId = 0 }
|
|
|
104
104
|
|
|
105
105
|
function createRepository(knex) {
|
|
106
106
|
if (typeof knex !== "function") {
|
|
107
|
-
throw new TypeError("
|
|
107
|
+
throw new TypeError("usersRepository requires knex.");
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
async function findById(userId, options = {}) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { normalizeIdentity } from "../repositories/
|
|
1
|
+
import { normalizeIdentity } from "../repositories/usersRepository.js";
|
|
2
2
|
|
|
3
|
-
async function resolveUserProfile(
|
|
3
|
+
async function resolveUserProfile(usersRepository, user) {
|
|
4
4
|
const identity = normalizeIdentity(user);
|
|
5
5
|
if (identity) {
|
|
6
|
-
const profile = await
|
|
6
|
+
const profile = await usersRepository.findByIdentity(identity);
|
|
7
7
|
if (profile) {
|
|
8
8
|
return profile;
|
|
9
9
|
}
|
|
@@ -11,7 +11,7 @@ async function resolveUserProfile(userProfilesRepository, user) {
|
|
|
11
11
|
|
|
12
12
|
const userId = Number(user?.id);
|
|
13
13
|
if (Number.isInteger(userId) && userId > 0) {
|
|
14
|
-
const profileById = await
|
|
14
|
+
const profileById = await usersRepository.findById(userId);
|
|
15
15
|
if (profileById) {
|
|
16
16
|
return profileById;
|
|
17
17
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeLowerText, normalizeText } from "@jskit-ai/kernel/shared/actions/textNormalization";
|
|
2
|
-
import { normalizeIdentity } from "../repositories/
|
|
2
|
+
import { normalizeIdentity } from "../repositories/usersRepository.js";
|
|
3
3
|
|
|
4
4
|
function buildNormalizedIdentityKey(identityLike) {
|
|
5
5
|
const identity = normalizeIdentity(identityLike);
|
|
@@ -53,12 +53,12 @@ function requireSynchronizedProfile(profile) {
|
|
|
53
53
|
throw new Error("Profile synchronization failed.");
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function createService({
|
|
57
|
-
if (!
|
|
58
|
-
throw new Error("authProfileSyncService requires
|
|
56
|
+
function createService({ usersRepository, workspaceProvisioningService = null, userSettingsRepository = null } = {}) {
|
|
57
|
+
if (!usersRepository || typeof usersRepository.findByIdentity !== "function") {
|
|
58
|
+
throw new Error("authProfileSyncService requires usersRepository.findByIdentity().");
|
|
59
59
|
}
|
|
60
|
-
if (typeof
|
|
61
|
-
throw new Error("authProfileSyncService requires
|
|
60
|
+
if (typeof usersRepository.upsert !== "function") {
|
|
61
|
+
throw new Error("authProfileSyncService requires usersRepository.upsert().");
|
|
62
62
|
}
|
|
63
63
|
if (!userSettingsRepository || typeof userSettingsRepository.ensureForUserId !== "function") {
|
|
64
64
|
throw new Error("authProfileSyncService requires userSettingsRepository.ensureForUserId().");
|
|
@@ -66,7 +66,7 @@ function createService({ userProfilesRepository, workspaceProvisioningService =
|
|
|
66
66
|
|
|
67
67
|
async function findByIdentity(identityLike, options = {}) {
|
|
68
68
|
const normalized = buildNormalizedIdentityKey(identityLike);
|
|
69
|
-
return
|
|
69
|
+
return usersRepository.findByIdentity(
|
|
70
70
|
{
|
|
71
71
|
provider: normalized.authProvider,
|
|
72
72
|
providerUserId: normalized.authProviderUserSid
|
|
@@ -77,7 +77,7 @@ function createService({ userProfilesRepository, workspaceProvisioningService =
|
|
|
77
77
|
|
|
78
78
|
async function upsertByIdentity(profileLike, options = {}) {
|
|
79
79
|
const normalized = buildNormalizedIdentityProfile(profileLike);
|
|
80
|
-
return
|
|
80
|
+
return usersRepository.upsert(
|
|
81
81
|
{
|
|
82
82
|
authProvider: normalized.authProvider,
|
|
83
83
|
authProviderUserSid: normalized.authProviderUserSid,
|
|
@@ -118,8 +118,8 @@ function createService({ userProfilesRepository, workspaceProvisioningService =
|
|
|
118
118
|
if (options?.trx) {
|
|
119
119
|
return runSync(options.trx);
|
|
120
120
|
}
|
|
121
|
-
if (typeof
|
|
122
|
-
return
|
|
121
|
+
if (typeof usersRepository.withTransaction === "function") {
|
|
122
|
+
return usersRepository.withTransaction((trx) => runSync(trx));
|
|
123
123
|
}
|
|
124
124
|
return runSync();
|
|
125
125
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { registerBootstrapPayloadContributor } from "@jskit-ai/kernel/server/runtime";
|
|
2
|
+
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
3
|
+
import { createUsersBootstrapContributor } from "./usersBootstrapContributor.js";
|
|
4
|
+
|
|
5
|
+
function registerUsersBootstrap(app) {
|
|
6
|
+
if (!app || typeof app.singleton !== "function") {
|
|
7
|
+
throw new Error("registerUsersBootstrap requires application singleton().");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
registerBootstrapPayloadContributor(app, "users.core.bootstrap.payloadContributor", (scope) => {
|
|
11
|
+
return createUsersBootstrapContributor({
|
|
12
|
+
usersRepository: scope.make("usersRepository"),
|
|
13
|
+
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
14
|
+
appConfig: resolveAppConfig(scope),
|
|
15
|
+
tenancyProfile: scope.make("users.tenancy.profile"),
|
|
16
|
+
authService: scope.make("authService"),
|
|
17
|
+
consoleService: scope.has("consoleService") ? scope.make("consoleService") : null
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { registerUsersBootstrap };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
2
|
+
import { resolveTenancyProfile } from "../shared/tenancyProfile.js";
|
|
3
|
+
import { createService as createAuthProfileSyncService } from "./common/services/authProfileSyncService.js";
|
|
4
|
+
import { registerUsersCoreActionSurfaceSources } from "./support/workspaceActionSurfaces.js";
|
|
5
|
+
|
|
6
|
+
function registerUsersCore(app) {
|
|
7
|
+
if (!app || typeof app.singleton !== "function") {
|
|
8
|
+
throw new Error("registerUsersCore requires application singleton().");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
registerUsersCoreActionSurfaceSources(app);
|
|
12
|
+
|
|
13
|
+
app.singleton("users.profile.sync.service", (scope) => {
|
|
14
|
+
return createAuthProfileSyncService({
|
|
15
|
+
usersRepository: scope.make("usersRepository"),
|
|
16
|
+
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
17
|
+
workspaceProvisioningService:
|
|
18
|
+
typeof scope.has === "function" && scope.has("users.workspace.service")
|
|
19
|
+
? scope.make("users.workspace.service")
|
|
20
|
+
: null
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
app.singleton("users.tenancy.profile", (scope) => {
|
|
25
|
+
const appConfig = resolveAppConfig(scope);
|
|
26
|
+
return resolveTenancyProfile(appConfig);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { registerUsersCore };
|
|
@@ -8,7 +8,7 @@ function registerWorkspaceBootstrap(app) {
|
|
|
8
8
|
throw new Error("registerWorkspaceBootstrap requires application singleton().");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
registerBootstrapPayloadContributor(app, "
|
|
11
|
+
registerBootstrapPayloadContributor(app, "workspaces.core.bootstrap.payloadContributor", (scope) => {
|
|
12
12
|
const workspaceInvitationsEnabled = scope.make("users.workspace.invitations.enabled");
|
|
13
13
|
|
|
14
14
|
return createWorkspaceBootstrapContributor({
|
|
@@ -17,12 +17,9 @@ function registerWorkspaceBootstrap(app) {
|
|
|
17
17
|
? scope.make("users.workspace.pending-invitations.service")
|
|
18
18
|
: null,
|
|
19
19
|
workspaceInvitationsEnabled,
|
|
20
|
-
|
|
21
|
-
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
20
|
+
usersRepository: scope.make("usersRepository"),
|
|
22
21
|
appConfig: resolveAppConfig(scope),
|
|
23
|
-
tenancyProfile: scope.make("users.tenancy.profile")
|
|
24
|
-
authService: scope.make("authService"),
|
|
25
|
-
consoleService: scope.has("consoleService") ? scope.make("consoleService") : null
|
|
22
|
+
tenancyProfile: scope.make("users.tenancy.profile")
|
|
26
23
|
});
|
|
27
24
|
});
|
|
28
25
|
}
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "@jskit-ai/kernel/server/actions";
|
|
4
4
|
import { registerRouteVisibilityResolver } from "@jskit-ai/kernel/server/http";
|
|
5
5
|
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
6
|
-
import { TENANCY_MODE_WORKSPACES, resolveTenancyProfile } from "../shared/tenancyProfile.js";
|
|
7
6
|
import { createService as createWorkspaceService } from "./common/services/workspaceContextService.js";
|
|
8
|
-
import { createService as createAuthProfileSyncService } from "./common/services/authProfileSyncService.js";
|
|
9
7
|
import { createWorkspaceActionContextContributor } from "./common/contributors/workspaceActionContextContributor.js";
|
|
10
8
|
import { createWorkspaceRouteVisibilityResolver } from "./common/contributors/workspaceRouteVisibilityResolver.js";
|
|
11
9
|
import { createWorkspaceAuthPolicyContextResolver } from "./common/contributors/workspaceAuthPolicyContextResolver.js";
|
|
10
|
+
import { TENANCY_MODE_WORKSPACES } from "../shared/tenancyProfile.js";
|
|
12
11
|
import { resolveWorkspaceInvitationsPolicy } from "./support/workspaceInvitationsPolicy.js";
|
|
12
|
+
import { resolveWorkspaceSurfaceIdsFromAppConfig } from "./support/workspaceActionSurfaces.js";
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
function registerWorkspaceCore(app) {
|
|
@@ -26,20 +26,6 @@ function registerWorkspaceCore(app) {
|
|
|
26
26
|
workspaceSettingsRepository: scope.make("workspaceSettingsRepository")
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
|
-
|
|
30
|
-
app.singleton("users.profile.sync.service", (scope) => {
|
|
31
|
-
return createAuthProfileSyncService({
|
|
32
|
-
userProfilesRepository: scope.make("userProfilesRepository"),
|
|
33
|
-
userSettingsRepository: scope.make("userSettingsRepository"),
|
|
34
|
-
workspaceProvisioningService: scope.make("users.workspace.service")
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
app.singleton("users.tenancy.profile", (scope) => {
|
|
39
|
-
const appConfig = resolveAppConfig(scope);
|
|
40
|
-
return resolveTenancyProfile(appConfig);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
29
|
app.singleton("users.workspace.enabled", (scope) => {
|
|
44
30
|
return scope.make("users.tenancy.profile").workspace.enabled === true;
|
|
45
31
|
});
|
|
@@ -62,8 +48,10 @@ function registerWorkspaceCore(app) {
|
|
|
62
48
|
});
|
|
63
49
|
|
|
64
50
|
registerActionContextContributor(app, "users.core.workspace.actionContextContributor", (scope) => {
|
|
51
|
+
const appConfig = resolveAppConfig(scope);
|
|
65
52
|
return createWorkspaceActionContextContributor({
|
|
66
|
-
workspaceService: scope.make("users.workspace.service")
|
|
53
|
+
workspaceService: scope.make("users.workspace.service"),
|
|
54
|
+
workspaceSurfaceIds: resolveWorkspaceSurfaceIdsFromAppConfig(appConfig)
|
|
67
55
|
});
|
|
68
56
|
});
|
|
69
57
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createRepository as createWorkspacesRepository } from "./common/repositories/workspacesRepository.js";
|
|
2
|
+
import { createRepository as createWorkspaceMembershipsRepository } from "./common/repositories/workspaceMembershipsRepository.js";
|
|
3
|
+
import { createRepository as createWorkspaceInvitesRepository } from "./common/repositories/workspaceInvitesRepository.js";
|
|
4
|
+
|
|
5
|
+
function registerWorkspaceRepositories(app) {
|
|
6
|
+
if (!app || typeof app.singleton !== "function") {
|
|
7
|
+
throw new Error("registerWorkspaceRepositories requires application singleton().");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
app.singleton("workspacesRepository", (scope) => {
|
|
11
|
+
const knex = scope.make("jskit.database.knex");
|
|
12
|
+
return createWorkspacesRepository(knex);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
app.singleton("workspaceMembershipsRepository", (scope) => {
|
|
16
|
+
const knex = scope.make("jskit.database.knex");
|
|
17
|
+
return createWorkspaceMembershipsRepository(knex);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
app.singleton("workspaceInvitesRepository", (scope) => {
|
|
21
|
+
const knex = scope.make("jskit.database.knex");
|
|
22
|
+
return createWorkspaceInvitesRepository(knex);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { registerWorkspaceRepositories };
|