@jskit-ai/workspaces-core 0.1.137 → 0.1.138
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.json +38 -238
- package/patterns/workspace-server/PATTERN.md +60 -0
- package/src/server/WorkspacesFeature.js +226 -0
- package/src/server/WorkspacesIntegrationsProvider.js +74 -0
- package/src/server/common/contributors/workspaceActionContextContributor.js +18 -6
- package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +25 -4
- package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +22 -4
- package/src/server/common/services/workspaceContextService.js +7 -2
- package/src/server/common/support/realtimeServiceEvents.js +102 -61
- package/src/server/support/workspaceActionSurfaces.js +18 -13
- package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +5 -11
- package/src/server/workspaceDirectory/workspaceDirectoryActions.js +24 -14
- package/src/server/workspaceMembers/bootWorkspaceMembers.js +5 -12
- package/src/server/workspaceMembers/workspaceMembersActions.js +63 -23
- package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +4 -6
- package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +31 -12
- package/src/server/workspaceSettings/bootWorkspaceSettings.js +5 -8
- package/src/server/workspaceSettings/workspaceSettingsActions.js +26 -8
- package/src/server/workspaceSettings/workspaceSettingsRepository.js +4 -4
- package/test/exportsContract.test.js +2 -1
- package/test/featureRuntime.test.js +116 -0
- package/test/packageMetadata.test.js +20 -54
- package/test/workspaceActionContextContributor.test.js +49 -8
- package/test/workspaceActionSurfaces.test.js +36 -1
- package/test/workspaceAuthPolicyContextResolver.test.js +61 -0
- package/test/workspaceRouteVisibilityResolver.test.js +31 -0
- package/test/workspaceService.test.js +62 -0
- package/test/workspaceSettingsActions.test.js +102 -16
- package/test/workspacesRouteRequestInputValidator.test.js +14 -65
- package/src/server/WorkspacesCoreServiceProvider.js +0 -64
- package/src/server/registerWorkspaceBootstrap.js +0 -27
- package/src/server/registerWorkspaceCore.js +0 -101
- package/src/server/registerWorkspaceRepositories.js +0 -30
- package/src/server/support/workspaceServerScopeSupport.js +0 -18
- package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
- package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -137
- package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -130
- package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -66
- package/test/registerServiceRealtimeEvents.test.js +0 -116
- package/test/registerWorkspaceBootstrap.test.js +0 -86
- package/test/registerWorkspaceDirectory.test.js +0 -31
- package/test/registerWorkspaceMembers.test.js +0 -140
- package/test/registerWorkspaceSettings.test.js +0 -40
- package/test/workspaceServerScopeSupport.test.js +0 -131
- /package/{templates/migrations → migrations}/workspaces_core_initial.cjs +0 -0
- /package/{templates/migrations → migrations}/workspaces_core_workspace_settings_single_name_source.cjs +0 -0
- /package/{templates/migrations → migrations}/workspaces_core_workspaces_drop_color.cjs +0 -0
- /package/{templates → patterns/workspace-server/example}/config/roles.js +0 -0
- /package/{templates → patterns/workspace-server/example}/packages/main/src/server/email/workspaceInviteEmail.js +0 -0
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
INTERNAL_JSON_REST_API,
|
|
3
|
-
addResourceIfMissing,
|
|
4
|
-
createJsonRestResourceScopeOptions
|
|
5
|
-
} from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
6
|
-
import { toDatabaseDateTimeUtc } from "@jskit-ai/database-runtime/shared";
|
|
7
|
-
import { bootWorkspaceDirectoryRoutes } from "./workspaceDirectory/bootWorkspaceDirectoryRoutes.js";
|
|
8
|
-
import { registerWorkspaceDirectory } from "./workspaceDirectory/registerWorkspaceDirectory.js";
|
|
9
|
-
import {
|
|
10
|
-
registerWorkspacePendingInvitations
|
|
11
|
-
} from "./workspacePendingInvitations/registerWorkspacePendingInvitations.js";
|
|
12
|
-
import { bootWorkspacePendingInvitations } from "./workspacePendingInvitations/bootWorkspacePendingInvitations.js";
|
|
13
|
-
import { registerWorkspaceMembers } from "./workspaceMembers/registerWorkspaceMembers.js";
|
|
14
|
-
import { bootWorkspaceMembers } from "./workspaceMembers/bootWorkspaceMembers.js";
|
|
15
|
-
import { registerWorkspaceSettings } from "./workspaceSettings/registerWorkspaceSettings.js";
|
|
16
|
-
import { bootWorkspaceSettings } from "./workspaceSettings/bootWorkspaceSettings.js";
|
|
17
|
-
import { registerWorkspaceRepositories } from "./registerWorkspaceRepositories.js";
|
|
18
|
-
import { registerWorkspaceCore } from "./registerWorkspaceCore.js";
|
|
19
|
-
import { registerWorkspaceBootstrap } from "./registerWorkspaceBootstrap.js";
|
|
20
|
-
import { workspaceResource } from "../shared/resources/workspaceResource.js";
|
|
21
|
-
import { workspaceMembershipsResource } from "../shared/resources/workspaceMembershipsResource.js";
|
|
22
|
-
import { workspaceInvitesResource } from "../shared/resources/workspaceInvitesResource.js";
|
|
23
|
-
import { workspaceSettingsResource } from "../shared/resources/workspaceSettingsResource.js";
|
|
24
|
-
|
|
25
|
-
class WorkspacesCoreServiceProvider {
|
|
26
|
-
static id = "workspaces.core";
|
|
27
|
-
|
|
28
|
-
static startsAfter = ["runtime.actions", "users.core"];
|
|
29
|
-
|
|
30
|
-
async register(app) {
|
|
31
|
-
registerWorkspaceRepositories(app);
|
|
32
|
-
registerWorkspaceCore(app);
|
|
33
|
-
registerWorkspaceBootstrap(app);
|
|
34
|
-
registerWorkspaceDirectory(app);
|
|
35
|
-
registerWorkspaceMembers(app);
|
|
36
|
-
registerWorkspaceSettings(app);
|
|
37
|
-
registerWorkspacePendingInvitations(app);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async boot(app) {
|
|
41
|
-
const api = app.make(INTERNAL_JSON_REST_API);
|
|
42
|
-
const scopeOptions = {
|
|
43
|
-
writeSerializers: {
|
|
44
|
-
"datetime-utc": toDatabaseDateTimeUtc
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
await addResourceIfMissing(api, "workspaces", createJsonRestResourceScopeOptions(workspaceResource, scopeOptions));
|
|
48
|
-
await addResourceIfMissing(api, "workspaceMemberships", createJsonRestResourceScopeOptions(workspaceMembershipsResource, scopeOptions));
|
|
49
|
-
await addResourceIfMissing(api, "workspaceInvites", createJsonRestResourceScopeOptions(workspaceInvitesResource, scopeOptions));
|
|
50
|
-
await addResourceIfMissing(api, "workspaceSettings", createJsonRestResourceScopeOptions(workspaceSettingsResource, scopeOptions));
|
|
51
|
-
if (app.make("workspaces.enabled") !== true) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
bootWorkspaceDirectoryRoutes(app);
|
|
56
|
-
if (app.make("workspaces.invitations.enabled") === true) {
|
|
57
|
-
bootWorkspacePendingInvitations(app);
|
|
58
|
-
}
|
|
59
|
-
bootWorkspaceSettings(app);
|
|
60
|
-
bootWorkspaceMembers(app);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { WorkspacesCoreServiceProvider };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { registerBootstrapPayloadContributor } from "@jskit-ai/kernel/server/runtime";
|
|
2
|
-
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
3
|
-
import { createWorkspaceBootstrapContributor } from "./workspaceBootstrapContributor.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function registerWorkspaceBootstrap(app) {
|
|
7
|
-
if (!app || typeof app.singleton !== "function") {
|
|
8
|
-
throw new Error("registerWorkspaceBootstrap requires application singleton().");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
registerBootstrapPayloadContributor(app, "workspaces.core.bootstrap.payloadContributor", (scope) => {
|
|
12
|
-
const workspaceInvitationsEnabled = scope.make("workspaces.invitations.enabled");
|
|
13
|
-
|
|
14
|
-
return createWorkspaceBootstrapContributor({
|
|
15
|
-
workspaceService: scope.make("workspaces.service"),
|
|
16
|
-
workspacePendingInvitationsService: workspaceInvitationsEnabled
|
|
17
|
-
? scope.make("workspaces.pending-invitations.service")
|
|
18
|
-
: null,
|
|
19
|
-
workspaceInvitationsEnabled,
|
|
20
|
-
userProfilesRepository: scope.make("internal.repository.user-profiles"),
|
|
21
|
-
appConfig: resolveAppConfig(scope),
|
|
22
|
-
tenancyProfile: scope.make("workspaces.tenancy.profile")
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { registerWorkspaceBootstrap };
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
registerActionContextContributor
|
|
3
|
-
} from "@jskit-ai/kernel/server/actions";
|
|
4
|
-
import { registerRouteVisibilityResolver } from "@jskit-ai/kernel/server/http";
|
|
5
|
-
import { registerAuthPolicyContextResolver } from "@jskit-ai/auth-core/server/authPolicyContextResolverRegistry";
|
|
6
|
-
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
7
|
-
import { registerProfileSyncLifecycleContributor } from "@jskit-ai/users-core/server/profileSyncLifecycleContributorRegistry";
|
|
8
|
-
import { createService as createWorkspaceService } from "./common/services/workspaceContextService.js";
|
|
9
|
-
import { createWorkspaceActionContextContributor } from "./common/contributors/workspaceActionContextContributor.js";
|
|
10
|
-
import { createWorkspaceRouteVisibilityResolver } from "./common/contributors/workspaceRouteVisibilityResolver.js";
|
|
11
|
-
import { createWorkspaceAuthPolicyContextResolver } from "./common/contributors/workspaceAuthPolicyContextResolver.js";
|
|
12
|
-
import { TENANCY_MODE_WORKSPACES, resolveTenancyProfile } from "../shared/tenancyProfile.js";
|
|
13
|
-
import { resolveWorkspaceInvitationsPolicy } from "./support/workspaceInvitationsPolicy.js";
|
|
14
|
-
import {
|
|
15
|
-
registerWorkspaceActionSurfaceSources,
|
|
16
|
-
resolveWorkspaceSurfaceIdsFromAppConfig
|
|
17
|
-
} from "./support/workspaceActionSurfaces.js";
|
|
18
|
-
import { createWorkspaceServerScopeSupport } from "./support/workspaceServerScopeSupport.js";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function registerWorkspaceCore(app) {
|
|
22
|
-
if (!app || typeof app.singleton !== "function") {
|
|
23
|
-
throw new Error("registerWorkspaceCore requires application singleton().");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
registerWorkspaceActionSurfaceSources(app);
|
|
27
|
-
|
|
28
|
-
app.singleton("workspaces.tenancy.profile", (scope) => {
|
|
29
|
-
const appConfig = resolveAppConfig(scope);
|
|
30
|
-
return resolveTenancyProfile(appConfig);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
app.singleton("workspaces.service", (scope) => {
|
|
34
|
-
const appConfig = resolveAppConfig(scope);
|
|
35
|
-
return createWorkspaceService({
|
|
36
|
-
appConfig,
|
|
37
|
-
workspacesRepository: scope.make("internal.repository.workspaces"),
|
|
38
|
-
workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships"),
|
|
39
|
-
workspaceSettingsRepository: scope.make("internal.repository.workspace-settings")
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
app.singleton("workspaces.enabled", (scope) => {
|
|
43
|
-
return scope.make("workspaces.tenancy.profile").workspace.enabled === true;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
app.singleton("workspaces.self-create.enabled", (scope) => {
|
|
47
|
-
return scope.make("workspaces.tenancy.profile").workspace.allowSelfCreate === true;
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
app.singleton("workspaces.tenancy.enabled", (scope) => {
|
|
51
|
-
return scope.make("workspaces.tenancy.profile").mode === TENANCY_MODE_WORKSPACES;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
app.singleton("workspaces.invitations.enabled", (scope) => {
|
|
55
|
-
const appConfig = resolveAppConfig(scope);
|
|
56
|
-
const tenancyProfile = scope.make("workspaces.tenancy.profile");
|
|
57
|
-
return resolveWorkspaceInvitationsPolicy({
|
|
58
|
-
appConfig,
|
|
59
|
-
tenancyProfile
|
|
60
|
-
}).enabled;
|
|
61
|
-
});
|
|
62
|
-
app.singleton("workspaces.server.scope-support", () => createWorkspaceServerScopeSupport());
|
|
63
|
-
|
|
64
|
-
registerProfileSyncLifecycleContributor(app, "workspaces.core.profileSyncLifecycleContributor", (scope) => {
|
|
65
|
-
const workspaceService = scope.make("workspaces.service");
|
|
66
|
-
|
|
67
|
-
return Object.freeze({
|
|
68
|
-
contributorId: "workspaces.core.profileSync",
|
|
69
|
-
order: 100,
|
|
70
|
-
async afterIdentityProfileSynced({ profile, options } = {}) {
|
|
71
|
-
if (!profile || typeof workspaceService?.ensureProvisionedWorkspaceForAuthenticatedUser !== "function") {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
await workspaceService.ensureProvisionedWorkspaceForAuthenticatedUser(profile, options);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
registerActionContextContributor(app, "users.core.workspace.actionContextContributor", (scope) => {
|
|
81
|
-
const appConfig = resolveAppConfig(scope);
|
|
82
|
-
return createWorkspaceActionContextContributor({
|
|
83
|
-
workspaceService: scope.make("workspaces.service"),
|
|
84
|
-
workspaceSurfaceIds: resolveWorkspaceSurfaceIdsFromAppConfig(appConfig)
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
registerAuthPolicyContextResolver(app, "workspaces.core.authPolicyContextResolver", (scope) =>
|
|
89
|
-
createWorkspaceAuthPolicyContextResolver({
|
|
90
|
-
workspaceService: scope.make("workspaces.service")
|
|
91
|
-
})
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
registerRouteVisibilityResolver(app, "users.core.workspace.routeVisibilityResolver", (scope) =>
|
|
95
|
-
createWorkspaceRouteVisibilityResolver({
|
|
96
|
-
workspaceService: scope.make("workspaces.service")
|
|
97
|
-
})
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export { registerWorkspaceCore };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { INTERNAL_JSON_REST_API } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
2
|
-
import { createRepository as createWorkspacesRepository } from "./common/repositories/workspacesRepository.js";
|
|
3
|
-
import { createRepository as createWorkspaceMembershipsRepository } from "./common/repositories/workspaceMembershipsRepository.js";
|
|
4
|
-
import { createRepository as createWorkspaceInvitesRepository } from "./common/repositories/workspaceInvitesRepository.js";
|
|
5
|
-
|
|
6
|
-
function registerWorkspaceRepositories(app) {
|
|
7
|
-
if (!app || typeof app.singleton !== "function") {
|
|
8
|
-
throw new Error("registerWorkspaceRepositories requires application singleton().");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
app.singleton("internal.repository.workspaces", (scope) => {
|
|
12
|
-
const api = scope.make(INTERNAL_JSON_REST_API);
|
|
13
|
-
const knex = scope.make("jskit.database.knex");
|
|
14
|
-
return createWorkspacesRepository({ api, knex });
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
app.singleton("internal.repository.workspace-memberships", (scope) => {
|
|
18
|
-
const api = scope.make(INTERNAL_JSON_REST_API);
|
|
19
|
-
const knex = scope.make("jskit.database.knex");
|
|
20
|
-
return createWorkspaceMembershipsRepository({ api, knex });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
app.singleton("internal.repository.workspace-invites", (scope) => {
|
|
24
|
-
const api = scope.make(INTERNAL_JSON_REST_API);
|
|
25
|
-
const knex = scope.make("jskit.database.knex");
|
|
26
|
-
return createWorkspaceInvitesRepository({ api, knex });
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export { registerWorkspaceRepositories };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { workspaceSlugParamsValidator } from "../common/validators/routeParamsValidator.js";
|
|
2
|
-
import { buildWorkspaceInputFromRouteParams } from "./workspaceRouteInput.js";
|
|
3
|
-
import { resolveWorkspace } from "./resolveWorkspace.js";
|
|
4
|
-
|
|
5
|
-
function createWorkspaceServerScopeSupport() {
|
|
6
|
-
return Object.freeze({
|
|
7
|
-
available: true,
|
|
8
|
-
params: workspaceSlugParamsValidator,
|
|
9
|
-
buildInputFromRouteParams(params = {}) {
|
|
10
|
-
return buildWorkspaceInputFromRouteParams(params);
|
|
11
|
-
},
|
|
12
|
-
resolveWorkspace(context = {}, input = {}) {
|
|
13
|
-
return resolveWorkspace(context, input);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export { createWorkspaceServerScopeSupport };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
-
import { workspaceDirectoryActions } from "./workspaceDirectoryActions.js";
|
|
3
|
-
|
|
4
|
-
function registerWorkspaceDirectory(app) {
|
|
5
|
-
if (!app || typeof app.singleton !== "function" || typeof app.actions !== "function") {
|
|
6
|
-
throw new Error("registerWorkspaceDirectory requires application singleton()/actions().");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
app.actions(
|
|
10
|
-
withActionDefaults(workspaceDirectoryActions, {
|
|
11
|
-
domain: "workspace",
|
|
12
|
-
dependencies: {
|
|
13
|
-
workspaceService: "workspaces.service"
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { registerWorkspaceDirectory };
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
-
import { normalizeDbRecordId } from "@jskit-ai/database-runtime/shared";
|
|
3
|
-
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
4
|
-
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
5
|
-
import { deepFreeze } from "../common/support/deepFreeze.js";
|
|
6
|
-
import { createService as createWorkspaceMembersService } from "./workspaceMembersService.js";
|
|
7
|
-
import { workspaceMembersActions } from "./workspaceMembersActions.js";
|
|
8
|
-
import { createWorkspaceRoleCatalog } from "../../shared/roles.js";
|
|
9
|
-
import { createWorkspaceEntityAndBootstrapEvents } from "../common/support/realtimeServiceEvents.js";
|
|
10
|
-
import { renderDefaultWorkspaceInviteEmail } from "./defaultWorkspaceInviteEmail.js";
|
|
11
|
-
import { createWorkspaceInviteUrlBuilder } from "./workspaceInviteUrls.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function resolveWorkspaceMembersInviteExpiresInMs(appConfig = {}) {
|
|
15
|
-
const inviteExpiresInMs = Number(appConfig?.workspaceMembers?.defaults?.inviteExpiresInMs);
|
|
16
|
-
if (!Number.isInteger(inviteExpiresInMs) || inviteExpiresInMs < 1) {
|
|
17
|
-
throw new TypeError("users.core requires appConfig.workspaceMembers.defaults.inviteExpiresInMs.");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return inviteExpiresInMs;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function resolveWorkspaceInviteEmailTemplate(scope, appConfig = {}) {
|
|
24
|
-
if (typeof scope.has === "function" && scope.has("workspaces.invite.emailTemplate")) {
|
|
25
|
-
return scope.make("workspaces.invite.emailTemplate");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const configuredTemplate =
|
|
29
|
-
appConfig.workspaceInviteEmailTemplate ||
|
|
30
|
-
appConfig.workspaceInviteEmailRenderer ||
|
|
31
|
-
appConfig.workspaceInvitations?.emailTemplate ||
|
|
32
|
-
appConfig.workspaceInvitations?.emailRenderer;
|
|
33
|
-
if (typeof configuredTemplate === "function") {
|
|
34
|
-
return configuredTemplate;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return renderDefaultWorkspaceInviteEmail;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const INVITE_RECIPIENT_BOOTSTRAP_AUDIENCE = Object.freeze({
|
|
41
|
-
preset: "event_scope",
|
|
42
|
-
async userQuery({ knex, event } = {}) {
|
|
43
|
-
if (typeof knex !== "function") {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const inviteId = normalizeRecordId(event?.entityId, { fallback: null });
|
|
48
|
-
if (!inviteId) {
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const row = await knex("workspace_invites as wi")
|
|
53
|
-
.join("users as up", "up.email", "wi.email")
|
|
54
|
-
.where("wi.id", inviteId)
|
|
55
|
-
.first("up.id as user_id");
|
|
56
|
-
|
|
57
|
-
const userId = normalizeDbRecordId(row?.user_id, { fallback: null });
|
|
58
|
-
if (!userId) {
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return [
|
|
63
|
-
{
|
|
64
|
-
userId
|
|
65
|
-
}
|
|
66
|
-
];
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
function registerWorkspaceMembers(app) {
|
|
71
|
-
if (!app || typeof app.singleton !== "function" || typeof app.service !== "function" || typeof app.actions !== "function") {
|
|
72
|
-
throw new Error("registerWorkspaceMembers requires application singleton()/service()/actions().");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
app.service(
|
|
76
|
-
"workspaces.members.service",
|
|
77
|
-
(scope) => {
|
|
78
|
-
const appConfig = resolveAppConfig(scope);
|
|
79
|
-
const env = typeof scope.has === "function" && scope.has("jskit.env") ? scope.make("jskit.env") : process.env;
|
|
80
|
-
return createWorkspaceMembersService({
|
|
81
|
-
workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships"),
|
|
82
|
-
workspaceInvitesRepository: scope.make("internal.repository.workspace-invites"),
|
|
83
|
-
inviteExpiresInMs: resolveWorkspaceMembersInviteExpiresInMs(appConfig),
|
|
84
|
-
roleCatalog: createWorkspaceRoleCatalog(appConfig),
|
|
85
|
-
workspaceInvitationsEnabled: scope.make("workspaces.invitations.enabled") === true,
|
|
86
|
-
inviteUrlBuilder: createWorkspaceInviteUrlBuilder({
|
|
87
|
-
appConfig,
|
|
88
|
-
env
|
|
89
|
-
}),
|
|
90
|
-
workspaceInviteMailer:
|
|
91
|
-
typeof scope.has === "function" && scope.has("workspaces.invite.mailer")
|
|
92
|
-
? scope.make("workspaces.invite.mailer")
|
|
93
|
-
: null,
|
|
94
|
-
workspaceInviteEmailTemplate: resolveWorkspaceInviteEmailTemplate(scope, appConfig)
|
|
95
|
-
});
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
events: deepFreeze({
|
|
99
|
-
updateMemberRole: createWorkspaceEntityAndBootstrapEvents({
|
|
100
|
-
workspaceEntity: "member",
|
|
101
|
-
workspaceOperation: "updated",
|
|
102
|
-
workspaceRealtimeEvent: "workspace.members.changed"
|
|
103
|
-
}),
|
|
104
|
-
removeMember: createWorkspaceEntityAndBootstrapEvents({
|
|
105
|
-
workspaceEntity: "member",
|
|
106
|
-
workspaceOperation: "updated",
|
|
107
|
-
workspaceRealtimeEvent: "workspace.members.changed"
|
|
108
|
-
}),
|
|
109
|
-
createInvite: createWorkspaceEntityAndBootstrapEvents({
|
|
110
|
-
workspaceEntity: "invite",
|
|
111
|
-
workspaceOperation: "created",
|
|
112
|
-
workspaceRealtimeEvent: "workspace.invites.changed",
|
|
113
|
-
bootstrapEntityId: ({ result }) => result?.createdInviteId,
|
|
114
|
-
bootstrapAudience: INVITE_RECIPIENT_BOOTSTRAP_AUDIENCE
|
|
115
|
-
}),
|
|
116
|
-
revokeInvite: createWorkspaceEntityAndBootstrapEvents({
|
|
117
|
-
workspaceEntity: "invite",
|
|
118
|
-
workspaceOperation: "updated",
|
|
119
|
-
workspaceRealtimeEvent: "workspace.invites.changed",
|
|
120
|
-
bootstrapEntityId: ({ result }) => result?.revokedInviteId,
|
|
121
|
-
bootstrapAudience: INVITE_RECIPIENT_BOOTSTRAP_AUDIENCE
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
app.actions(
|
|
128
|
-
withActionDefaults(workspaceMembersActions, {
|
|
129
|
-
domain: "workspace",
|
|
130
|
-
dependencies: {
|
|
131
|
-
workspaceMembersService: "workspaces.members.service"
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export { registerWorkspaceMembers };
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
-
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
3
|
-
import { createService } from "./workspacePendingInvitationsService.js";
|
|
4
|
-
import { workspacePendingInvitationsActions } from "./workspacePendingInvitationsActions.js";
|
|
5
|
-
import { deepFreeze } from "../common/support/deepFreeze.js";
|
|
6
|
-
|
|
7
|
-
function workspaceAudienceFromEntityId({ event } = {}) {
|
|
8
|
-
const workspaceId = normalizeRecordId(event?.entityId, { fallback: null });
|
|
9
|
-
if (!workspaceId) {
|
|
10
|
-
return "none";
|
|
11
|
-
}
|
|
12
|
-
return {
|
|
13
|
-
workspaceId
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function actorUserEntityId({ options } = {}) {
|
|
18
|
-
return normalizeRecordId(options?.context?.actor?.id, { fallback: "" });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function createActorUserEvent({ source, entity, realtimeEvent }) {
|
|
22
|
-
return {
|
|
23
|
-
type: "entity.changed",
|
|
24
|
-
source,
|
|
25
|
-
entity,
|
|
26
|
-
operation: "updated",
|
|
27
|
-
entityId: actorUserEntityId,
|
|
28
|
-
realtime: {
|
|
29
|
-
event: realtimeEvent,
|
|
30
|
-
audience: "actor_user"
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function createWorkspaceAudienceEvent({ entity, realtimeEvent }) {
|
|
36
|
-
return {
|
|
37
|
-
type: "entity.changed",
|
|
38
|
-
source: "workspace",
|
|
39
|
-
entity,
|
|
40
|
-
operation: "updated",
|
|
41
|
-
entityId: ({ result }) => normalizeRecordId(result?.workspaceId, { fallback: "" }),
|
|
42
|
-
realtime: {
|
|
43
|
-
event: realtimeEvent,
|
|
44
|
-
audience: workspaceAudienceFromEntityId
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function createInviteDecisionEvents({ includeDirectoryAndMembers = false } = {}) {
|
|
50
|
-
const events = [
|
|
51
|
-
createActorUserEvent({
|
|
52
|
-
source: "workspace",
|
|
53
|
-
entity: "invitation",
|
|
54
|
-
realtimeEvent: "workspace.invitations.pending.changed"
|
|
55
|
-
}),
|
|
56
|
-
createActorUserEvent({
|
|
57
|
-
source: "users",
|
|
58
|
-
entity: "bootstrap",
|
|
59
|
-
realtimeEvent: "users.bootstrap.changed"
|
|
60
|
-
})
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
if (includeDirectoryAndMembers) {
|
|
64
|
-
events.push(
|
|
65
|
-
createActorUserEvent({
|
|
66
|
-
source: "workspace",
|
|
67
|
-
entity: "directory",
|
|
68
|
-
realtimeEvent: "workspaces.changed"
|
|
69
|
-
}),
|
|
70
|
-
createWorkspaceAudienceEvent({
|
|
71
|
-
entity: "member",
|
|
72
|
-
realtimeEvent: "workspace.members.changed"
|
|
73
|
-
})
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
events.push(
|
|
78
|
-
createWorkspaceAudienceEvent({
|
|
79
|
-
entity: "invite",
|
|
80
|
-
realtimeEvent: "workspace.invites.changed"
|
|
81
|
-
})
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
return events;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function registerWorkspacePendingInvitations(app) {
|
|
88
|
-
if (!app || typeof app.singleton !== "function" || typeof app.service !== "function" || typeof app.actions !== "function") {
|
|
89
|
-
throw new Error("registerWorkspacePendingInvitations requires application singleton()/service()/actions().");
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
app.service(
|
|
93
|
-
"workspaces.pending-invitations.service",
|
|
94
|
-
(scope) =>
|
|
95
|
-
createService({
|
|
96
|
-
workspaceInvitesRepository: scope.make("internal.repository.workspace-invites"),
|
|
97
|
-
workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships")
|
|
98
|
-
}),
|
|
99
|
-
{
|
|
100
|
-
events: deepFreeze({
|
|
101
|
-
acceptInviteByToken: createInviteDecisionEvents({
|
|
102
|
-
includeDirectoryAndMembers: true
|
|
103
|
-
}),
|
|
104
|
-
refuseInviteByToken: createInviteDecisionEvents()
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
if (typeof app.has === "function" && !app.has("auth.invitationContextResolver")) {
|
|
110
|
-
app.singleton("auth.invitationContextResolver", (scope) => {
|
|
111
|
-
const service = scope.make("workspaces.pending-invitations.service");
|
|
112
|
-
return {
|
|
113
|
-
async resolveInvitationContext(invitation, options = {}) {
|
|
114
|
-
return service.resolveInviteContextForAuth(invitation, options);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
app.actions(
|
|
121
|
-
withActionDefaults(workspacePendingInvitationsActions, {
|
|
122
|
-
domain: "workspace",
|
|
123
|
-
dependencies: {
|
|
124
|
-
workspacePendingInvitationsService: "workspaces.pending-invitations.service"
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export { registerWorkspacePendingInvitations };
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
-
import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
|
|
3
|
-
import { INTERNAL_JSON_REST_API } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
|
|
4
|
-
import { deepFreeze } from "../common/support/deepFreeze.js";
|
|
5
|
-
import { createRepository as createWorkspaceSettingsRepository } from "./workspaceSettingsRepository.js";
|
|
6
|
-
import { createService as createWorkspaceSettingsService } from "./workspaceSettingsService.js";
|
|
7
|
-
import { workspaceSettingsActions } from "./workspaceSettingsActions.js";
|
|
8
|
-
import { createWorkspaceRoleCatalog } from "../../shared/roles.js";
|
|
9
|
-
import { createWorkspaceEntityAndBootstrapEvents } from "../common/support/realtimeServiceEvents.js";
|
|
10
|
-
|
|
11
|
-
function resolveWorkspaceSettingsDefaultInvitesEnabled(appConfig = {}) {
|
|
12
|
-
const defaultInvitesEnabled = appConfig?.workspaceSettings?.defaults?.invitesEnabled;
|
|
13
|
-
|
|
14
|
-
if (typeof defaultInvitesEnabled !== "boolean") {
|
|
15
|
-
throw new TypeError("users.core requires appConfig.workspaceSettings.defaults.invitesEnabled.");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return defaultInvitesEnabled;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function registerWorkspaceSettings(app) {
|
|
22
|
-
if (!app || typeof app.singleton !== "function" || typeof app.actions !== "function" || typeof app.service !== "function") {
|
|
23
|
-
throw new Error("registerWorkspaceSettings requires application singleton()/service()/actions().");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
app.singleton("internal.repository.workspace-settings", (scope) => {
|
|
27
|
-
const api = scope.make(INTERNAL_JSON_REST_API);
|
|
28
|
-
const knex = scope.make("jskit.database.knex");
|
|
29
|
-
const appConfig = resolveAppConfig(scope);
|
|
30
|
-
return createWorkspaceSettingsRepository({
|
|
31
|
-
api,
|
|
32
|
-
knex,
|
|
33
|
-
defaultInvitesEnabled: resolveWorkspaceSettingsDefaultInvitesEnabled(appConfig)
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
app.service(
|
|
38
|
-
"workspaces.settings.service",
|
|
39
|
-
(scope) =>
|
|
40
|
-
createWorkspaceSettingsService({
|
|
41
|
-
workspaceSettingsRepository: scope.make("internal.repository.workspace-settings"),
|
|
42
|
-
workspaceInvitationsEnabled: scope.make("workspaces.invitations.enabled"),
|
|
43
|
-
roleCatalog: createWorkspaceRoleCatalog(resolveAppConfig(scope))
|
|
44
|
-
}),
|
|
45
|
-
{
|
|
46
|
-
events: deepFreeze({
|
|
47
|
-
updateWorkspaceSettings: createWorkspaceEntityAndBootstrapEvents({
|
|
48
|
-
workspaceEntity: "settings",
|
|
49
|
-
workspaceOperation: "updated",
|
|
50
|
-
workspaceRealtimeEvent: "workspace.settings.changed"
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
app.actions(
|
|
57
|
-
withActionDefaults(workspaceSettingsActions, {
|
|
58
|
-
domain: "workspace",
|
|
59
|
-
dependencies: {
|
|
60
|
-
workspaceSettingsService: "workspaces.settings.service"
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export { registerWorkspaceSettings };
|