@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.
- package/package.descriptor.mjs +7 -7
- package/package.json +7 -17
- 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 +0 -1
- package/src/server/registerUsersCore.js +2 -14
- package/src/server/usersBootstrapContributor.js +2 -64
- package/src/shared/index.js +2 -99
- package/src/shared/settings.js +1 -119
- package/test/authProfileSyncService.test.js +19 -10
- package/test/registerServiceRealtimeEvents.test.js +0 -86
- package/test/registerUsersCore.test.js +6 -15
- package/test/repositoryContracts.test.js +1 -9
- package/test/resourcesCanonical.test.js +0 -16
- package/test/settingsFieldRegistriesSingleton.test.js +0 -5
- package/test/usersBootstrapContributor.test.js +2 -26
- package/test/usersRouteResources.test.js +0 -16
- 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/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 -118
- package/src/server/support/workspaceInvitationsPolicy.js +0 -45
- package/src/server/support/workspaceRouteInput.js +0 -22
- package/src/server/workspaceBootstrapContributor.js +0 -212
- 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/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/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 -85
- 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
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { createWorkspaceBootstrapContributor } from "../src/server/workspaceBootstrapContributor.js";
|
|
4
|
-
|
|
5
|
-
function createAuthenticatedProfile(overrides = {}) {
|
|
6
|
-
return {
|
|
7
|
-
id: "7",
|
|
8
|
-
authProvider: "local",
|
|
9
|
-
authProviderUserSid: "user-7",
|
|
10
|
-
username: "tester",
|
|
11
|
-
displayName: "Test User",
|
|
12
|
-
email: "test@example.com",
|
|
13
|
-
...overrides
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
test("workspace bootstrap contributor passes actor context to pending invites service", async () => {
|
|
18
|
-
const profile = createAuthenticatedProfile();
|
|
19
|
-
const pendingServiceCalls = [];
|
|
20
|
-
const contributor = createWorkspaceBootstrapContributor({
|
|
21
|
-
workspaceService: {
|
|
22
|
-
async listWorkspacesForUser() {
|
|
23
|
-
return [];
|
|
24
|
-
},
|
|
25
|
-
async resolveWorkspaceContextForUserBySlug() {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
workspacePendingInvitationsService: {
|
|
30
|
-
async listPendingInvitesForUser(user, options = {}) {
|
|
31
|
-
pendingServiceCalls.push({
|
|
32
|
-
user,
|
|
33
|
-
options
|
|
34
|
-
});
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
usersRepository: {
|
|
39
|
-
async findById() {
|
|
40
|
-
return profile;
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
workspaceInvitationsEnabled: true,
|
|
44
|
-
appConfig: {
|
|
45
|
-
tenancyMode: "workspaces"
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
await contributor.contribute({
|
|
50
|
-
payload: {
|
|
51
|
-
session: {
|
|
52
|
-
authenticated: true,
|
|
53
|
-
userId: profile.id
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
assert.equal(pendingServiceCalls.length, 1);
|
|
59
|
-
assert.equal(pendingServiceCalls[0].user.id, profile.id);
|
|
60
|
-
assert.equal(pendingServiceCalls[0].options?.context?.actor?.id, profile.id);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("workspace bootstrap contributor resolves workspace slug from bootstrap query", async () => {
|
|
64
|
-
const profile = createAuthenticatedProfile();
|
|
65
|
-
const calls = [];
|
|
66
|
-
const contributor = createWorkspaceBootstrapContributor({
|
|
67
|
-
workspaceService: {
|
|
68
|
-
async listWorkspacesForUser() {
|
|
69
|
-
return [];
|
|
70
|
-
},
|
|
71
|
-
async resolveWorkspaceContextForUserBySlug(_user, workspaceSlug) {
|
|
72
|
-
calls.push(workspaceSlug);
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
workspacePendingInvitationsService: {
|
|
77
|
-
async listPendingInvitesForUser() {
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
usersRepository: {
|
|
82
|
-
async findById() {
|
|
83
|
-
return profile;
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
workspaceInvitationsEnabled: true,
|
|
87
|
-
appConfig: {
|
|
88
|
-
tenancyMode: "workspaces"
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const payload = await contributor.contribute({
|
|
93
|
-
query: {
|
|
94
|
-
workspaceSlug: " AcMe "
|
|
95
|
-
},
|
|
96
|
-
payload: {
|
|
97
|
-
session: {
|
|
98
|
-
authenticated: true,
|
|
99
|
-
userId: profile.id
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
assert.deepEqual(calls, ["acme"]);
|
|
105
|
-
assert.deepEqual(payload.requestedWorkspace, {
|
|
106
|
-
slug: "acme",
|
|
107
|
-
status: "resolved"
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test("workspace bootstrap contributor reports unauthenticated requested workspace without generic bootstrap work", async () => {
|
|
112
|
-
const contributor = createWorkspaceBootstrapContributor({
|
|
113
|
-
workspaceService: {
|
|
114
|
-
async listWorkspacesForUser() {
|
|
115
|
-
assert.fail("listWorkspacesForUser should not run for unauthenticated payloads");
|
|
116
|
-
},
|
|
117
|
-
async resolveWorkspaceContextForUserBySlug() {
|
|
118
|
-
assert.fail("resolveWorkspaceContextForUserBySlug should not run for unauthenticated payloads");
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
workspacePendingInvitationsService: {
|
|
122
|
-
async listPendingInvitesForUser() {
|
|
123
|
-
assert.fail("listPendingInvitesForUser should not run for unauthenticated payloads");
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
usersRepository: {
|
|
127
|
-
async findById() {
|
|
128
|
-
assert.fail("findById should not run for unauthenticated payloads");
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
workspaceInvitationsEnabled: true,
|
|
132
|
-
appConfig: {
|
|
133
|
-
tenancyMode: "workspaces"
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const payload = await contributor.contribute({
|
|
138
|
-
query: {
|
|
139
|
-
workspaceSlug: "AcMe"
|
|
140
|
-
},
|
|
141
|
-
payload: {
|
|
142
|
-
session: {
|
|
143
|
-
authenticated: false
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
assert.deepEqual(payload, {
|
|
149
|
-
requestedWorkspace: {
|
|
150
|
-
slug: "acme",
|
|
151
|
-
status: "unauthenticated"
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { resolveWorkspaceInvitationsPolicy } from "../src/server/support/workspaceInvitationsPolicy.js";
|
|
4
|
-
|
|
5
|
-
test("workspace invitations policy enables invitations by default in personal mode", () => {
|
|
6
|
-
const policy = resolveWorkspaceInvitationsPolicy({
|
|
7
|
-
appConfig: {},
|
|
8
|
-
tenancyProfile: {
|
|
9
|
-
mode: "personal",
|
|
10
|
-
workspace: {
|
|
11
|
-
enabled: true
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
assert.equal(policy.enabled, true);
|
|
17
|
-
assert.equal(policy.allowInPersonalMode, true);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("workspace invitations policy disables invitations in personal mode when explicitly configured", () => {
|
|
21
|
-
const policy = resolveWorkspaceInvitationsPolicy({
|
|
22
|
-
appConfig: {
|
|
23
|
-
workspaceInvitations: {
|
|
24
|
-
allowInPersonalMode: false
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
tenancyProfile: {
|
|
28
|
-
mode: "personal",
|
|
29
|
-
workspace: {
|
|
30
|
-
enabled: true
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
assert.equal(policy.enabled, false);
|
|
36
|
-
assert.equal(policy.allowInPersonalMode, false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("workspace invitations policy disables invitations when workspace mode is disabled", () => {
|
|
40
|
-
const policy = resolveWorkspaceInvitationsPolicy({
|
|
41
|
-
appConfig: {},
|
|
42
|
-
tenancyProfile: {
|
|
43
|
-
mode: "none",
|
|
44
|
-
workspace: {
|
|
45
|
-
enabled: false
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
assert.equal(policy.enabled, false);
|
|
51
|
-
assert.equal(policy.workspaceEnabled, false);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("workspace invitations policy disables invitations when app config disables feature", () => {
|
|
55
|
-
const policy = resolveWorkspaceInvitationsPolicy({
|
|
56
|
-
appConfig: {
|
|
57
|
-
workspaceInvitations: {
|
|
58
|
-
enabled: false,
|
|
59
|
-
allowInPersonalMode: true
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
tenancyProfile: {
|
|
63
|
-
mode: "workspace",
|
|
64
|
-
workspace: {
|
|
65
|
-
enabled: true
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
assert.equal(policy.enabled, false);
|
|
71
|
-
});
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { createRepository } from "../src/server/common/repositories/workspaceInvitesRepository.js";
|
|
4
|
-
|
|
5
|
-
function createKnexStub() {
|
|
6
|
-
const state = {
|
|
7
|
-
insertPayload: null
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const row = {
|
|
11
|
-
id: 1,
|
|
12
|
-
workspace_id: 1,
|
|
13
|
-
email: "invitee@example.com",
|
|
14
|
-
role_sid: "member",
|
|
15
|
-
status: "pending",
|
|
16
|
-
token_hash: "hash",
|
|
17
|
-
invited_by_user_id: 1,
|
|
18
|
-
expires_at: "2026-03-16 00:26:35.709",
|
|
19
|
-
accepted_at: null,
|
|
20
|
-
revoked_at: null,
|
|
21
|
-
created_at: "2026-03-09 00:26:35.710",
|
|
22
|
-
updated_at: "2026-03-09 00:26:35.710"
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function tableBuilder(tableName) {
|
|
26
|
-
assert.equal(tableName, "workspace_invites");
|
|
27
|
-
return {
|
|
28
|
-
insert(payload) {
|
|
29
|
-
state.insertPayload = payload;
|
|
30
|
-
return Promise.resolve([1]);
|
|
31
|
-
},
|
|
32
|
-
where(criteria) {
|
|
33
|
-
assert.equal(typeof criteria, "object");
|
|
34
|
-
return {
|
|
35
|
-
first() {
|
|
36
|
-
return Promise.resolve({ ...row });
|
|
37
|
-
},
|
|
38
|
-
orderBy() {
|
|
39
|
-
return {
|
|
40
|
-
first() {
|
|
41
|
-
return Promise.resolve({ ...row });
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return { knexStub: tableBuilder, state };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
test("workspaceInvitesRepository.insert normalizes expiresAt ISO input to database datetime", async () => {
|
|
54
|
-
const { knexStub, state } = createKnexStub();
|
|
55
|
-
const repository = createRepository(knexStub);
|
|
56
|
-
|
|
57
|
-
await repository.insert({
|
|
58
|
-
workspaceId: "1",
|
|
59
|
-
email: "invitee@example.com",
|
|
60
|
-
roleSid: "member",
|
|
61
|
-
status: "pending",
|
|
62
|
-
tokenHash: "hash",
|
|
63
|
-
invitedByUserId: "1",
|
|
64
|
-
expiresAt: "2026-03-16T00:26:35.709Z"
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
assert.equal(state.insertPayload.expires_at, "2026-03-16 00:26:35.709");
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("workspaceInvitesRepository.findPendingByTokenHash reads from invites table without workspace join", async () => {
|
|
71
|
-
const calls = {
|
|
72
|
-
tableName: "",
|
|
73
|
-
whereCriteria: null
|
|
74
|
-
};
|
|
75
|
-
const row = {
|
|
76
|
-
id: 44,
|
|
77
|
-
workspace_id: 9,
|
|
78
|
-
email: "invitee@example.com",
|
|
79
|
-
role_sid: "member",
|
|
80
|
-
status: "pending",
|
|
81
|
-
token_hash: "hash-token",
|
|
82
|
-
invited_by_user_id: 1,
|
|
83
|
-
expires_at: "2030-01-01 00:00:00.000",
|
|
84
|
-
accepted_at: null,
|
|
85
|
-
revoked_at: null,
|
|
86
|
-
created_at: "2026-03-09 00:26:35.710",
|
|
87
|
-
updated_at: "2026-03-09 00:26:35.710"
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const repository = createRepository((tableName) => {
|
|
91
|
-
calls.tableName = String(tableName || "");
|
|
92
|
-
return {
|
|
93
|
-
where(criteria) {
|
|
94
|
-
calls.whereCriteria = criteria;
|
|
95
|
-
return this;
|
|
96
|
-
},
|
|
97
|
-
first() {
|
|
98
|
-
return Promise.resolve({ ...row });
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const invite = await repository.findPendingByTokenHash("hash-token");
|
|
104
|
-
assert.equal(calls.tableName, "workspace_invites");
|
|
105
|
-
assert.deepEqual(calls.whereCriteria, {
|
|
106
|
-
token_hash: "hash-token",
|
|
107
|
-
status: "pending"
|
|
108
|
-
});
|
|
109
|
-
assert.equal(invite?.workspaceId, "9");
|
|
110
|
-
assert.equal(invite?.workspaceSlug, undefined);
|
|
111
|
-
});
|