@jskit-ai/users-core 0.1.48 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/package.descriptor.mjs +7 -7
  2. package/package.json +7 -17
  3. package/src/server/common/services/authProfileSyncService.js +28 -7
  4. package/src/server/common/support/realtimeServiceEvents.js +1 -59
  5. package/src/server/profileSyncLifecycleContributorRegistry.js +56 -0
  6. package/src/server/registerUsersBootstrap.js +0 -1
  7. package/src/server/registerUsersCore.js +2 -14
  8. package/src/server/usersBootstrapContributor.js +2 -64
  9. package/src/shared/index.js +2 -99
  10. package/src/shared/settings.js +1 -119
  11. package/test/authProfileSyncService.test.js +19 -10
  12. package/test/registerServiceRealtimeEvents.test.js +0 -86
  13. package/test/registerUsersCore.test.js +6 -15
  14. package/test/repositoryContracts.test.js +1 -9
  15. package/test/resourcesCanonical.test.js +0 -16
  16. package/test/settingsFieldRegistriesSingleton.test.js +0 -5
  17. package/test/usersBootstrapContributor.test.js +2 -26
  18. package/test/usersRouteResources.test.js +0 -16
  19. package/src/server/UsersWorkspacesServiceProvider.js +0 -44
  20. package/src/server/common/contributors/workspaceActionContextContributor.js +0 -88
  21. package/src/server/common/contributors/workspaceAuthPolicyContextResolver.js +0 -34
  22. package/src/server/common/contributors/workspaceRouteVisibilityResolver.js +0 -78
  23. package/src/server/common/formatters/workspaceFormatter.js +0 -53
  24. package/src/server/common/repositories/workspaceInvitesRepository.js +0 -208
  25. package/src/server/common/repositories/workspaceMembershipsRepository.js +0 -190
  26. package/src/server/common/repositories/workspacesRepository.js +0 -202
  27. package/src/server/common/services/workspaceContextService.js +0 -281
  28. package/src/server/common/support/workspaceRoutePaths.js +0 -17
  29. package/src/server/common/validators/routeParamsValidator.js +0 -62
  30. package/src/server/registerWorkspaceBootstrap.js +0 -27
  31. package/src/server/registerWorkspaceCore.js +0 -73
  32. package/src/server/registerWorkspaceRepositories.js +0 -26
  33. package/src/server/support/resolveWorkspace.js +0 -16
  34. package/src/server/support/workspaceActionSurfaces.js +0 -118
  35. package/src/server/support/workspaceInvitationsPolicy.js +0 -45
  36. package/src/server/support/workspaceRouteInput.js +0 -22
  37. package/src/server/workspaceBootstrapContributor.js +0 -212
  38. package/src/server/workspaceDirectory/bootWorkspaceDirectoryRoutes.js +0 -133
  39. package/src/server/workspaceDirectory/registerWorkspaceDirectory.js +0 -19
  40. package/src/server/workspaceDirectory/workspaceDirectoryActions.js +0 -133
  41. package/src/server/workspaceMembers/bootWorkspaceMembers.js +0 -236
  42. package/src/server/workspaceMembers/registerWorkspaceMembers.js +0 -108
  43. package/src/server/workspaceMembers/workspaceMembersActions.js +0 -186
  44. package/src/server/workspaceMembers/workspaceMembersService.js +0 -222
  45. package/src/server/workspacePendingInvitations/bootWorkspacePendingInvitations.js +0 -62
  46. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +0 -119
  47. package/src/server/workspacePendingInvitations/workspacePendingInvitationsActions.js +0 -74
  48. package/src/server/workspacePendingInvitations/workspacePendingInvitationsService.js +0 -138
  49. package/src/server/workspaceSettings/bootWorkspaceSettings.js +0 -76
  50. package/src/server/workspaceSettings/registerWorkspaceSettings.js +0 -62
  51. package/src/server/workspaceSettings/workspaceSettingsActions.js +0 -72
  52. package/src/server/workspaceSettings/workspaceSettingsRepository.js +0 -154
  53. package/src/server/workspaceSettings/workspaceSettingsService.js +0 -66
  54. package/src/shared/resources/workspaceMembersResource.js +0 -354
  55. package/src/shared/resources/workspacePendingInvitationsResource.js +0 -82
  56. package/src/shared/resources/workspaceResource.js +0 -176
  57. package/src/shared/resources/workspaceSettingsFields.js +0 -59
  58. package/src/shared/resources/workspaceSettingsResource.js +0 -169
  59. package/src/shared/roles.js +0 -161
  60. package/src/shared/support/usersApiPaths.js +0 -43
  61. package/src/shared/support/usersVisibility.js +0 -42
  62. package/src/shared/support/workspacePathModel.js +0 -145
  63. package/src/shared/tenancyMode.js +0 -35
  64. package/src/shared/tenancyProfile.js +0 -73
  65. package/test/registerWorkspaceDirectory.test.js +0 -31
  66. package/test/registerWorkspaceSettings.test.js +0 -40
  67. package/test/roles.test.js +0 -159
  68. package/test/tenancyProfile.test.js +0 -67
  69. package/test/usersApiPaths.test.js +0 -49
  70. package/test/usersRouteValidators.test.js +0 -49
  71. package/test/usersVisibility.test.js +0 -27
  72. package/test/workspaceActionContextContributor.test.js +0 -344
  73. package/test/workspaceActionSurfaces.test.js +0 -85
  74. package/test/workspaceAuthPolicyContextResolver.test.js +0 -119
  75. package/test/workspaceBootstrapContributor.test.js +0 -154
  76. package/test/workspaceInvitationsPolicy.test.js +0 -71
  77. package/test/workspaceInvitesRepository.test.js +0 -111
  78. package/test/workspaceMembersService.test.js +0 -398
  79. package/test/workspacePathModel.test.js +0 -93
  80. package/test/workspacePendingInvitationsResource.test.js +0 -38
  81. package/test/workspacePendingInvitationsService.test.js +0 -151
  82. package/test/workspaceRouteVisibilityResolver.test.js +0 -83
  83. package/test/workspaceService.test.js +0 -546
  84. package/test/workspaceSettingsActions.test.js +0 -52
  85. package/test/workspaceSettingsRepository.test.js +0 -202
  86. package/test/workspaceSettingsResource.test.js +0 -169
  87. package/test/workspaceSettingsService.test.js +0 -140
@@ -1,62 +0,0 @@
1
- import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
2
- import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
3
- import { deepFreeze } from "../common/support/deepFreeze.js";
4
- import { createRepository as createWorkspaceSettingsRepository } from "./workspaceSettingsRepository.js";
5
- import { createService as createWorkspaceSettingsService } from "./workspaceSettingsService.js";
6
- import { workspaceSettingsActions } from "./workspaceSettingsActions.js";
7
- import { createWorkspaceRoleCatalog } from "../../shared/roles.js";
8
- import { createWorkspaceEntityAndBootstrapEvents } from "../common/support/realtimeServiceEvents.js";
9
-
10
- function resolveWorkspaceSettingsDefaultInvitesEnabled(appConfig = {}) {
11
- const defaultInvitesEnabled = appConfig?.workspaceSettings?.defaults?.invitesEnabled;
12
-
13
- if (typeof defaultInvitesEnabled !== "boolean") {
14
- throw new TypeError("users.core requires appConfig.workspaceSettings.defaults.invitesEnabled.");
15
- }
16
-
17
- return defaultInvitesEnabled;
18
- }
19
-
20
- function registerWorkspaceSettings(app) {
21
- if (!app || typeof app.singleton !== "function" || typeof app.actions !== "function" || typeof app.service !== "function") {
22
- throw new Error("registerWorkspaceSettings requires application singleton()/service()/actions().");
23
- }
24
-
25
- app.singleton("workspaceSettingsRepository", (scope) => {
26
- const knex = scope.make("jskit.database.knex");
27
- const appConfig = resolveAppConfig(scope);
28
- return createWorkspaceSettingsRepository(knex, {
29
- defaultInvitesEnabled: resolveWorkspaceSettingsDefaultInvitesEnabled(appConfig)
30
- });
31
- });
32
-
33
- app.service(
34
- "users.workspace.settings.service",
35
- (scope) =>
36
- createWorkspaceSettingsService({
37
- workspaceSettingsRepository: scope.make("workspaceSettingsRepository"),
38
- workspaceInvitationsEnabled: scope.make("users.workspace.invitations.enabled"),
39
- roleCatalog: createWorkspaceRoleCatalog(resolveAppConfig(scope))
40
- }),
41
- {
42
- events: deepFreeze({
43
- updateWorkspaceSettings: createWorkspaceEntityAndBootstrapEvents({
44
- workspaceEntity: "settings",
45
- workspaceOperation: "updated",
46
- workspaceRealtimeEvent: "workspace.settings.changed"
47
- })
48
- })
49
- }
50
- );
51
-
52
- app.actions(
53
- withActionDefaults(workspaceSettingsActions, {
54
- domain: "workspace",
55
- dependencies: {
56
- workspaceSettingsService: "users.workspace.settings.service"
57
- }
58
- })
59
- );
60
- }
61
-
62
- export { registerWorkspaceSettings };
@@ -1,72 +0,0 @@
1
- import { workspaceSettingsResource } from "../../shared/resources/workspaceSettingsResource.js";
2
- import { workspaceSlugParamsValidator } from "../common/validators/routeParamsValidator.js";
3
- import { resolveWorkspace } from "../support/resolveWorkspace.js";
4
-
5
- const workspaceSettingsActions = Object.freeze([
6
- {
7
- id: "workspace.settings.read",
8
- version: 1,
9
- kind: "query",
10
- channels: ["api", "automation", "internal"],
11
- surfacesFrom: "workspace",
12
- permission: {
13
- require: "any",
14
- permissions: ["workspace.settings.view", "workspace.settings.update"]
15
- },
16
- inputValidator: workspaceSlugParamsValidator,
17
- outputValidator: workspaceSettingsResource.operations.view.outputValidator,
18
- idempotency: "none",
19
- audit: {
20
- actionName: "workspace.settings.read"
21
- },
22
- observability: {},
23
- async execute(input, context, deps) {
24
- const response = await deps.workspaceSettingsService.getWorkspaceSettings(resolveWorkspace(context, input), {
25
- context
26
- });
27
-
28
- return response;
29
- }
30
- },
31
- {
32
- id: "workspace.settings.update",
33
- version: 1,
34
- kind: "command",
35
- channels: ["api", "assistant_tool", "automation", "internal"],
36
- surfacesFrom: "workspace",
37
- permission: {
38
- require: "all",
39
- permissions: ["workspace.settings.update"]
40
- },
41
- inputValidator: [
42
- workspaceSlugParamsValidator,
43
- {
44
- patch: workspaceSettingsResource.operations.patch.bodyValidator
45
- }
46
- ],
47
- outputValidator: workspaceSettingsResource.operations.patch.outputValidator,
48
- idempotency: "optional",
49
- audit: {
50
- actionName: "workspace.settings.update"
51
- },
52
- observability: {},
53
- extensions: {
54
- assistant: {
55
- description: "Update workspace settings."
56
- }
57
- },
58
- async execute(input, context, deps) {
59
- const response = await deps.workspaceSettingsService.updateWorkspaceSettings(
60
- resolveWorkspace(context, input),
61
- input.patch,
62
- {
63
- context
64
- }
65
- );
66
-
67
- return response;
68
- }
69
- }
70
- ]);
71
-
72
- export { workspaceSettingsActions };
@@ -1,154 +0,0 @@
1
- import {
2
- normalizeDbRecordId,
3
- normalizeRecordId,
4
- toIsoString,
5
- nowDb,
6
- isDuplicateEntryError,
7
- createWithTransaction
8
- } from "../common/repositories/repositoryUtils.js";
9
- import { normalizeObjectInput } from "@jskit-ai/kernel/shared/validators/inputNormalization";
10
- import { pickOwnProperties } from "@jskit-ai/kernel/shared/support";
11
- import {
12
- workspaceSettingsFields,
13
- resolveWorkspaceSettingsFieldKeys
14
- } from "../../shared/resources/workspaceSettingsFields.js";
15
-
16
- function resolveWorkspaceSettingsSeed(workspace = {}, { defaultInvitesEnabled = true } = {}) {
17
- const source = normalizeObjectInput(workspace);
18
- const seed = {};
19
- for (const field of workspaceSettingsFields) {
20
- const rawValue = Object.hasOwn(source, field.key)
21
- ? source[field.key]
22
- : field.resolveDefault({
23
- workspace: source,
24
- defaultInvitesEnabled
25
- });
26
- seed[field.key] = field.normalizeOutput(rawValue, {
27
- workspace: source,
28
- defaultInvitesEnabled
29
- });
30
- }
31
- return seed;
32
- }
33
-
34
- function createRepository(knex, { defaultInvitesEnabled } = {}) {
35
- if (typeof knex !== "function") {
36
- throw new TypeError("workspaceSettingsRepository requires knex.");
37
- }
38
- const withTransaction = createWithTransaction(knex);
39
-
40
- function mapRow(row) {
41
- if (!row) {
42
- return null;
43
- }
44
-
45
- const settings = {
46
- workspaceId: normalizeDbRecordId(row.workspace_id, { fallback: "" })
47
- };
48
- for (const field of workspaceSettingsFields) {
49
- const rawValue = Object.hasOwn(row, field.dbColumn)
50
- ? row[field.dbColumn]
51
- : field.resolveDefault({
52
- defaultInvitesEnabled
53
- });
54
- settings[field.key] = field.normalizeOutput(rawValue, {
55
- defaultInvitesEnabled
56
- });
57
- }
58
-
59
- settings.createdAt = toIsoString(row.created_at);
60
- settings.updatedAt = toIsoString(row.updated_at);
61
- return settings;
62
- }
63
-
64
- async function findByWorkspaceId(workspaceId, options = {}) {
65
- const client = options?.trx || knex;
66
- const normalizedWorkspaceId = normalizeRecordId(workspaceId, { fallback: null });
67
- if (!normalizedWorkspaceId) {
68
- return null;
69
- }
70
-
71
- const row = await client("workspace_settings").where({ workspace_id: normalizedWorkspaceId }).first();
72
- return mapRow(row);
73
- }
74
-
75
- async function ensureForWorkspaceId(workspaceId, options = {}) {
76
- const client = options?.trx || knex;
77
- const normalizedWorkspaceId = normalizeRecordId(workspaceId, { fallback: null });
78
- if (!normalizedWorkspaceId) {
79
- throw new TypeError("workspaceSettingsRepository.ensureForWorkspaceId requires a valid workspace id.");
80
- }
81
-
82
- const seed = resolveWorkspaceSettingsSeed(options?.workspace, {
83
- defaultInvitesEnabled
84
- });
85
- const existing = await findByWorkspaceId(normalizedWorkspaceId, { trx: client });
86
- if (existing) {
87
- return existing;
88
- }
89
-
90
- try {
91
- const insertPayload = {
92
- workspace_id: normalizedWorkspaceId,
93
- created_at: nowDb(),
94
- updated_at: nowDb()
95
- };
96
- for (const field of workspaceSettingsFields) {
97
- insertPayload[field.dbColumn] = seed[field.key];
98
- }
99
- await client("workspace_settings").insert(insertPayload);
100
- } catch (error) {
101
- if (!isDuplicateEntryError(error)) {
102
- throw error;
103
- }
104
- }
105
-
106
- return findByWorkspaceId(normalizedWorkspaceId, { trx: client });
107
- }
108
-
109
- async function updateSettingsByWorkspaceId(workspaceId, patch = {}, options = {}) {
110
- const client = options?.trx || knex;
111
- const normalizedWorkspaceId = normalizeRecordId(workspaceId, { fallback: null });
112
- if (!normalizedWorkspaceId) {
113
- throw new TypeError("workspaceSettingsRepository.updateSettingsByWorkspaceId requires a valid workspace id.");
114
- }
115
-
116
- const ensured = await ensureForWorkspaceId(normalizedWorkspaceId, {
117
- trx: client,
118
- workspace: options?.workspace
119
- });
120
- const source = normalizeObjectInput(patch);
121
- const settingsPatch = pickOwnProperties(source, resolveWorkspaceSettingsFieldKeys());
122
-
123
- if (Object.keys(settingsPatch).length === 0) {
124
- return ensured;
125
- }
126
-
127
- const dbPatch = {
128
- updated_at: nowDb()
129
- };
130
-
131
- for (const field of workspaceSettingsFields) {
132
- if (!Object.hasOwn(settingsPatch, field.key)) {
133
- continue;
134
- }
135
- dbPatch[field.dbColumn] = field.normalizeInput(settingsPatch[field.key], {
136
- payload: source
137
- });
138
- }
139
-
140
- await client("workspace_settings").where({ workspace_id: normalizedWorkspaceId }).update({
141
- ...dbPatch
142
- });
143
- return findByWorkspaceId(normalizedWorkspaceId, { trx: client });
144
- }
145
-
146
- return Object.freeze({
147
- withTransaction,
148
- findByWorkspaceId,
149
- ensureForWorkspaceId,
150
- updateSettingsByWorkspaceId
151
- });
152
- }
153
-
154
- export { createRepository };
@@ -1,66 +0,0 @@
1
- import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
2
- import { normalizeObjectInput } from "@jskit-ai/kernel/shared/validators/inputNormalization";
3
- import { pickOwnProperties } from "@jskit-ai/kernel/shared/support";
4
- import {
5
- workspaceSettingsFields,
6
- resolveWorkspaceSettingsFieldKeys
7
- } from "../../shared/resources/workspaceSettingsFields.js";
8
- import { createWorkspaceRoleCatalog, cloneWorkspaceRoleCatalog } from "../../shared/roles.js";
9
-
10
- function createService({
11
- workspaceSettingsRepository,
12
- workspaceInvitationsEnabled = true,
13
- roleCatalog = null
14
- } = {}) {
15
- if (!workspaceSettingsRepository) {
16
- throw new Error("workspaceSettingsService requires workspaceSettingsRepository.");
17
- }
18
- const resolvedRoleCatalog = roleCatalog && typeof roleCatalog === "object" ? roleCatalog : createWorkspaceRoleCatalog();
19
- const invitesAvailable = workspaceInvitationsEnabled === true;
20
-
21
- async function getWorkspaceSettings(workspace, options = {}) {
22
- const settingsRecord = await workspaceSettingsRepository.ensureForWorkspaceId(workspace.id, {
23
- ...options,
24
- workspace
25
- });
26
- const settings = {};
27
- for (const field of workspaceSettingsFields) {
28
- settings[field.key] = settingsRecord[field.key];
29
- }
30
- const invitesEnabled = invitesAvailable && settings.invitesEnabled !== false;
31
- settings.invitesEnabled = invitesEnabled;
32
- settings.invitesAvailable = invitesAvailable;
33
- settings.invitesEffective = invitesAvailable && invitesEnabled;
34
-
35
- return {
36
- workspace: {
37
- id: normalizeRecordId(workspace.id, { fallback: "" }),
38
- slug: String(workspace.slug || ""),
39
- ownerUserId: normalizeRecordId(workspace.ownerUserId, { fallback: "" })
40
- },
41
- settings,
42
- roleCatalog: cloneWorkspaceRoleCatalog(resolvedRoleCatalog)
43
- };
44
- }
45
-
46
- async function updateWorkspaceSettings(workspace, payload = {}, options = {}) {
47
- const source = normalizeObjectInput(payload);
48
- const settingsPatch = pickOwnProperties(source, resolveWorkspaceSettingsFieldKeys());
49
-
50
- if (Object.keys(settingsPatch).length > 0) {
51
- await workspaceSettingsRepository.updateSettingsByWorkspaceId(workspace.id, settingsPatch, {
52
- ...options,
53
- workspace
54
- });
55
- }
56
-
57
- return getWorkspaceSettings(workspace, options);
58
- }
59
-
60
- return Object.freeze({
61
- getWorkspaceSettings,
62
- updateWorkspaceSettings
63
- });
64
- }
65
-
66
- export { createService };
@@ -1,354 +0,0 @@
1
- import { Type } from "@fastify/type-provider-typebox";
2
- import { normalizeLowerText, normalizeText } from "@jskit-ai/kernel/shared/actions/textNormalization";
3
- import {
4
- normalizeObjectInput,
5
- recordIdSchema,
6
- recordIdInputSchema,
7
- nullableRecordIdSchema
8
- } from "@jskit-ai/kernel/shared/validators";
9
- import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
10
- import { createOperationMessages } from "../operationMessages.js";
11
- import { createWorkspaceRoleCatalog, OWNER_ROLE_ID } from "../roles.js";
12
-
13
- const workspaceSummaryOutputSchema = Type.Object(
14
- {
15
- id: recordIdSchema,
16
- slug: Type.String({ minLength: 1 }),
17
- name: Type.String({ minLength: 1 }),
18
- ownerUserId: recordIdSchema,
19
- avatarUrl: Type.String()
20
- },
21
- { additionalProperties: false }
22
- );
23
-
24
- const memberSummaryOutputSchema = Type.Object(
25
- {
26
- userId: recordIdSchema,
27
- roleSid: Type.String({ minLength: 1 }),
28
- status: Type.String({ minLength: 1 }),
29
- displayName: Type.String(),
30
- email: Type.String({ minLength: 1 }),
31
- isOwner: Type.Boolean()
32
- },
33
- { additionalProperties: false }
34
- );
35
-
36
- const inviteSummaryOutputSchema = Type.Object(
37
- {
38
- id: recordIdSchema,
39
- email: Type.String({ minLength: 3, format: "email" }),
40
- roleSid: Type.String({ minLength: 1 }),
41
- status: Type.String({ minLength: 1 }),
42
- expiresAt: Type.String({ minLength: 1 }),
43
- invitedByUserId: nullableRecordIdSchema
44
- },
45
- { additionalProperties: false }
46
- );
47
-
48
- function normalizeWorkspaceAdminSummary(workspace) {
49
- const source = normalizeObjectInput(workspace);
50
-
51
- return {
52
- id: normalizeRecordId(source.id, { fallback: "" }),
53
- slug: normalizeText(source.slug),
54
- name: normalizeText(source.name),
55
- ownerUserId: normalizeRecordId(source.ownerUserId, { fallback: "" }),
56
- avatarUrl: normalizeText(source.avatarUrl)
57
- };
58
- }
59
-
60
- function normalizeMemberSummary(member, workspace) {
61
- const source = normalizeObjectInput(member);
62
- const userId = normalizeRecordId(source.userId, { fallback: "" });
63
-
64
- return {
65
- userId,
66
- roleSid: normalizeLowerText(source.roleSid || "member") || "member",
67
- status: normalizeLowerText(source.status || "active") || "active",
68
- displayName: normalizeText(source.displayName),
69
- email: normalizeLowerText(source.email),
70
- isOwner: userId === workspace.ownerUserId || normalizeLowerText(source.roleSid) === OWNER_ROLE_ID
71
- };
72
- }
73
-
74
- function normalizeInviteSummary(invite) {
75
- const source = normalizeObjectInput(invite);
76
-
77
- return {
78
- id: normalizeRecordId(source.id, { fallback: "" }),
79
- email: normalizeLowerText(source.email),
80
- roleSid: normalizeLowerText(source.roleSid || "member") || "member",
81
- status: normalizeLowerText(source.status || "pending") || "pending",
82
- expiresAt: source.expiresAt,
83
- invitedByUserId: source.invitedByUserId == null ? null : normalizeRecordId(source.invitedByUserId, { fallback: null })
84
- };
85
- }
86
-
87
- function normalizeWorkspaceOutputEnvelope(
88
- payload = {},
89
- { itemsKey, normalizeItem, includeInviteTokenPreview = false } = {}
90
- ) {
91
- const source = normalizeObjectInput(payload);
92
- const workspace = normalizeWorkspaceAdminSummary(source.workspace);
93
- const items = Array.isArray(source[itemsKey]) ? source[itemsKey] : [];
94
- const roleCatalog = normalizeObjectInput(source.roleCatalog);
95
- const hasRoleCatalog =
96
- Array.isArray(roleCatalog.roles) &&
97
- roleCatalog.roles.length > 0 &&
98
- Array.isArray(roleCatalog.assignableRoleIds);
99
- const normalized = {
100
- workspace,
101
- [itemsKey]: items.map((item) => normalizeItem(item, workspace)),
102
- roleCatalog: hasRoleCatalog ? roleCatalog : createWorkspaceRoleCatalog()
103
- };
104
-
105
- if (includeInviteTokenPreview && Object.hasOwn(source, "inviteTokenPreview")) {
106
- normalized.inviteTokenPreview = normalizeText(source.inviteTokenPreview);
107
- }
108
-
109
- return normalized;
110
- }
111
-
112
- function normalizeWorkspaceMembersOutput(payload = {}) {
113
- return normalizeWorkspaceOutputEnvelope(payload, {
114
- itemsKey: "members",
115
- normalizeItem: normalizeMemberSummary
116
- });
117
- }
118
-
119
- function normalizeWorkspaceInvitesOutput(payload = {}) {
120
- return normalizeWorkspaceOutputEnvelope(payload, {
121
- itemsKey: "invites",
122
- normalizeItem: normalizeInviteSummary,
123
- includeInviteTokenPreview: true
124
- });
125
- }
126
-
127
- const workspaceRoleCatalogOutputValidator = Object.freeze({
128
- schema: Type.Object(
129
- {
130
- collaborationEnabled: Type.Boolean(),
131
- defaultInviteRole: Type.String(),
132
- roles: Type.Array(Type.Object({}, { additionalProperties: true })),
133
- assignableRoleIds: Type.Array(Type.String({ minLength: 1 }))
134
- },
135
- { additionalProperties: true }
136
- )
137
- });
138
-
139
- const workspaceMembersOutputValidator = Object.freeze({
140
- schema: Type.Object(
141
- {
142
- workspace: workspaceSummaryOutputSchema,
143
- members: Type.Array(memberSummaryOutputSchema),
144
- roleCatalog: workspaceRoleCatalogOutputValidator.schema
145
- },
146
- { additionalProperties: false }
147
- ),
148
- normalize: normalizeWorkspaceMembersOutput
149
- });
150
-
151
- const workspaceInvitesOutputValidator = Object.freeze({
152
- schema: Type.Object(
153
- {
154
- workspace: workspaceSummaryOutputSchema,
155
- invites: Type.Array(inviteSummaryOutputSchema),
156
- roleCatalog: workspaceRoleCatalogOutputValidator.schema,
157
- inviteTokenPreview: Type.Optional(Type.String({ minLength: 1 }))
158
- },
159
- { additionalProperties: false }
160
- ),
161
- normalize: normalizeWorkspaceInvitesOutput
162
- });
163
-
164
- const updateMemberRoleBodyValidator = Object.freeze({
165
- schema: Type.Object(
166
- {
167
- roleSid: Type.String({ minLength: 1 })
168
- },
169
- { additionalProperties: false }
170
- ),
171
- normalize(payload = {}) {
172
- const source = normalizeObjectInput(payload);
173
-
174
- return {
175
- roleSid: normalizeLowerText(source.roleSid)
176
- };
177
- }
178
- });
179
-
180
- const updateMemberRoleInputValidator = Object.freeze({
181
- schema: Type.Object(
182
- {
183
- memberUserId: recordIdInputSchema,
184
- roleSid: Type.String({ minLength: 1 })
185
- },
186
- { additionalProperties: false }
187
- ),
188
- normalize(payload = {}) {
189
- const source = normalizeObjectInput(payload);
190
-
191
- return {
192
- memberUserId: normalizeRecordId(source.memberUserId, { fallback: "" }),
193
- roleSid: normalizeLowerText(source.roleSid)
194
- };
195
- }
196
- });
197
-
198
- const removeMemberInputValidator = Object.freeze({
199
- schema: Type.Object(
200
- {
201
- memberUserId: recordIdInputSchema
202
- },
203
- { additionalProperties: false }
204
- ),
205
- normalize(payload = {}) {
206
- const source = normalizeObjectInput(payload);
207
-
208
- return {
209
- memberUserId: normalizeRecordId(source.memberUserId, { fallback: "" })
210
- };
211
- }
212
- });
213
-
214
- const createInviteBodyValidator = Object.freeze({
215
- schema: Type.Object(
216
- {
217
- email: Type.String({ minLength: 3, format: "email" }),
218
- roleSid: Type.String({ minLength: 1 })
219
- },
220
- { additionalProperties: false }
221
- ),
222
- normalize(payload = {}) {
223
- const source = normalizeObjectInput(payload);
224
-
225
- return {
226
- email: normalizeLowerText(source.email),
227
- roleSid: normalizeLowerText(source.roleSid || "member") || "member"
228
- };
229
- }
230
- });
231
-
232
- const revokeInviteInputValidator = Object.freeze({
233
- schema: Type.Object(
234
- {
235
- inviteId: recordIdInputSchema
236
- },
237
- { additionalProperties: false }
238
- ),
239
- normalize(payload = {}) {
240
- const source = normalizeObjectInput(payload);
241
-
242
- return {
243
- inviteId: normalizeRecordId(source.inviteId, { fallback: "" })
244
- };
245
- }
246
- });
247
-
248
- const redeemInviteBodyValidator = Object.freeze({
249
- schema: Type.Object(
250
- {
251
- token: Type.String({
252
- minLength: 1,
253
- messages: {
254
- required: "Invite token is required.",
255
- minLength: "Invite token is required.",
256
- default: "Invite token is invalid."
257
- }
258
- }),
259
- decision: Type.Union([Type.Literal("accept"), Type.Literal("refuse")], {
260
- messages: {
261
- required: "Decision is required.",
262
- default: "Decision must be accept or refuse."
263
- }
264
- })
265
- },
266
- {
267
- additionalProperties: false,
268
- messages: {
269
- additionalProperties: "Unexpected field."
270
- }
271
- }
272
- ),
273
- normalize(payload = {}) {
274
- const source = normalizeObjectInput(payload);
275
-
276
- return {
277
- token: normalizeText(source.token),
278
- decision: normalizeLowerText(source.decision)
279
- };
280
- }
281
- });
282
-
283
- const redeemInviteOutputValidator = Object.freeze({
284
- schema: Type.Object(
285
- {
286
- decision: Type.Union([Type.Literal("accepted"), Type.Literal("refused")])
287
- },
288
- { additionalProperties: false }
289
- ),
290
- normalize(payload = {}) {
291
- const source = normalizeObjectInput(payload);
292
-
293
- return {
294
- decision: normalizeLowerText(source.decision)
295
- };
296
- }
297
- });
298
-
299
- const WORKSPACE_MEMBERS_MESSAGES = createOperationMessages();
300
-
301
- const workspaceMembersResource = Object.freeze({
302
- resource: "workspaceMembers",
303
- messages: WORKSPACE_MEMBERS_MESSAGES,
304
- operations: Object.freeze({
305
- rolesList: Object.freeze({
306
- method: "GET",
307
- messages: WORKSPACE_MEMBERS_MESSAGES,
308
- outputValidator: workspaceRoleCatalogOutputValidator
309
- }),
310
- membersList: Object.freeze({
311
- method: "GET",
312
- messages: WORKSPACE_MEMBERS_MESSAGES,
313
- outputValidator: workspaceMembersOutputValidator
314
- }),
315
- updateMemberRole: Object.freeze({
316
- method: "PATCH",
317
- messages: WORKSPACE_MEMBERS_MESSAGES,
318
- bodyValidator: updateMemberRoleBodyValidator,
319
- inputValidator: updateMemberRoleInputValidator,
320
- outputValidator: workspaceMembersOutputValidator
321
- }),
322
- removeMember: Object.freeze({
323
- method: "DELETE",
324
- messages: WORKSPACE_MEMBERS_MESSAGES,
325
- inputValidator: removeMemberInputValidator,
326
- outputValidator: workspaceMembersOutputValidator
327
- }),
328
- invitesList: Object.freeze({
329
- method: "GET",
330
- messages: WORKSPACE_MEMBERS_MESSAGES,
331
- outputValidator: workspaceInvitesOutputValidator
332
- }),
333
- createInvite: Object.freeze({
334
- method: "POST",
335
- messages: WORKSPACE_MEMBERS_MESSAGES,
336
- bodyValidator: createInviteBodyValidator,
337
- outputValidator: workspaceInvitesOutputValidator
338
- }),
339
- revokeInvite: Object.freeze({
340
- method: "DELETE",
341
- messages: WORKSPACE_MEMBERS_MESSAGES,
342
- inputValidator: revokeInviteInputValidator,
343
- outputValidator: workspaceInvitesOutputValidator
344
- }),
345
- redeemInvite: Object.freeze({
346
- method: "POST",
347
- messages: WORKSPACE_MEMBERS_MESSAGES,
348
- bodyValidator: redeemInviteBodyValidator,
349
- outputValidator: redeemInviteOutputValidator
350
- })
351
- })
352
- });
353
-
354
- export { workspaceMembersResource };