@jskit-ai/workspaces-core 0.1.163 → 0.1.164

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/workspaces-core",
3
- "version": "0.1.163",
3
+ "version": "0.1.164",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -18,11 +18,11 @@
18
18
  "./shared/resources/workspaceSettingsResource": "./src/shared/resources/workspaceSettingsResource.js"
19
19
  },
20
20
  "dependencies": {
21
- "@jskit-ai/database-runtime": "0.1.185",
22
- "@jskit-ai/json-rest-api-core": "0.1.129",
23
- "@jskit-ai/resource-core": "0.1.127",
24
- "@jskit-ai/resource-crud-core": "0.1.127",
25
- "@jskit-ai/users-core": "0.1.198",
21
+ "@jskit-ai/database-runtime": "0.1.186",
22
+ "@jskit-ai/json-rest-api-core": "0.1.130",
23
+ "@jskit-ai/resource-core": "0.1.128",
24
+ "@jskit-ai/resource-crud-core": "0.1.128",
25
+ "@jskit-ai/users-core": "0.1.199",
26
26
  "json-rest-schema": "^1.0.17"
27
27
  },
28
28
  "description": "Workspace tenancy runtime plus HTTP routes, role catalog, and workspace config scaffolding.",
@@ -169,8 +169,8 @@
169
169
  }
170
170
  },
171
171
  "peerDependencies": {
172
- "@jskit-ai/auth-core": "0.1.183",
173
- "@jskit-ai/http-runtime": "0.1.183",
174
- "@jskit-ai/kernel": "0.1.185"
172
+ "@jskit-ai/auth-core": "0.1.184",
173
+ "@jskit-ai/http-runtime": "0.1.184",
174
+ "@jskit-ai/kernel": "0.1.186"
175
175
  }
176
176
  }
@@ -82,28 +82,21 @@ async function installWorkspaceResources(jsonRestApi) {
82
82
  );
83
83
  }
84
84
 
85
- function createWorkspacesRuntime({ config, database, env, jsonRestApi } = {}) {
85
+ function createWorkspacesRuntime({ config, env, jsonRestApi } = {}) {
86
86
  const tenancyProfile = resolveTenancyProfile(config);
87
87
  const invitationsPolicy = resolveWorkspaceInvitationsPolicy({ config, appConfig: config, tenancyProfile });
88
88
  const invitationsEnabled = invitationsPolicy.enabled === true;
89
89
  const roleCatalog = createWorkspaceRoleCatalog(config);
90
90
  const workspaceSettingsRepository = createWorkspaceSettingsRepository({
91
91
  api: jsonRestApi,
92
- knex: database.knex,
93
92
  defaultInvitesEnabled: requireBoolean(
94
93
  config?.workspaceSettings?.defaults?.invitesEnabled,
95
94
  "runtime.config.workspaceSettings.defaults.invitesEnabled"
96
95
  )
97
96
  });
98
- const workspacesRepository = createWorkspacesRepository({ api: jsonRestApi, knex: database.knex });
99
- const workspaceMembershipsRepository = createWorkspaceMembershipsRepository({
100
- api: jsonRestApi,
101
- knex: database.knex
102
- });
103
- const workspaceInvitesRepository = createWorkspaceInvitesRepository({
104
- api: jsonRestApi,
105
- knex: database.knex
106
- });
97
+ const workspacesRepository = createWorkspacesRepository({ api: jsonRestApi });
98
+ const workspaceMembershipsRepository = createWorkspaceMembershipsRepository({ api: jsonRestApi });
99
+ const workspaceInvitesRepository = createWorkspaceInvitesRepository({ api: jsonRestApi });
107
100
  const workspaceService = createWorkspaceService({
108
101
  appConfig: config,
109
102
  workspacesRepository,
@@ -165,7 +158,6 @@ const WorkspacesFeature = defineFeature({
165
158
  requires: {
166
159
  bootstrap: "runtime.bootstrap",
167
160
  config: "runtime.config",
168
- database: "runtime.database",
169
161
  env: "runtime.env",
170
162
  http: "runtime.http",
171
163
  jsonRestApi: "runtime.json-rest-api",
@@ -174,9 +166,9 @@ const WorkspacesFeature = defineFeature({
174
166
  provides: {
175
167
  workspaces: "workspaces.core"
176
168
  },
177
- async setup({ bootstrap, config, database, env, http, jsonRestApi, users }) {
169
+ async setup({ bootstrap, config, env, http, jsonRestApi, users }) {
178
170
  await installWorkspaceResources(jsonRestApi);
179
- const workspaces = createWorkspacesRuntime({ config, database, env, jsonRestApi });
171
+ const workspaces = createWorkspacesRuntime({ config, env, jsonRestApi });
180
172
 
181
173
  bootstrap.register({
182
174
  id: "workspaces.bootstrap",
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  normalizeDbRecordId,
3
- toIsoString,
4
- createWithTransaction
3
+ toIsoString
5
4
  } from "@jskit-ai/database-runtime/shared";
6
5
  import { isDuplicateEntryError } from "@jskit-ai/database-runtime/shared/duplicateEntry";
7
6
  import { normalizeLowerText, normalizeRecordId, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
@@ -38,6 +37,5 @@ export {
38
37
  normalizeDbRecordId,
39
38
  uniqueSorted,
40
39
  parseJson,
41
- toDbJson,
42
- createWithTransaction
40
+ toDbJson
43
41
  };
@@ -1,5 +1,4 @@
1
1
  import {
2
- createWithTransaction,
3
2
  normalizeLowerText,
4
3
  normalizeRecordId,
5
4
  normalizeDbRecordId,
@@ -8,14 +7,10 @@ import {
8
7
  toIsoString
9
8
  } from "./repositoryUtils.js";
10
9
  import {
11
- createJsonApiInputRecord,
12
- createJsonApiRelationship,
13
10
  createJsonRestContext,
14
11
  extractJsonRestCollectionRows
15
12
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
16
13
 
17
- const RESOURCE_TYPE = "workspaceInvites";
18
-
19
14
  function normalizeInviteRecord(payload) {
20
15
  if (!payload) {
21
16
  return null;
@@ -80,28 +75,12 @@ function normalizeInviteWithWorkspace(payload = {}) {
80
75
  };
81
76
  }
82
77
 
83
- function createInviteRelationships({ workspaceId = null, invitedByUserId = undefined } = {}) {
84
- const relationships = {};
85
-
86
- if (workspaceId) {
87
- relationships.workspace = createJsonApiRelationship("workspaces", workspaceId);
88
- }
89
- if (invitedByUserId !== undefined) {
90
- relationships.invitedByUser = createJsonApiRelationship("userProfiles", invitedByUserId);
91
- }
92
-
93
- return relationships;
94
- }
95
-
96
- function createRepository({ api, knex } = {}) {
78
+ function createRepository({ api } = {}) {
97
79
  if (!api?.resources?.workspaceInvites) {
98
80
  throw new TypeError("workspaceInvitesRepository requires json-rest-api workspaceInvites resource.");
99
81
  }
100
- if (typeof knex !== "function") {
101
- throw new TypeError("workspaceInvitesRepository requires knex.");
102
- }
103
82
 
104
- const withTransaction = createWithTransaction(knex);
83
+ const withTransaction = (work) => api.transaction(work);
105
84
 
106
85
  async function queryInvites(filters = {}, options = {}, { includeWorkspace = false } = {}) {
107
86
  return extractJsonRestCollectionRows(
@@ -112,7 +91,7 @@ function createRepository({ api, knex } = {}) {
112
91
  ...(includeWorkspace ? { include: ["workspace"] } : {})
113
92
  },
114
93
  transaction: options?.trx || null,
115
- simplified: true
94
+ format: "plain"
116
95
  },
117
96
  createJsonRestContext(options?.context || null)
118
97
  )
@@ -210,26 +189,21 @@ function createRepository({ api, knex } = {}) {
210
189
  const createdAt = new Date().toISOString();
211
190
  const created = await api.resources.workspaceInvites.post(
212
191
  {
213
- inputRecord: createJsonApiInputRecord(
214
- RESOURCE_TYPE,
215
- {
216
- email: createPayload.email,
217
- roleSid: createPayload.roleSid,
218
- status: createPayload.status,
219
- tokenHash: createPayload.tokenHash,
220
- expiresAt: createPayload.expiresAt == null ? null : toIsoString(createPayload.expiresAt),
221
- acceptedAt: null,
222
- revokedAt: null,
223
- createdAt,
224
- updatedAt: createdAt
225
- },
226
- {
227
- relationships: createInviteRelationships({
228
- workspaceId: createPayload.workspaceId,
229
- invitedByUserId: createPayload.invitedByUserId ?? null
230
- })
231
- }
232
- ),
192
+ data: {
193
+ email: createPayload.email,
194
+ roleSid: createPayload.roleSid,
195
+ status: createPayload.status,
196
+ tokenHash: createPayload.tokenHash,
197
+ expiresAt: createPayload.expiresAt == null ? null : toIsoString(createPayload.expiresAt),
198
+ acceptedAt: null,
199
+ revokedAt: null,
200
+ createdAt,
201
+ updatedAt: createdAt,
202
+ workspace: createPayload.workspaceId,
203
+ invitedByUser: createPayload.invitedByUserId ?? null
204
+ },
205
+ format: "plain",
206
+ returning: "full",
233
207
  transaction: options?.trx || null
234
208
  },
235
209
  createJsonRestContext(options?.context || null)
@@ -237,7 +211,7 @@ function createRepository({ api, knex } = {}) {
237
211
 
238
212
  return normalizeInviteRecord(created);
239
213
  } catch (error) {
240
- if (!isDuplicateEntryError(error)) {
214
+ if (options?.trx || error?.transactionOutcome !== "rolledBack" || !isDuplicateEntryError(error)) {
241
215
  throw error;
242
216
  }
243
217
  }
@@ -277,16 +251,13 @@ function createRepository({ api, knex } = {}) {
277
251
  }
278
252
  await api.resources.workspaceInvites.patch(
279
253
  {
280
- inputRecord: createJsonApiInputRecord(
281
- RESOURCE_TYPE,
282
- {
283
- status: patch.status,
284
- updatedAt: new Date().toISOString()
285
- },
286
- {
287
- id: row.id
288
- }
289
- ),
254
+ id: row.id,
255
+ data: {
256
+ status: patch.status,
257
+ updatedAt: new Date().toISOString()
258
+ },
259
+ format: "plain",
260
+ returning: "full",
290
261
  transaction: options?.trx || null
291
262
  },
292
263
  createJsonRestContext(options?.context || null)
@@ -303,17 +274,14 @@ function createRepository({ api, knex } = {}) {
303
274
  const acceptedAt = new Date().toISOString();
304
275
  await api.resources.workspaceInvites.patch(
305
276
  {
306
- inputRecord: createJsonApiInputRecord(
307
- RESOURCE_TYPE,
308
- {
309
- status: "accepted",
310
- acceptedAt,
311
- updatedAt: acceptedAt
312
- },
313
- {
314
- id: normalizedInviteId
315
- }
316
- ),
277
+ id: normalizedInviteId,
278
+ data: {
279
+ status: "accepted",
280
+ acceptedAt,
281
+ updatedAt: acceptedAt
282
+ },
283
+ format: "plain",
284
+ returning: "full",
317
285
  transaction: options?.trx || null
318
286
  },
319
287
  createJsonRestContext(options?.context || null)
@@ -329,17 +297,14 @@ function createRepository({ api, knex } = {}) {
329
297
  const revokedAt = new Date().toISOString();
330
298
  await api.resources.workspaceInvites.patch(
331
299
  {
332
- inputRecord: createJsonApiInputRecord(
333
- RESOURCE_TYPE,
334
- {
335
- status: "revoked",
336
- revokedAt,
337
- updatedAt: revokedAt
338
- },
339
- {
340
- id: normalizedInviteId
341
- }
342
- ),
300
+ id: normalizedInviteId,
301
+ data: {
302
+ status: "revoked",
303
+ revokedAt,
304
+ updatedAt: revokedAt
305
+ },
306
+ format: "plain",
307
+ returning: "full",
343
308
  transaction: options?.trx || null
344
309
  },
345
310
  createJsonRestContext(options?.context || null)
@@ -1,5 +1,4 @@
1
1
  import {
2
- createWithTransaction,
3
2
  normalizeLowerText,
4
3
  normalizeRecordId,
5
4
  normalizeDbRecordId,
@@ -8,15 +7,11 @@ import {
8
7
  toIsoString
9
8
  } from "./repositoryUtils.js";
10
9
  import {
11
- createJsonApiInputRecord,
12
- createJsonApiRelationship,
13
10
  createJsonRestContext,
14
11
  extractJsonRestCollectionRows
15
12
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
16
13
  import { OWNER_ROLE_ID } from "../../../shared/roles.js";
17
14
 
18
- const RESOURCE_TYPE = "workspaceMemberships";
19
-
20
15
  function normalizeMembershipRecord(payload) {
21
16
  if (!payload) {
22
17
  return null;
@@ -61,28 +56,12 @@ function normalizeMemberSummaryRow(row) {
61
56
  };
62
57
  }
63
58
 
64
- function createMembershipRelationships({ workspaceId = null, userId = null } = {}) {
65
- const relationships = {};
66
-
67
- if (workspaceId) {
68
- relationships.workspace = createJsonApiRelationship("workspaces", workspaceId);
69
- }
70
- if (userId) {
71
- relationships.user = createJsonApiRelationship("userProfiles", userId);
72
- }
73
-
74
- return relationships;
75
- }
76
-
77
- function createRepository({ api, knex } = {}) {
59
+ function createRepository({ api } = {}) {
78
60
  if (!api?.resources?.workspaceMemberships) {
79
61
  throw new TypeError("workspaceMembershipsRepository requires json-rest-api workspaceMemberships resource.");
80
62
  }
81
- if (typeof knex !== "function") {
82
- throw new TypeError("workspaceMembershipsRepository requires knex.");
83
- }
84
63
 
85
- const withTransaction = createWithTransaction(knex);
64
+ const withTransaction = (work) => api.transaction(work);
86
65
 
87
66
  async function queryMemberships(filters = {}, options = {}, { include = [] } = {}) {
88
67
  const normalizedInclude = Array.from(
@@ -100,7 +79,7 @@ function createRepository({ api, knex } = {}) {
100
79
  ...(normalizedInclude.length > 0 ? { include: normalizedInclude } : {})
101
80
  },
102
81
  transaction: options?.trx || null,
103
- simplified: true
82
+ format: "plain"
104
83
  },
105
84
  createJsonRestContext(options?.context || null)
106
85
  )
@@ -139,17 +118,14 @@ function createRepository({ api, knex } = {}) {
139
118
  const updatedAt = new Date().toISOString();
140
119
  await api.resources.workspaceMemberships.patch(
141
120
  {
142
- inputRecord: createJsonApiInputRecord(
143
- RESOURCE_TYPE,
144
- {
145
- roleSid: OWNER_ROLE_ID,
146
- status: "active",
147
- updatedAt
148
- },
149
- {
150
- id: existing.id
151
- }
152
- ),
121
+ id: existing.id,
122
+ data: {
123
+ roleSid: OWNER_ROLE_ID,
124
+ status: "active",
125
+ updatedAt
126
+ },
127
+ format: "plain",
128
+ returning: "full",
153
129
  transaction: options?.trx || null
154
130
  },
155
131
  createJsonRestContext(options?.context || null)
@@ -162,27 +138,22 @@ function createRepository({ api, knex } = {}) {
162
138
  const createdAt = new Date().toISOString();
163
139
  await api.resources.workspaceMemberships.post(
164
140
  {
165
- inputRecord: createJsonApiInputRecord(
166
- RESOURCE_TYPE,
167
- {
168
- roleSid: OWNER_ROLE_ID,
169
- status: "active",
170
- createdAt,
171
- updatedAt: createdAt
172
- },
173
- {
174
- relationships: createMembershipRelationships({
175
- workspaceId: normalizedWorkspaceId,
176
- userId: normalizedUserId
177
- })
178
- }
179
- ),
141
+ data: {
142
+ roleSid: OWNER_ROLE_ID,
143
+ status: "active",
144
+ createdAt,
145
+ updatedAt: createdAt,
146
+ workspace: normalizedWorkspaceId,
147
+ user: normalizedUserId
148
+ },
149
+ format: "plain",
150
+ returning: "full",
180
151
  transaction: options?.trx || null
181
152
  },
182
153
  createJsonRestContext(options?.context || null)
183
154
  );
184
155
  } catch (error) {
185
- if (!isDuplicateEntryError(error)) {
156
+ if (options?.trx || error?.transactionOutcome !== "rolledBack" || !isDuplicateEntryError(error)) {
186
157
  throw error;
187
158
  }
188
159
  }
@@ -210,27 +181,22 @@ function createRepository({ api, knex } = {}) {
210
181
  const createdAt = new Date().toISOString();
211
182
  await api.resources.workspaceMemberships.post(
212
183
  {
213
- inputRecord: createJsonApiInputRecord(
214
- RESOURCE_TYPE,
215
- {
216
- roleSid,
217
- status,
218
- createdAt,
219
- updatedAt: createdAt
220
- },
221
- {
222
- relationships: createMembershipRelationships({
223
- workspaceId: normalizedWorkspaceId,
224
- userId: normalizedUserId
225
- })
226
- }
227
- ),
184
+ data: {
185
+ roleSid,
186
+ status,
187
+ createdAt,
188
+ updatedAt: createdAt,
189
+ workspace: normalizedWorkspaceId,
190
+ user: normalizedUserId
191
+ },
192
+ format: "plain",
193
+ returning: "full",
228
194
  transaction: options?.trx || null
229
195
  },
230
196
  createJsonRestContext(options?.context || null)
231
197
  );
232
198
  } catch (error) {
233
- if (!isDuplicateEntryError(error)) {
199
+ if (options?.trx || error?.transactionOutcome !== "rolledBack" || !isDuplicateEntryError(error)) {
234
200
  throw error;
235
201
  }
236
202
  }
@@ -240,17 +206,14 @@ function createRepository({ api, knex } = {}) {
240
206
  const updatedAt = new Date().toISOString();
241
207
  await api.resources.workspaceMemberships.patch(
242
208
  {
243
- inputRecord: createJsonApiInputRecord(
244
- RESOURCE_TYPE,
245
- {
246
- roleSid,
247
- status,
248
- updatedAt
249
- },
250
- {
251
- id: existing.id
252
- }
253
- ),
209
+ id: existing.id,
210
+ data: {
211
+ roleSid,
212
+ status,
213
+ updatedAt
214
+ },
215
+ format: "plain",
216
+ returning: "full",
254
217
  transaction: options?.trx || null
255
218
  },
256
219
  createJsonRestContext(options?.context || null)
@@ -1,19 +1,14 @@
1
1
  import {
2
- createWithTransaction,
3
2
  normalizeRecordId,
4
3
  isDuplicateEntryError,
5
4
  normalizeText,
6
5
  toIsoString
7
6
  } from "./repositoryUtils.js";
8
7
  import {
9
- createJsonApiInputRecord,
10
- createJsonApiRelationship,
11
8
  createJsonRestContext,
12
9
  extractJsonRestCollectionRows
13
10
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
14
11
 
15
- const RESOURCE_TYPE = "workspaces";
16
-
17
12
  function normalizeWorkspaceRecord(payload = null) {
18
13
  if (!payload || typeof payload !== "object") {
19
14
  return null;
@@ -32,26 +27,12 @@ function normalizeWorkspaceRecord(payload = null) {
32
27
  };
33
28
  }
34
29
 
35
- function createWorkspaceRelationships(source = {}) {
36
- const relationships = {};
37
- const ownerUserId = normalizeRecordId(source.ownerUserId, { fallback: null });
38
-
39
- if (ownerUserId) {
40
- relationships.owner = createJsonApiRelationship("userProfiles", ownerUserId);
41
- }
42
-
43
- return relationships;
44
- }
45
-
46
- function createRepository({ api, knex } = {}) {
30
+ function createRepository({ api } = {}) {
47
31
  if (!api?.resources?.workspaces || !api?.resources?.workspaceMemberships) {
48
32
  throw new TypeError("workspacesRepository requires json-rest-api workspaces and workspaceMemberships resources.");
49
33
  }
50
- if (typeof knex !== "function") {
51
- throw new TypeError("workspacesRepository requires knex.");
52
- }
53
34
 
54
- const withTransaction = createWithTransaction(knex);
35
+ const withTransaction = (work) => api.transaction(work);
55
36
 
56
37
  async function queryFirst(filters = {}, options = {}) {
57
38
  const rows = extractJsonRestCollectionRows(
@@ -61,7 +42,7 @@ function createRepository({ api, knex } = {}) {
61
42
  filters
62
43
  },
63
44
  transaction: options?.trx || null,
64
- simplified: true
45
+ format: "plain"
65
46
  },
66
47
  createJsonRestContext(options?.context || null)
67
48
  )
@@ -104,7 +85,7 @@ function createRepository({ api, knex } = {}) {
104
85
  }
105
86
  },
106
87
  transaction: options?.trx || null,
107
- simplified: true
88
+ format: "plain"
108
89
  },
109
90
  createJsonRestContext(options?.context || null)
110
91
  )
@@ -140,17 +121,14 @@ function createRepository({ api, knex } = {}) {
140
121
  const createdAt = new Date().toISOString();
141
122
  const created = await api.resources.workspaces.post(
142
123
  {
143
- inputRecord: createJsonApiInputRecord(
144
- RESOURCE_TYPE,
145
- {
146
- ...createPayload,
147
- createdAt,
148
- updatedAt: createdAt
149
- },
150
- {
151
- relationships: createWorkspaceRelationships({ ownerUserId })
152
- }
153
- ),
124
+ data: {
125
+ ...createPayload,
126
+ createdAt,
127
+ updatedAt: createdAt,
128
+ owner: ownerUserId
129
+ },
130
+ format: "plain",
131
+ returning: "full",
154
132
  transaction: options?.trx || null
155
133
  },
156
134
  createJsonRestContext(options?.context || null)
@@ -158,7 +136,7 @@ function createRepository({ api, knex } = {}) {
158
136
 
159
137
  return normalizeWorkspaceRecord(created);
160
138
  } catch (error) {
161
- if (!isDuplicateEntryError(error)) {
139
+ if (options?.trx || error?.transactionOutcome !== "rolledBack" || !isDuplicateEntryError(error)) {
162
140
  throw error;
163
141
  }
164
142
  if (!Object.hasOwn(createPayload, "slug")) {
@@ -184,18 +162,17 @@ function createRepository({ api, knex } = {}) {
184
162
  ...sourcePatch,
185
163
  updatedAt: new Date().toISOString()
186
164
  };
187
- const relationships = createWorkspaceRelationships(sourcePatch);
165
+ delete workspacePatch.ownerUserId;
166
+ if (Object.hasOwn(sourcePatch, "ownerUserId")) {
167
+ workspacePatch.owner = normalizeRecordId(sourcePatch.ownerUserId, { fallback: null });
168
+ }
188
169
 
189
170
  const updated = await api.resources.workspaces.patch(
190
171
  {
191
- inputRecord: createJsonApiInputRecord(
192
- RESOURCE_TYPE,
193
- workspacePatch,
194
- {
195
- id: normalizedWorkspaceId,
196
- relationships
197
- }
198
- ),
172
+ id: normalizedWorkspaceId,
173
+ data: workspacePatch,
174
+ format: "plain",
175
+ returning: "full",
199
176
  transaction: options?.trx || null
200
177
  },
201
178
  createJsonRestContext(options?.context || null)
@@ -221,7 +198,7 @@ function createRepository({ api, knex } = {}) {
221
198
  include: ["workspace"]
222
199
  },
223
200
  transaction: options?.trx || null,
224
- simplified: true
201
+ format: "plain"
225
202
  },
226
203
  createJsonRestContext(options?.context || null)
227
204
  )