@jskit-ai/workspaces-core 0.1.21 → 0.1.23

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 (30) hide show
  1. package/package.descriptor.mjs +2 -2
  2. package/package.json +6 -6
  3. package/src/server/common/repositories/workspaceInvitesRepository.js +68 -65
  4. package/src/server/common/repositories/workspaceMembershipsRepository.js +83 -52
  5. package/src/server/common/repositories/workspacesRepository.js +42 -67
  6. package/src/server/common/resources/workspaceInvitesResource.js +207 -0
  7. package/src/server/common/resources/workspaceMembershipsResource.js +154 -0
  8. package/src/server/common/resources/workspacesResource.js +170 -0
  9. package/src/server/registerWorkspaceBootstrap.js +1 -1
  10. package/src/server/registerWorkspaceCore.js +3 -3
  11. package/src/server/registerWorkspaceRepositories.js +3 -3
  12. package/src/server/workspaceBootstrapContributor.js +4 -4
  13. package/src/server/workspaceMembers/registerWorkspaceMembers.js +2 -2
  14. package/src/server/workspacePendingInvitations/registerWorkspacePendingInvitations.js +2 -2
  15. package/src/server/workspaceSettings/registerWorkspaceSettings.js +2 -2
  16. package/src/server/workspaceSettings/workspaceSettingsRepository.js +5 -4
  17. package/src/shared/resources/workspaceMembersResource.js +1 -1
  18. package/src/shared/resources/workspacePendingInvitationsResource.js +1 -1
  19. package/src/shared/resources/workspaceResource.js +1 -1
  20. package/src/shared/resources/workspaceSettingsFields.js +10 -4
  21. package/src/shared/resources/workspaceSettingsResource.js +1 -1
  22. package/templates/packages/main/src/shared/resources/workspaceSettingsFields.js +9 -9
  23. package/test/exportsContract.test.js +3 -1
  24. package/test/registerWorkspaceBootstrap.test.js +1 -1
  25. package/test/registerWorkspaceSettings.test.js +1 -1
  26. package/test/usersRouteResources.test.js +1 -1
  27. package/test/workspaceBootstrapContributor.test.js +3 -3
  28. package/test/workspaceInvitesRepository.test.js +129 -18
  29. package/test/workspaceMembershipsRepository.test.js +212 -0
  30. package/test/workspacesRepository.test.js +253 -0
@@ -0,0 +1,207 @@
1
+ import { Type } from "typebox";
2
+ import {
3
+ createCursorListValidator,
4
+ normalizeObjectInput,
5
+ recordIdInputSchema,
6
+ recordIdSchema
7
+ } from "@jskit-ai/kernel/shared/validators";
8
+ import {
9
+ normalizeIfPresent,
10
+ normalizeLowerText,
11
+ normalizeRecordId,
12
+ normalizeText,
13
+ normalizeOrNull
14
+ } from "@jskit-ai/kernel/shared/support/normalize";
15
+ import { normalizeDbRecordId, toIsoString, toNullableDateTime } from "@jskit-ai/database-runtime/shared";
16
+
17
+ function normalizeInviteRecord(payload = {}) {
18
+ const source = normalizeObjectInput(payload);
19
+
20
+ return {
21
+ id: normalizeIfPresent(source.id, (value) => normalizeDbRecordId(value, { fallback: null })),
22
+ workspaceId: normalizeIfPresent(
23
+ source.workspaceId ?? source.workspace_id,
24
+ (value) => normalizeDbRecordId(value, { fallback: null })
25
+ ),
26
+ email: normalizeLowerText(source.email),
27
+ roleSid: normalizeLowerText(source.roleSid ?? source.role_sid ?? "member") || "member",
28
+ status: normalizeLowerText(source.status ?? "pending") || "pending",
29
+ tokenHash: normalizeText(source.tokenHash ?? source.token_hash),
30
+ invitedByUserId: normalizeOrNull(
31
+ source.invitedByUserId ?? source.invited_by_user_id,
32
+ (value) => normalizeDbRecordId(value, { fallback: null })
33
+ ),
34
+ expiresAt: normalizeOrNull(source.expiresAt ?? source.expires_at, toIsoString),
35
+ acceptedAt: normalizeOrNull(source.acceptedAt ?? source.accepted_at, toIsoString),
36
+ revokedAt: normalizeOrNull(source.revokedAt ?? source.revoked_at, toIsoString),
37
+ createdAt: normalizeIfPresent(source.createdAt ?? source.created_at, toIsoString),
38
+ updatedAt: normalizeIfPresent(source.updatedAt ?? source.updated_at, toIsoString)
39
+ };
40
+ }
41
+
42
+ function normalizeInviteInput(payload = {}) {
43
+ const source = normalizeObjectInput(payload);
44
+ const normalized = {};
45
+
46
+ if (Object.hasOwn(source, "workspaceId")) {
47
+ normalized.workspaceId = normalizeRecordId(source.workspaceId, { fallback: "" });
48
+ }
49
+ if (Object.hasOwn(source, "email")) {
50
+ normalized.email = normalizeLowerText(source.email);
51
+ }
52
+ if (Object.hasOwn(source, "roleSid")) {
53
+ normalized.roleSid = normalizeLowerText(source.roleSid);
54
+ }
55
+ if (Object.hasOwn(source, "status")) {
56
+ normalized.status = normalizeLowerText(source.status);
57
+ }
58
+ if (Object.hasOwn(source, "tokenHash")) {
59
+ normalized.tokenHash = normalizeText(source.tokenHash);
60
+ }
61
+ if (Object.hasOwn(source, "invitedByUserId")) {
62
+ normalized.invitedByUserId =
63
+ source.invitedByUserId == null
64
+ ? null
65
+ : normalizeRecordId(source.invitedByUserId, { fallback: null });
66
+ }
67
+ if (Object.hasOwn(source, "expiresAt")) {
68
+ normalized.expiresAt = toNullableDateTime(source.expiresAt);
69
+ }
70
+ if (Object.hasOwn(source, "acceptedAt")) {
71
+ normalized.acceptedAt = toNullableDateTime(source.acceptedAt);
72
+ }
73
+ if (Object.hasOwn(source, "revokedAt")) {
74
+ normalized.revokedAt = toNullableDateTime(source.revokedAt);
75
+ }
76
+
77
+ return normalized;
78
+ }
79
+
80
+ const recordOutputSchema = Type.Object(
81
+ {
82
+ id: recordIdSchema,
83
+ workspaceId: recordIdSchema,
84
+ email: Type.String({ minLength: 1 }),
85
+ roleSid: Type.String({ minLength: 1 }),
86
+ status: Type.String({ minLength: 1 }),
87
+ tokenHash: Type.String({ minLength: 1 }),
88
+ invitedByUserId: Type.Union([recordIdSchema, Type.Null()]),
89
+ expiresAt: Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]),
90
+ acceptedAt: Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]),
91
+ revokedAt: Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]),
92
+ createdAt: Type.String({ format: "date-time", minLength: 1 }),
93
+ updatedAt: Type.String({ format: "date-time", minLength: 1 })
94
+ },
95
+ { additionalProperties: false }
96
+ );
97
+
98
+ const createBodySchema = Type.Object(
99
+ {
100
+ workspaceId: recordIdInputSchema,
101
+ email: Type.String({ minLength: 1, maxLength: 255 }),
102
+ tokenHash: Type.String({ minLength: 1, maxLength: 255 }),
103
+ roleSid: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
104
+ status: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
105
+ invitedByUserId: Type.Optional(Type.Union([recordIdInputSchema, Type.Null()])),
106
+ expiresAt: Type.Optional(Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]))
107
+ },
108
+ {
109
+ additionalProperties: false,
110
+ required: []
111
+ }
112
+ );
113
+
114
+ const patchBodySchema = Type.Object(
115
+ {
116
+ roleSid: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
117
+ status: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
118
+ invitedByUserId: Type.Optional(Type.Union([recordIdInputSchema, Type.Null()])),
119
+ expiresAt: Type.Optional(Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()])),
120
+ acceptedAt: Type.Optional(Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()])),
121
+ revokedAt: Type.Optional(Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]))
122
+ },
123
+ {
124
+ additionalProperties: false
125
+ }
126
+ );
127
+
128
+ const recordOutputValidator = Object.freeze({
129
+ schema: recordOutputSchema,
130
+ normalize: normalizeInviteRecord
131
+ });
132
+
133
+ const createBodyValidator = Object.freeze({
134
+ schema: createBodySchema,
135
+ normalize: normalizeInviteInput
136
+ });
137
+
138
+ const patchBodyValidator = Object.freeze({
139
+ schema: patchBodySchema,
140
+ normalize: normalizeInviteInput
141
+ });
142
+
143
+ const workspaceInvitesResource = Object.freeze({
144
+ namespace: "workspaceInvites",
145
+ tableName: "workspace_invites",
146
+ idColumn: "id",
147
+ operations: Object.freeze({
148
+ list: Object.freeze({
149
+ method: "GET",
150
+ outputValidator: createCursorListValidator(recordOutputValidator)
151
+ }),
152
+ view: Object.freeze({
153
+ method: "GET",
154
+ outputValidator: recordOutputValidator
155
+ }),
156
+ create: Object.freeze({
157
+ method: "POST",
158
+ bodyValidator: createBodyValidator,
159
+ outputValidator: recordOutputValidator
160
+ }),
161
+ patch: Object.freeze({
162
+ method: "PATCH",
163
+ bodyValidator: patchBodyValidator,
164
+ outputValidator: recordOutputValidator
165
+ })
166
+ }),
167
+ fieldMeta: Object.freeze([
168
+ Object.freeze({
169
+ key: "workspaceId",
170
+ repository: { column: "workspace_id" }
171
+ }),
172
+ Object.freeze({
173
+ key: "roleSid",
174
+ repository: { column: "role_sid" }
175
+ }),
176
+ Object.freeze({
177
+ key: "tokenHash",
178
+ repository: { column: "token_hash" }
179
+ }),
180
+ Object.freeze({
181
+ key: "invitedByUserId",
182
+ repository: { column: "invited_by_user_id" }
183
+ }),
184
+ Object.freeze({
185
+ key: "expiresAt",
186
+ repository: { column: "expires_at" }
187
+ }),
188
+ Object.freeze({
189
+ key: "acceptedAt",
190
+ repository: { column: "accepted_at" }
191
+ }),
192
+ Object.freeze({
193
+ key: "revokedAt",
194
+ repository: { column: "revoked_at" }
195
+ }),
196
+ Object.freeze({
197
+ key: "createdAt",
198
+ repository: { column: "created_at" }
199
+ }),
200
+ Object.freeze({
201
+ key: "updatedAt",
202
+ repository: { column: "updated_at" }
203
+ })
204
+ ])
205
+ });
206
+
207
+ export { workspaceInvitesResource };
@@ -0,0 +1,154 @@
1
+ import { Type } from "typebox";
2
+ import {
3
+ createCursorListValidator,
4
+ normalizeObjectInput,
5
+ recordIdInputSchema,
6
+ recordIdSchema
7
+ } from "@jskit-ai/kernel/shared/validators";
8
+ import {
9
+ normalizeIfPresent,
10
+ normalizeLowerText,
11
+ normalizeRecordId
12
+ } from "@jskit-ai/kernel/shared/support/normalize";
13
+ import { normalizeDbRecordId, toIsoString } from "@jskit-ai/database-runtime/shared";
14
+
15
+ function normalizeMembershipRecord(payload = {}) {
16
+ const source = normalizeObjectInput(payload);
17
+
18
+ return {
19
+ id: normalizeIfPresent(source.id, (value) => normalizeDbRecordId(value, { fallback: null })),
20
+ workspaceId: normalizeIfPresent(
21
+ source.workspaceId ?? source.workspace_id,
22
+ (value) => normalizeDbRecordId(value, { fallback: null })
23
+ ),
24
+ userId: normalizeIfPresent(
25
+ source.userId ?? source.user_id,
26
+ (value) => normalizeDbRecordId(value, { fallback: null })
27
+ ),
28
+ roleSid: normalizeLowerText(source.roleSid ?? source.role_sid ?? "member") || "member",
29
+ status: normalizeLowerText(source.status ?? "active") || "active",
30
+ createdAt: normalizeIfPresent(source.createdAt ?? source.created_at, toIsoString),
31
+ updatedAt: normalizeIfPresent(source.updatedAt ?? source.updated_at, toIsoString)
32
+ };
33
+ }
34
+
35
+ function normalizeMembershipInput(payload = {}) {
36
+ const source = normalizeObjectInput(payload);
37
+ const normalized = {};
38
+
39
+ if (Object.hasOwn(source, "workspaceId")) {
40
+ normalized.workspaceId = normalizeRecordId(source.workspaceId, { fallback: "" });
41
+ }
42
+ if (Object.hasOwn(source, "userId")) {
43
+ normalized.userId = normalizeRecordId(source.userId, { fallback: "" });
44
+ }
45
+ if (Object.hasOwn(source, "roleSid")) {
46
+ normalized.roleSid = normalizeLowerText(source.roleSid);
47
+ }
48
+ if (Object.hasOwn(source, "status")) {
49
+ normalized.status = normalizeLowerText(source.status);
50
+ }
51
+
52
+ return normalized;
53
+ }
54
+
55
+ const recordOutputSchema = Type.Object(
56
+ {
57
+ id: recordIdSchema,
58
+ workspaceId: recordIdSchema,
59
+ userId: recordIdSchema,
60
+ roleSid: Type.String({ minLength: 1 }),
61
+ status: Type.String({ minLength: 1 }),
62
+ createdAt: Type.String({ format: "date-time", minLength: 1 }),
63
+ updatedAt: Type.String({ format: "date-time", minLength: 1 })
64
+ },
65
+ { additionalProperties: false }
66
+ );
67
+
68
+ const createBodySchema = Type.Object(
69
+ {
70
+ workspaceId: recordIdInputSchema,
71
+ userId: recordIdInputSchema,
72
+ roleSid: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
73
+ status: Type.Optional(Type.String({ minLength: 1, maxLength: 32 }))
74
+ },
75
+ {
76
+ additionalProperties: false,
77
+ required: []
78
+ }
79
+ );
80
+
81
+ const patchBodySchema = Type.Object(
82
+ {
83
+ roleSid: Type.Optional(Type.String({ minLength: 1, maxLength: 64 })),
84
+ status: Type.Optional(Type.String({ minLength: 1, maxLength: 32 }))
85
+ },
86
+ {
87
+ additionalProperties: false
88
+ }
89
+ );
90
+
91
+ const recordOutputValidator = Object.freeze({
92
+ schema: recordOutputSchema,
93
+ normalize: normalizeMembershipRecord
94
+ });
95
+
96
+ const createBodyValidator = Object.freeze({
97
+ schema: createBodySchema,
98
+ normalize: normalizeMembershipInput
99
+ });
100
+
101
+ const patchBodyValidator = Object.freeze({
102
+ schema: patchBodySchema,
103
+ normalize: normalizeMembershipInput
104
+ });
105
+
106
+ const workspaceMembershipsResource = Object.freeze({
107
+ namespace: "workspaceMemberships",
108
+ tableName: "workspace_memberships",
109
+ idColumn: "id",
110
+ operations: Object.freeze({
111
+ list: Object.freeze({
112
+ method: "GET",
113
+ outputValidator: createCursorListValidator(recordOutputValidator)
114
+ }),
115
+ view: Object.freeze({
116
+ method: "GET",
117
+ outputValidator: recordOutputValidator
118
+ }),
119
+ create: Object.freeze({
120
+ method: "POST",
121
+ bodyValidator: createBodyValidator,
122
+ outputValidator: recordOutputValidator
123
+ }),
124
+ patch: Object.freeze({
125
+ method: "PATCH",
126
+ bodyValidator: patchBodyValidator,
127
+ outputValidator: recordOutputValidator
128
+ })
129
+ }),
130
+ fieldMeta: Object.freeze([
131
+ Object.freeze({
132
+ key: "workspaceId",
133
+ repository: { column: "workspace_id" }
134
+ }),
135
+ Object.freeze({
136
+ key: "userId",
137
+ repository: { column: "user_id" }
138
+ }),
139
+ Object.freeze({
140
+ key: "roleSid",
141
+ repository: { column: "role_sid" }
142
+ }),
143
+ Object.freeze({
144
+ key: "createdAt",
145
+ repository: { column: "created_at" }
146
+ }),
147
+ Object.freeze({
148
+ key: "updatedAt",
149
+ repository: { column: "updated_at" }
150
+ })
151
+ ])
152
+ });
153
+
154
+ export { workspaceMembershipsResource };
@@ -0,0 +1,170 @@
1
+ import { Type } from "typebox";
2
+ import {
3
+ createCursorListValidator,
4
+ normalizeObjectInput,
5
+ recordIdInputSchema,
6
+ recordIdSchema
7
+ } from "@jskit-ai/kernel/shared/validators";
8
+ import {
9
+ normalizeBoolean,
10
+ normalizeIfPresent,
11
+ normalizeLowerText,
12
+ normalizeRecordId,
13
+ normalizeText,
14
+ normalizeOrNull
15
+ } from "@jskit-ai/kernel/shared/support/normalize";
16
+ import { normalizeDbRecordId, toIsoString, toNullableDateTime } from "@jskit-ai/database-runtime/shared";
17
+
18
+ function normalizeWorkspaceRecord(payload = {}) {
19
+ const source = normalizeObjectInput(payload);
20
+
21
+ return {
22
+ id: normalizeIfPresent(source.id, (value) => normalizeDbRecordId(value, { fallback: null })),
23
+ slug: normalizeLowerText(source.slug),
24
+ name: normalizeText(source.name),
25
+ ownerUserId: normalizeIfPresent(
26
+ source.ownerUserId ?? source.owner_user_id,
27
+ (value) => normalizeDbRecordId(value, { fallback: null })
28
+ ),
29
+ isPersonal: normalizeBoolean(source.isPersonal ?? source.is_personal),
30
+ avatarUrl: normalizeText(source.avatarUrl ?? source.avatar_url),
31
+ createdAt: normalizeIfPresent(source.createdAt ?? source.created_at, toIsoString),
32
+ updatedAt: normalizeIfPresent(source.updatedAt ?? source.updated_at, toIsoString),
33
+ deletedAt: normalizeOrNull(source.deletedAt ?? source.deleted_at, toIsoString)
34
+ };
35
+ }
36
+
37
+ function normalizeWorkspaceInput(payload = {}) {
38
+ const source = normalizeObjectInput(payload);
39
+ const normalized = {};
40
+
41
+ if (Object.hasOwn(source, "slug")) {
42
+ normalized.slug = normalizeLowerText(source.slug);
43
+ }
44
+ if (Object.hasOwn(source, "name")) {
45
+ normalized.name = normalizeText(source.name);
46
+ }
47
+ if (Object.hasOwn(source, "ownerUserId")) {
48
+ normalized.ownerUserId = normalizeRecordId(source.ownerUserId, { fallback: "" });
49
+ }
50
+ if (Object.hasOwn(source, "isPersonal")) {
51
+ normalized.isPersonal = normalizeBoolean(source.isPersonal);
52
+ }
53
+ if (Object.hasOwn(source, "avatarUrl")) {
54
+ normalized.avatarUrl = normalizeText(source.avatarUrl);
55
+ }
56
+ if (Object.hasOwn(source, "deletedAt")) {
57
+ normalized.deletedAt = toNullableDateTime(source.deletedAt);
58
+ }
59
+
60
+ return normalized;
61
+ }
62
+
63
+ const recordOutputSchema = Type.Object(
64
+ {
65
+ id: recordIdSchema,
66
+ slug: Type.String({ minLength: 1 }),
67
+ name: Type.String({ minLength: 1, maxLength: 160 }),
68
+ ownerUserId: recordIdSchema,
69
+ isPersonal: Type.Boolean(),
70
+ avatarUrl: Type.String(),
71
+ createdAt: Type.String({ format: "date-time", minLength: 1 }),
72
+ updatedAt: Type.String({ format: "date-time", minLength: 1 }),
73
+ deletedAt: Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()])
74
+ },
75
+ { additionalProperties: false }
76
+ );
77
+
78
+ const createBodySchema = Type.Object(
79
+ {
80
+ slug: Type.String({ minLength: 1, maxLength: 120 }),
81
+ name: Type.String({ minLength: 1, maxLength: 160 }),
82
+ ownerUserId: recordIdInputSchema,
83
+ isPersonal: Type.Optional(Type.Boolean()),
84
+ avatarUrl: Type.Optional(Type.String({ maxLength: 512 }))
85
+ },
86
+ {
87
+ additionalProperties: false,
88
+ required: []
89
+ }
90
+ );
91
+
92
+ const patchBodySchema = Type.Object(
93
+ {
94
+ name: Type.Optional(Type.String({ minLength: 1, maxLength: 160 })),
95
+ avatarUrl: Type.Optional(Type.String({ maxLength: 512 })),
96
+ deletedAt: Type.Optional(Type.Union([Type.String({ format: "date-time", minLength: 1 }), Type.Null()]))
97
+ },
98
+ {
99
+ additionalProperties: false
100
+ }
101
+ );
102
+
103
+ const recordOutputValidator = Object.freeze({
104
+ schema: recordOutputSchema,
105
+ normalize: normalizeWorkspaceRecord
106
+ });
107
+
108
+ const createBodyValidator = Object.freeze({
109
+ schema: createBodySchema,
110
+ normalize: normalizeWorkspaceInput
111
+ });
112
+
113
+ const patchBodyValidator = Object.freeze({
114
+ schema: patchBodySchema,
115
+ normalize: normalizeWorkspaceInput
116
+ });
117
+
118
+ const workspacesResource = Object.freeze({
119
+ namespace: "workspaces",
120
+ tableName: "workspaces",
121
+ idColumn: "id",
122
+ operations: Object.freeze({
123
+ list: Object.freeze({
124
+ method: "GET",
125
+ outputValidator: createCursorListValidator(recordOutputValidator)
126
+ }),
127
+ view: Object.freeze({
128
+ method: "GET",
129
+ outputValidator: recordOutputValidator
130
+ }),
131
+ create: Object.freeze({
132
+ method: "POST",
133
+ bodyValidator: createBodyValidator,
134
+ outputValidator: recordOutputValidator
135
+ }),
136
+ patch: Object.freeze({
137
+ method: "PATCH",
138
+ bodyValidator: patchBodyValidator,
139
+ outputValidator: recordOutputValidator
140
+ })
141
+ }),
142
+ fieldMeta: Object.freeze([
143
+ Object.freeze({
144
+ key: "ownerUserId",
145
+ repository: { column: "owner_user_id" }
146
+ }),
147
+ Object.freeze({
148
+ key: "isPersonal",
149
+ repository: { column: "is_personal" }
150
+ }),
151
+ Object.freeze({
152
+ key: "avatarUrl",
153
+ repository: { column: "avatar_url" }
154
+ }),
155
+ Object.freeze({
156
+ key: "createdAt",
157
+ repository: { column: "created_at" }
158
+ }),
159
+ Object.freeze({
160
+ key: "updatedAt",
161
+ repository: { column: "updated_at" }
162
+ }),
163
+ Object.freeze({
164
+ key: "deletedAt",
165
+ repository: { column: "deleted_at" }
166
+ })
167
+ ])
168
+ });
169
+
170
+ export { workspacesResource };
@@ -17,7 +17,7 @@ function registerWorkspaceBootstrap(app) {
17
17
  ? scope.make("workspaces.pending-invitations.service")
18
18
  : null,
19
19
  workspaceInvitationsEnabled,
20
- usersRepository: scope.make("usersRepository"),
20
+ userProfilesRepository: scope.make("internal.repository.user-profiles"),
21
21
  appConfig: resolveAppConfig(scope),
22
22
  tenancyProfile: scope.make("workspaces.tenancy.profile")
23
23
  });
@@ -33,9 +33,9 @@ function registerWorkspaceCore(app) {
33
33
  const appConfig = resolveAppConfig(scope);
34
34
  return createWorkspaceService({
35
35
  appConfig,
36
- workspacesRepository: scope.make("workspacesRepository"),
37
- workspaceMembershipsRepository: scope.make("workspaceMembershipsRepository"),
38
- workspaceSettingsRepository: scope.make("workspaceSettingsRepository")
36
+ workspacesRepository: scope.make("internal.repository.workspaces"),
37
+ workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships"),
38
+ workspaceSettingsRepository: scope.make("internal.repository.workspace-settings")
39
39
  });
40
40
  });
41
41
  app.singleton("workspaces.enabled", (scope) => {
@@ -7,17 +7,17 @@ function registerWorkspaceRepositories(app) {
7
7
  throw new Error("registerWorkspaceRepositories requires application singleton().");
8
8
  }
9
9
 
10
- app.singleton("workspacesRepository", (scope) => {
10
+ app.singleton("internal.repository.workspaces", (scope) => {
11
11
  const knex = scope.make("jskit.database.knex");
12
12
  return createWorkspacesRepository(knex);
13
13
  });
14
14
 
15
- app.singleton("workspaceMembershipsRepository", (scope) => {
15
+ app.singleton("internal.repository.workspace-memberships", (scope) => {
16
16
  const knex = scope.make("jskit.database.knex");
17
17
  return createWorkspaceMembershipsRepository(knex);
18
18
  });
19
19
 
20
- app.singleton("workspaceInvitesRepository", (scope) => {
20
+ app.singleton("internal.repository.workspace-invites", (scope) => {
21
21
  const knex = scope.make("jskit.database.knex");
22
22
  return createWorkspaceInvitesRepository(knex);
23
23
  });
@@ -104,7 +104,7 @@ function resolveBootstrapTenancyProfile(tenancyProfile = null, appConfig = {}) {
104
104
  function createWorkspaceBootstrapContributor({
105
105
  workspaceService,
106
106
  workspacePendingInvitationsService,
107
- usersRepository,
107
+ userProfilesRepository,
108
108
  workspaceInvitationsEnabled = false,
109
109
  appConfig = {},
110
110
  tenancyProfile = null
@@ -123,8 +123,8 @@ function createWorkspaceBootstrapContributor({
123
123
  serviceLabel: "workspacePendingInvitationsService"
124
124
  });
125
125
  }
126
- requireServiceMethod(usersRepository, "findById", contributorId, {
127
- serviceLabel: "usersRepository"
126
+ requireServiceMethod(userProfilesRepository, "findById", contributorId, {
127
+ serviceLabel: "internal.repository.user-profiles"
128
128
  });
129
129
 
130
130
  return Object.freeze({
@@ -161,7 +161,7 @@ function createWorkspaceBootstrapContributor({
161
161
  };
162
162
  }
163
163
 
164
- const latestProfile = await usersRepository.findById(normalizedUserId);
164
+ const latestProfile = await userProfilesRepository.findById(normalizedUserId);
165
165
  if (!latestProfile) {
166
166
  return {};
167
167
  }
@@ -58,8 +58,8 @@ function registerWorkspaceMembers(app) {
58
58
  (scope) => {
59
59
  const appConfig = resolveAppConfig(scope);
60
60
  return createWorkspaceMembersService({
61
- workspaceMembershipsRepository: scope.make("workspaceMembershipsRepository"),
62
- workspaceInvitesRepository: scope.make("workspaceInvitesRepository"),
61
+ workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships"),
62
+ workspaceInvitesRepository: scope.make("internal.repository.workspace-invites"),
63
63
  inviteExpiresInMs: resolveWorkspaceMembersInviteExpiresInMs(appConfig),
64
64
  roleCatalog: createWorkspaceRoleCatalog(appConfig),
65
65
  workspaceInvitationsEnabled: scope.make("workspaces.invitations.enabled") === true
@@ -93,8 +93,8 @@ function registerWorkspacePendingInvitations(app) {
93
93
  "workspaces.pending-invitations.service",
94
94
  (scope) =>
95
95
  createService({
96
- workspaceInvitesRepository: scope.make("workspaceInvitesRepository"),
97
- workspaceMembershipsRepository: scope.make("workspaceMembershipsRepository")
96
+ workspaceInvitesRepository: scope.make("internal.repository.workspace-invites"),
97
+ workspaceMembershipsRepository: scope.make("internal.repository.workspace-memberships")
98
98
  }),
99
99
  {
100
100
  events: deepFreeze({
@@ -22,7 +22,7 @@ function registerWorkspaceSettings(app) {
22
22
  throw new Error("registerWorkspaceSettings requires application singleton()/service()/actions().");
23
23
  }
24
24
 
25
- app.singleton("workspaceSettingsRepository", (scope) => {
25
+ app.singleton("internal.repository.workspace-settings", (scope) => {
26
26
  const knex = scope.make("jskit.database.knex");
27
27
  const appConfig = resolveAppConfig(scope);
28
28
  return createWorkspaceSettingsRepository(knex, {
@@ -34,7 +34,7 @@ function registerWorkspaceSettings(app) {
34
34
  "workspaces.settings.service",
35
35
  (scope) =>
36
36
  createWorkspaceSettingsService({
37
- workspaceSettingsRepository: scope.make("workspaceSettingsRepository"),
37
+ workspaceSettingsRepository: scope.make("internal.repository.workspace-settings"),
38
38
  workspaceInvitationsEnabled: scope.make("workspaces.invitations.enabled"),
39
39
  roleCatalog: createWorkspaceRoleCatalog(resolveAppConfig(scope))
40
40
  }),
@@ -46,8 +46,9 @@ function createRepository(knex, { defaultInvitesEnabled } = {}) {
46
46
  workspaceId: normalizeDbRecordId(row.workspace_id, { fallback: "" })
47
47
  };
48
48
  for (const field of workspaceSettingsFields) {
49
- const rawValue = Object.hasOwn(row, field.dbColumn)
50
- ? row[field.dbColumn]
49
+ const column = field.repository.column;
50
+ const rawValue = Object.hasOwn(row, column)
51
+ ? row[column]
51
52
  : field.resolveDefault({
52
53
  defaultInvitesEnabled
53
54
  });
@@ -94,7 +95,7 @@ function createRepository(knex, { defaultInvitesEnabled } = {}) {
94
95
  updated_at: nowDb()
95
96
  };
96
97
  for (const field of workspaceSettingsFields) {
97
- insertPayload[field.dbColumn] = seed[field.key];
98
+ insertPayload[field.repository.column] = seed[field.key];
98
99
  }
99
100
  await client("workspace_settings").insert(insertPayload);
100
101
  } catch (error) {
@@ -132,7 +133,7 @@ function createRepository(knex, { defaultInvitesEnabled } = {}) {
132
133
  if (!Object.hasOwn(settingsPatch, field.key)) {
133
134
  continue;
134
135
  }
135
- dbPatch[field.dbColumn] = field.normalizeInput(settingsPatch[field.key], {
136
+ dbPatch[field.repository.column] = field.normalizeInput(settingsPatch[field.key], {
136
137
  payload: source
137
138
  });
138
139
  }
@@ -299,7 +299,7 @@ const redeemInviteOutputValidator = Object.freeze({
299
299
  const WORKSPACE_MEMBERS_MESSAGES = createOperationMessages();
300
300
 
301
301
  const workspaceMembersResource = Object.freeze({
302
- resource: "workspaceMembers",
302
+ namespace: "workspaceMembers",
303
303
  messages: WORKSPACE_MEMBERS_MESSAGES,
304
304
  operations: Object.freeze({
305
305
  rolesList: Object.freeze({