@jskit-ai/workspaces-core 0.1.34 → 0.1.36

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.
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  packageVersion: 1,
3
3
  packageId: "@jskit-ai/workspaces-core",
4
- version: "0.1.34",
4
+ version: "0.1.36",
5
5
  kind: "runtime",
6
6
  description: "Workspace tenancy runtime plus HTTP routes, role catalog, and workspace config scaffolding.",
7
7
  dependsOn: [
@@ -116,10 +116,10 @@ export default Object.freeze({
116
116
  mutations: {
117
117
  dependencies: {
118
118
  runtime: {
119
- "@jskit-ai/json-rest-api-core": "0.1.3",
120
- "@jskit-ai/resource-core": "0.1.3",
121
- "@jskit-ai/resource-crud-core": "0.1.3",
122
- "@jskit-ai/users-core": "0.1.68"
119
+ "@jskit-ai/json-rest-api-core": "0.1.5",
120
+ "@jskit-ai/resource-core": "0.1.5",
121
+ "@jskit-ai/resource-crud-core": "0.1.5",
122
+ "@jskit-ai/users-core": "0.1.70"
123
123
  },
124
124
  dev: {}
125
125
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/workspaces-core",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -17,14 +17,14 @@
17
17
  "./shared/resources/workspaceSettingsResource": "./src/shared/resources/workspaceSettingsResource.js"
18
18
  },
19
19
  "dependencies": {
20
- "@jskit-ai/auth-core": "0.1.57",
21
- "@jskit-ai/database-runtime": "0.1.58",
22
- "@jskit-ai/http-runtime": "0.1.57",
23
- "@jskit-ai/json-rest-api-core": "0.1.3",
24
- "@jskit-ai/kernel": "0.1.58",
25
- "@jskit-ai/resource-crud-core": "0.1.3",
26
- "@jskit-ai/resource-core": "0.1.3",
27
- "@jskit-ai/users-core": "0.1.68",
20
+ "@jskit-ai/auth-core": "0.1.59",
21
+ "@jskit-ai/database-runtime": "0.1.60",
22
+ "@jskit-ai/http-runtime": "0.1.59",
23
+ "@jskit-ai/json-rest-api-core": "0.1.5",
24
+ "@jskit-ai/kernel": "0.1.60",
25
+ "@jskit-ai/resource-crud-core": "0.1.5",
26
+ "@jskit-ai/resource-core": "0.1.5",
27
+ "@jskit-ai/users-core": "0.1.70",
28
28
  "json-rest-schema": "1.x.x"
29
29
  }
30
30
  }
@@ -12,7 +12,7 @@ import {
12
12
  createJsonApiInputRecord,
13
13
  createJsonApiRelationship,
14
14
  createJsonRestContext,
15
- simplifyJsonApiDocument
15
+ extractJsonRestCollectionRows
16
16
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
17
17
 
18
18
  const RESOURCE_TYPE = "workspaceInvites";
@@ -105,19 +105,19 @@ function createRepository({ api, knex } = {}) {
105
105
  const withTransaction = createWithTransaction(knex);
106
106
 
107
107
  async function queryInvites(filters = {}, options = {}, { includeWorkspace = false } = {}) {
108
- const result = await api.resources.workspaceInvites.query(
109
- {
110
- queryParams: {
111
- filters,
112
- ...(includeWorkspace ? { include: ["workspace"] } : {})
108
+ return extractJsonRestCollectionRows(
109
+ await api.resources.workspaceInvites.query(
110
+ {
111
+ queryParams: {
112
+ filters,
113
+ ...(includeWorkspace ? { include: ["workspace"] } : {})
114
+ },
115
+ transaction: options?.trx || null,
116
+ simplified: true
113
117
  },
114
- transaction: options?.trx || null,
115
- simplified: false
116
- },
117
- createJsonRestContext(options?.context || null)
118
+ createJsonRestContext(options?.context || null)
119
+ )
118
120
  );
119
-
120
- return Array.isArray(simplifyJsonApiDocument(result)) ? simplifyJsonApiDocument(result) : [];
121
121
  }
122
122
 
123
123
  async function findPendingByTokenHash(tokenHash, options = {}) {
@@ -213,13 +213,12 @@ function createRepository({ api, knex } = {}) {
213
213
  })
214
214
  }
215
215
  ),
216
- transaction: options?.trx || null,
217
- simplified: false
216
+ transaction: options?.trx || null
218
217
  },
219
218
  createJsonRestContext(options?.context || null)
220
219
  );
221
220
 
222
- return normalizeInviteRecord(simplifyJsonApiDocument(created));
221
+ return normalizeInviteRecord(created);
223
222
  } catch (error) {
224
223
  if (!isDuplicateEntryError(error)) {
225
224
  throw error;
@@ -271,8 +270,7 @@ function createRepository({ api, knex } = {}) {
271
270
  id: row.id
272
271
  }
273
272
  ),
274
- transaction: options?.trx || null,
275
- simplified: false
273
+ transaction: options?.trx || null
276
274
  },
277
275
  createJsonRestContext(options?.context || null)
278
276
  );
@@ -298,8 +296,7 @@ function createRepository({ api, knex } = {}) {
298
296
  id: normalizedInviteId
299
297
  }
300
298
  ),
301
- transaction: options?.trx || null,
302
- simplified: false
299
+ transaction: options?.trx || null
303
300
  },
304
301
  createJsonRestContext(options?.context || null)
305
302
  );
@@ -324,8 +321,7 @@ function createRepository({ api, knex } = {}) {
324
321
  id: normalizedInviteId
325
322
  }
326
323
  ),
327
- transaction: options?.trx || null,
328
- simplified: false
324
+ transaction: options?.trx || null
329
325
  },
330
326
  createJsonRestContext(options?.context || null)
331
327
  );
@@ -11,7 +11,7 @@ import {
11
11
  createJsonApiInputRecord,
12
12
  createJsonApiRelationship,
13
13
  createJsonRestContext,
14
- simplifyJsonApiDocument
14
+ extractJsonRestCollectionRows
15
15
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
16
16
  import { OWNER_ROLE_ID } from "../../../shared/roles.js";
17
17
 
@@ -92,19 +92,19 @@ function createRepository({ api, knex } = {}) {
92
92
  .filter(Boolean)
93
93
  )
94
94
  );
95
- const result = await api.resources.workspaceMemberships.query(
96
- {
97
- queryParams: {
98
- filters,
99
- ...(normalizedInclude.length > 0 ? { include: normalizedInclude } : {})
95
+ return extractJsonRestCollectionRows(
96
+ await api.resources.workspaceMemberships.query(
97
+ {
98
+ queryParams: {
99
+ filters,
100
+ ...(normalizedInclude.length > 0 ? { include: normalizedInclude } : {})
101
+ },
102
+ transaction: options?.trx || null,
103
+ simplified: true
100
104
  },
101
- transaction: options?.trx || null,
102
- simplified: false
103
- },
104
- createJsonRestContext(options?.context || null)
105
+ createJsonRestContext(options?.context || null)
106
+ )
105
107
  );
106
-
107
- return Array.isArray(simplifyJsonApiDocument(result)) ? simplifyJsonApiDocument(result) : [];
108
108
  }
109
109
 
110
110
  async function findByWorkspaceIdAndUserId(workspaceId, userId, options = {}) {
@@ -148,8 +148,7 @@ function createRepository({ api, knex } = {}) {
148
148
  id: existing.id
149
149
  }
150
150
  ),
151
- transaction: options?.trx || null,
152
- simplified: false
151
+ transaction: options?.trx || null
153
152
  },
154
153
  createJsonRestContext(options?.context || null)
155
154
  );
@@ -175,8 +174,7 @@ function createRepository({ api, knex } = {}) {
175
174
  })
176
175
  }
177
176
  ),
178
- transaction: options?.trx || null,
179
- simplified: false
177
+ transaction: options?.trx || null
180
178
  },
181
179
  createJsonRestContext(options?.context || null)
182
180
  );
@@ -223,8 +221,7 @@ function createRepository({ api, knex } = {}) {
223
221
  })
224
222
  }
225
223
  ),
226
- transaction: options?.trx || null,
227
- simplified: false
224
+ transaction: options?.trx || null
228
225
  },
229
226
  createJsonRestContext(options?.context || null)
230
227
  );
@@ -249,8 +246,7 @@ function createRepository({ api, knex } = {}) {
249
246
  id: existing.id
250
247
  }
251
248
  ),
252
- transaction: options?.trx || null,
253
- simplified: false
249
+ transaction: options?.trx || null
254
250
  },
255
251
  createJsonRestContext(options?.context || null)
256
252
  );
@@ -9,7 +9,7 @@ import {
9
9
  createJsonApiInputRecord,
10
10
  createJsonApiRelationship,
11
11
  createJsonRestContext,
12
- simplifyJsonApiDocument
12
+ extractJsonRestCollectionRows
13
13
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
14
14
 
15
15
  const RESOURCE_TYPE = "workspaces";
@@ -54,19 +54,20 @@ function createRepository({ api, knex } = {}) {
54
54
  const withTransaction = createWithTransaction(knex);
55
55
 
56
56
  async function queryFirst(filters = {}, options = {}) {
57
- const result = await api.resources.workspaces.query(
58
- {
59
- queryParams: {
60
- filters
57
+ const rows = extractJsonRestCollectionRows(
58
+ await api.resources.workspaces.query(
59
+ {
60
+ queryParams: {
61
+ filters
62
+ },
63
+ transaction: options?.trx || null,
64
+ simplified: true
61
65
  },
62
- transaction: options?.trx || null,
63
- simplified: false
64
- },
65
- createJsonRestContext(options?.context || null)
66
+ createJsonRestContext(options?.context || null)
67
+ )
66
68
  );
67
69
 
68
- const rows = simplifyJsonApiDocument(result);
69
- return normalizeWorkspaceRecord(Array.isArray(rows) ? rows[0] || null : null);
70
+ return normalizeWorkspaceRecord(rows[0] || null);
70
71
  }
71
72
 
72
73
  async function findById(workspaceId, options = {}) {
@@ -93,24 +94,24 @@ function createRepository({ api, knex } = {}) {
93
94
  return null;
94
95
  }
95
96
 
96
- const result = await api.resources.workspaces.query(
97
- {
98
- queryParams: {
99
- filters: {
100
- owner: normalizedUserId,
101
- isPersonal: true
102
- }
97
+ const rows = extractJsonRestCollectionRows(
98
+ await api.resources.workspaces.query(
99
+ {
100
+ queryParams: {
101
+ filters: {
102
+ owner: normalizedUserId,
103
+ isPersonal: true
104
+ }
105
+ },
106
+ transaction: options?.trx || null,
107
+ simplified: true
103
108
  },
104
- transaction: options?.trx || null,
105
- simplified: false
106
- },
107
- createJsonRestContext(options?.context || null)
109
+ createJsonRestContext(options?.context || null)
110
+ )
108
111
  );
109
112
 
110
- const rows = Array.isArray(simplifyJsonApiDocument(result))
111
- ? simplifyJsonApiDocument(result).map((row) => normalizeWorkspaceRecord(row)).filter(Boolean)
112
- : [];
113
- rows.sort((left, right) => {
113
+ const normalizedRows = rows.map((row) => normalizeWorkspaceRecord(row)).filter(Boolean);
114
+ normalizedRows.sort((left, right) => {
114
115
  const leftId = Number(left?.id);
115
116
  const rightId = Number(right?.id);
116
117
  if (Number.isFinite(leftId) && Number.isFinite(rightId)) {
@@ -118,7 +119,7 @@ function createRepository({ api, knex } = {}) {
118
119
  }
119
120
  return String(left?.id || "").localeCompare(String(right?.id || ""));
120
121
  });
121
- return rows[0] || null;
122
+ return normalizedRows[0] || null;
122
123
  }
123
124
 
124
125
  async function insert(payload = {}, options = {}) {
@@ -149,13 +150,12 @@ function createRepository({ api, knex } = {}) {
149
150
  relationships: createWorkspaceRelationships({ ownerUserId })
150
151
  }
151
152
  ),
152
- transaction: options?.trx || null,
153
- simplified: false
153
+ transaction: options?.trx || null
154
154
  },
155
155
  createJsonRestContext(options?.context || null)
156
156
  );
157
157
 
158
- return normalizeWorkspaceRecord(simplifyJsonApiDocument(created));
158
+ return normalizeWorkspaceRecord(created);
159
159
  } catch (error) {
160
160
  if (!isDuplicateEntryError(error)) {
161
161
  throw error;
@@ -195,13 +195,12 @@ function createRepository({ api, knex } = {}) {
195
195
  relationships
196
196
  }
197
197
  ),
198
- transaction: options?.trx || null,
199
- simplified: false
198
+ transaction: options?.trx || null
200
199
  },
201
200
  createJsonRestContext(options?.context || null)
202
201
  );
203
202
 
204
- return normalizeWorkspaceRecord(simplifyJsonApiDocument(updated));
203
+ return normalizeWorkspaceRecord(updated);
205
204
  }
206
205
 
207
206
  async function listForUserId(userId, options = {}) {
@@ -210,22 +209,23 @@ function createRepository({ api, knex } = {}) {
210
209
  return [];
211
210
  }
212
211
 
213
- const result = await api.resources.workspaceMemberships.query(
214
- {
215
- queryParams: {
216
- filters: {
217
- user: normalizedUserId,
218
- status: "active"
212
+ const rows = extractJsonRestCollectionRows(
213
+ await api.resources.workspaceMemberships.query(
214
+ {
215
+ queryParams: {
216
+ filters: {
217
+ user: normalizedUserId,
218
+ status: "active"
219
+ },
220
+ include: ["workspace"]
219
221
  },
220
- include: ["workspace"]
222
+ transaction: options?.trx || null,
223
+ simplified: true
221
224
  },
222
- transaction: options?.trx || null,
223
- simplified: false
224
- },
225
- createJsonRestContext(options?.context || null)
225
+ createJsonRestContext(options?.context || null)
226
+ )
226
227
  );
227
228
 
228
- const rows = Array.isArray(simplifyJsonApiDocument(result)) ? simplifyJsonApiDocument(result) : [];
229
229
  const workspaces = rows
230
230
  .map((row) => {
231
231
  const workspace = normalizeWorkspaceRecord(row?.workspace);
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  createJsonApiInputRecord,
9
9
  createJsonRestContext,
10
- simplifyJsonApiDocument
10
+ extractJsonRestCollectionRows
11
11
  } from "@jskit-ai/json-rest-api-core/server/jsonRestApiHost";
12
12
  import { resolveWorkspaceThemePalettes } from "../../shared/settings.js";
13
13
 
@@ -63,19 +63,20 @@ function createRepository({ api, knex } = {}) {
63
63
  const withTransaction = createWithTransaction(knex);
64
64
 
65
65
  async function queryFirst(filters = {}, options = {}) {
66
- const result = await api.resources.workspaceSettings.query(
67
- {
68
- queryParams: {
69
- filters
66
+ const rows = extractJsonRestCollectionRows(
67
+ await api.resources.workspaceSettings.query(
68
+ {
69
+ queryParams: {
70
+ filters
71
+ },
72
+ transaction: options?.trx || null,
73
+ simplified: true
70
74
  },
71
- transaction: options?.trx || null,
72
- simplified: false
73
- },
74
- createJsonRestContext(options?.context || null)
75
+ createJsonRestContext(options?.context || null)
76
+ )
75
77
  );
76
78
 
77
- const rows = simplifyJsonApiDocument(result);
78
- return Array.isArray(rows) ? rows[0] || null : null;
79
+ return rows[0] || null;
79
80
  }
80
81
 
81
82
  async function findByWorkspaceId(workspaceId, options = {}) {
@@ -108,8 +109,7 @@ function createRepository({ api, knex } = {}) {
108
109
  id: normalizedWorkspaceId
109
110
  }
110
111
  ),
111
- transaction: options?.trx || null,
112
- simplified: false
112
+ transaction: options?.trx || null
113
113
  },
114
114
  createJsonRestContext(options?.context || null)
115
115
  );
@@ -148,8 +148,7 @@ function createRepository({ api, knex } = {}) {
148
148
  id: normalizedWorkspaceId
149
149
  }
150
150
  ),
151
- transaction: options?.trx || null,
152
- simplified: false
151
+ transaction: options?.trx || null
153
152
  },
154
153
  createJsonRestContext(options?.context || null)
155
154
  );
@@ -15,34 +15,34 @@ function createKnexStub() {
15
15
  return knex;
16
16
  }
17
17
 
18
- function toWorkspaceInviteResource(row = {}, { includeWorkspace = false } = {}) {
18
+ function asCollectionDocument(rows = []) {
19
+ return {
20
+ data: Array.isArray(rows) ? rows : []
21
+ };
22
+ }
23
+
24
+ function toWorkspaceInviteRow(row = {}) {
19
25
  return {
20
- type: "workspaceInvites",
21
26
  id: String(row.id || ""),
22
- attributes: {
23
- email: row.email,
24
- roleSid: row.roleSid,
25
- status: row.status,
26
- tokenHash: row.tokenHash,
27
- expiresAt: row.expiresAt,
28
- acceptedAt: row.acceptedAt,
29
- revokedAt: row.revokedAt,
30
- createdAt: row.createdAt,
31
- updatedAt: row.updatedAt
27
+ workspaceId: row?.workspace?.id == null ? null : String(row.workspace.id),
28
+ workspace: row?.workspace?.id == null ? null : {
29
+ ...row.workspace,
30
+ id: String(row.workspace.id)
32
31
  },
33
- relationships: {
34
- workspace: {
35
- data: row?.workspace?.id == null
36
- ? null
37
- : {
38
- type: "workspaces",
39
- id: String(row.workspace.id)
40
- }
41
- },
42
- invitedByUser: {
43
- data: row?.invitedByUser?.id == null ? null : { type: "userProfiles", id: String(row.invitedByUser.id) }
44
- }
45
- }
32
+ email: row.email,
33
+ roleSid: row.roleSid,
34
+ status: row.status,
35
+ tokenHash: row.tokenHash,
36
+ invitedByUserId: row?.invitedByUser?.id == null ? null : String(row.invitedByUser.id),
37
+ invitedByUser: row?.invitedByUser?.id == null ? null : {
38
+ ...row.invitedByUser,
39
+ id: String(row.invitedByUser.id)
40
+ },
41
+ expiresAt: row.expiresAt,
42
+ acceptedAt: row.acceptedAt,
43
+ revokedAt: row.revokedAt,
44
+ createdAt: row.createdAt,
45
+ updatedAt: row.updatedAt
46
46
  };
47
47
  }
48
48
 
@@ -60,7 +60,6 @@ function createWorkspaceInvitesApiStub({
60
60
  workspaceInvites: {
61
61
  async query({ queryParams }) {
62
62
  const filters = queryParams?.filters || {};
63
- const includeWorkspace = Array.isArray(queryParams?.include) && queryParams.include.includes("workspace");
64
63
  const matching = rows.filter((row) => {
65
64
  if (Object.hasOwn(filters, "id") && String(row.id) !== String(filters.id)) {
66
65
  return false;
@@ -80,25 +79,9 @@ function createWorkspaceInvitesApiStub({
80
79
  return true;
81
80
  });
82
81
 
83
- return {
84
- data: matching.map((row) => toWorkspaceInviteResource(row, { includeWorkspace })),
85
- included: includeWorkspace
86
- ? matching
87
- .filter((row) => row?.workspace?.id != null)
88
- .map((row) => ({
89
- type: "workspaces",
90
- id: String(row.workspace.id),
91
- attributes: {
92
- slug: row.workspace.slug,
93
- name: row.workspace.name,
94
- avatarUrl: row.workspace.avatarUrl
95
- }
96
- }))
97
- : []
98
- };
82
+ return asCollectionDocument(matching.map((row) => toWorkspaceInviteRow(row)));
99
83
  },
100
84
  async post(payload) {
101
- assert.equal(payload?.simplified, false);
102
85
  const inputRecord = payload?.inputRecord?.data || {};
103
86
  state.postPayload = inputRecord;
104
87
  const row = {
@@ -119,10 +102,9 @@ function createWorkspaceInvitesApiStub({
119
102
  };
120
103
  rows.push(row);
121
104
  rowById.set("1", row);
122
- return { data: toWorkspaceInviteResource(row) };
105
+ return toWorkspaceInviteRow(row);
123
106
  },
124
107
  async patch(payload) {
125
- assert.equal(payload?.simplified, false);
126
108
  const inputRecord = payload?.inputRecord?.data || {};
127
109
  state.patchPayloads.push(inputRecord);
128
110
  const existing = rowById.get(String(inputRecord.id));
@@ -134,7 +116,7 @@ function createWorkspaceInvitesApiStub({
134
116
  rowById.set(String(inputRecord.id), updated);
135
117
  }
136
118
  const updatedRow = rowById.get(String(inputRecord.id)) || null;
137
- return updatedRow ? { data: toWorkspaceInviteResource(updatedRow) } : null;
119
+ return updatedRow ? toWorkspaceInviteRow(updatedRow) : null;
138
120
  }
139
121
  }
140
122
  }
@@ -15,29 +15,31 @@ function createKnexStub() {
15
15
  return knex;
16
16
  }
17
17
 
18
- function toWorkspaceMembershipResource(row = {}) {
18
+ function asCollectionDocument(rows = []) {
19
+ return {
20
+ data: Array.isArray(rows) ? rows : []
21
+ };
22
+ }
23
+
24
+ function toWorkspaceMembershipRow(row = {}) {
19
25
  return {
20
- type: "workspaceMemberships",
21
26
  id: String(row.id || ""),
22
- attributes: {
23
- roleSid: row.roleSid,
24
- status: row.status,
25
- createdAt: row.createdAt,
26
- updatedAt: row.updatedAt
27
+ workspaceId: row?.workspace?.id == null ? null : String(row.workspace.id),
28
+ workspace: row?.workspace?.id == null ? null : {
29
+ ...row.workspace,
30
+ id: String(row.workspace.id)
27
31
  },
28
- relationships: {
29
- workspace: {
30
- data: row?.workspace?.id == null ? null : { type: "workspaces", id: String(row.workspace.id) }
31
- },
32
- user: {
33
- data: row?.user?.id == null
34
- ? null
35
- : {
36
- type: "userProfiles",
37
- id: String(row.user.id)
38
- }
39
- }
40
- }
32
+ userId: row?.user?.id == null ? null : String(row.user.id),
33
+ user: row?.user?.id == null
34
+ ? null
35
+ : {
36
+ ...row.user,
37
+ id: String(row.user.id)
38
+ },
39
+ roleSid: row.roleSid,
40
+ status: row.status,
41
+ createdAt: row.createdAt,
42
+ updatedAt: row.updatedAt
41
43
  };
42
44
  }
43
45
 
@@ -62,23 +64,11 @@ function createWorkspaceMembershipsApiStub({
62
64
 
63
65
  if (Object.hasOwn(filters, "workspace") && Object.hasOwn(filters, "user")) {
64
66
  const row = rowByComposite.get(`${filters.workspace}:${filters.user}`) || null;
65
- return { data: row ? [toWorkspaceMembershipResource(row)] : [] };
67
+ return asCollectionDocument(row ? [toWorkspaceMembershipRow(row)] : []);
66
68
  }
67
69
 
68
70
  if (Object.hasOwn(filters, "workspace") && Object.hasOwn(filters, "status") && includeUser) {
69
- return {
70
- data: memberSummaryRows.map((row) => toWorkspaceMembershipResource(row)),
71
- included: memberSummaryRows
72
- .filter((row) => row?.user?.id != null)
73
- .map((row) => ({
74
- type: "userProfiles",
75
- id: String(row.user.id),
76
- attributes: {
77
- displayName: row.user.displayName,
78
- email: row.user.email
79
- }
80
- }))
81
- };
71
+ return asCollectionDocument(memberSummaryRows.map((row) => toWorkspaceMembershipRow(row)));
82
72
  }
83
73
 
84
74
  if (Object.hasOwn(filters, "user") && Object.hasOwn(filters, "status")) {
@@ -86,13 +76,12 @@ function createWorkspaceMembershipsApiStub({
86
76
  String(row?.user?.id || "") === String(filters.user) &&
87
77
  String(row?.status || "") === String(filters.status)
88
78
  ));
89
- return { data: rows.map((row) => toWorkspaceMembershipResource(row)) };
79
+ return asCollectionDocument(rows.map((row) => toWorkspaceMembershipRow(row)));
90
80
  }
91
81
 
92
- return { data: [] };
82
+ return asCollectionDocument([]);
93
83
  },
94
84
  async post(payload) {
95
- assert.equal(payload?.simplified, false);
96
85
  const inputRecord = payload?.inputRecord?.data || {};
97
86
  state.postPayload = inputRecord;
98
87
  const row = rowById.get("1") || {
@@ -106,10 +95,9 @@ function createWorkspaceMembershipsApiStub({
106
95
  };
107
96
  rowByComposite.set(`${row.workspace.id}:${row.user.id}`, row);
108
97
  rowById.set(String(row.id), row);
109
- return { data: toWorkspaceMembershipResource(row) };
98
+ return toWorkspaceMembershipRow(row);
110
99
  },
111
100
  async patch(payload) {
112
- assert.equal(payload?.simplified, false);
113
101
  const inputRecord = payload?.inputRecord?.data || {};
114
102
  state.patchPayload = inputRecord;
115
103
  const existing = rowById.get(String(inputRecord.id));
@@ -122,7 +110,7 @@ function createWorkspaceMembershipsApiStub({
122
110
  };
123
111
  rowById.set(String(updated.id), updated);
124
112
  rowByComposite.set(`${updated.workspace.id}:${updated.user.id}`, updated);
125
- return { data: toWorkspaceMembershipResource(updated) };
113
+ return toWorkspaceMembershipRow(updated);
126
114
  }
127
115
  }
128
116
  }
@@ -20,6 +20,12 @@ function normalizeWorkspaceColor(value) {
20
20
  return typeof value === "string" ? value.toUpperCase() : value;
21
21
  }
22
22
 
23
+ function asCollectionDocument(rows = []) {
24
+ return {
25
+ data: Array.isArray(rows) ? rows : []
26
+ };
27
+ }
28
+
23
29
  function createWorkspaceSettingsApiStub(rowOverrides = {}) {
24
30
  const DEFAULT_WORKSPACE_THEME = resolveWorkspaceThemePalettes({});
25
31
  const STUB_CREATED_AT = "2026-03-09 00:26:35.710";
@@ -51,31 +57,15 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
51
57
  async query({ queryParams }) {
52
58
  const id = String(queryParams?.filters?.id || "");
53
59
  if (!state.row || (id && String(state.row.id) !== id)) {
54
- return { data: [] };
60
+ return asCollectionDocument([]);
55
61
  }
56
62
 
57
- return {
58
- data: [{
59
- type: "workspaceSettings",
60
- id: String(state.row.id),
61
- attributes: {
62
- lightPrimaryColor: state.row.lightPrimaryColor,
63
- lightSecondaryColor: state.row.lightSecondaryColor,
64
- lightSurfaceColor: state.row.lightSurfaceColor,
65
- lightSurfaceVariantColor: state.row.lightSurfaceVariantColor,
66
- darkPrimaryColor: state.row.darkPrimaryColor,
67
- darkSecondaryColor: state.row.darkSecondaryColor,
68
- darkSurfaceColor: state.row.darkSurfaceColor,
69
- darkSurfaceVariantColor: state.row.darkSurfaceVariantColor,
70
- invitesEnabled: state.row.invitesEnabled,
71
- createdAt: state.row.createdAt,
72
- updatedAt: state.row.updatedAt
73
- }
74
- }]
75
- };
63
+ return asCollectionDocument([{
64
+ ...state.row,
65
+ id: String(state.row.id)
66
+ }]);
76
67
  },
77
68
  async post(payload) {
78
- assert.equal(payload?.simplified, false);
79
69
  const inputRecord = payload?.inputRecord?.data || {};
80
70
  const attributes = inputRecord.attributes || {};
81
71
  state.postPayload = inputRecord;
@@ -94,17 +84,11 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
94
84
  updatedAt: toIsoString("2026-03-10 00:00:00.000")
95
85
  };
96
86
  return {
97
- data: {
98
- type: "workspaceSettings",
99
- id: String(state.row.id),
100
- attributes: {
101
- ...state.row
102
- }
103
- }
87
+ ...state.row,
88
+ id: String(state.row.id)
104
89
  };
105
90
  },
106
91
  async patch(payload) {
107
- assert.equal(payload?.simplified, false);
108
92
  const inputRecord = payload?.inputRecord?.data || {};
109
93
  const attributes = inputRecord.attributes || {};
110
94
  state.patchPayload = inputRecord;
@@ -122,13 +106,8 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
122
106
  id: String(inputRecord.id || state.row?.id || "")
123
107
  };
124
108
  return {
125
- data: {
126
- type: "workspaceSettings",
127
- id: String(state.row.id),
128
- attributes: {
129
- ...state.row
130
- }
131
- }
109
+ ...state.row,
110
+ id: String(state.row.id)
132
111
  };
133
112
  }
134
113
  }
@@ -13,50 +13,35 @@ function createKnexStub() {
13
13
  });
14
14
  }
15
15
 
16
- function toWorkspaceResource(row = {}) {
16
+ function asCollectionDocument(rows = []) {
17
+ return {
18
+ data: Array.isArray(rows) ? rows : []
19
+ };
20
+ }
21
+
22
+ function toWorkspaceRow(row = {}) {
17
23
  return {
18
- type: "workspaces",
19
24
  id: String(row.id || ""),
20
- attributes: {
21
- slug: row.slug,
22
- name: row.name,
23
- isPersonal: row.isPersonal,
24
- avatarUrl: row.avatarUrl,
25
- createdAt: row.createdAt,
26
- updatedAt: row.updatedAt,
27
- deletedAt: row.deletedAt
28
- },
29
- relationships: {
30
- owner: {
31
- data: row.ownerUserId == null
32
- ? null
33
- : {
34
- type: "userProfiles",
35
- id: String(row.ownerUserId)
36
- }
37
- }
38
- }
25
+ slug: row.slug,
26
+ name: row.name,
27
+ ownerUserId: row.ownerUserId == null ? null : String(row.ownerUserId),
28
+ isPersonal: row.isPersonal,
29
+ avatarUrl: row.avatarUrl,
30
+ createdAt: row.createdAt,
31
+ updatedAt: row.updatedAt,
32
+ deletedAt: row.deletedAt
39
33
  };
40
34
  }
41
35
 
42
- function toWorkspaceMembershipResource(row = {}) {
36
+ function toWorkspaceMembershipRow(row = {}) {
43
37
  return {
44
- type: "workspaceMemberships",
45
38
  id: String(row.id || ""),
46
- attributes: {
47
- roleSid: row.roleSid,
48
- status: row.status,
49
- createdAt: row.createdAt,
50
- updatedAt: row.updatedAt
51
- },
52
- relationships: {
53
- user: {
54
- data: row?.user?.id == null ? null : { type: "userProfiles", id: String(row.user.id) }
55
- },
56
- workspace: {
57
- data: row?.workspace?.id == null ? null : { type: "workspaces", id: String(row.workspace.id) }
58
- }
59
- }
39
+ roleSid: row.roleSid,
40
+ status: row.status,
41
+ createdAt: row.createdAt,
42
+ updatedAt: row.updatedAt,
43
+ user: row?.user?.id == null ? null : { ...row.user, id: String(row.user.id) },
44
+ workspace: row?.workspace?.id == null ? null : toWorkspaceRow(row.workspace)
60
45
  };
61
46
  }
62
47
 
@@ -80,23 +65,22 @@ function createWorkspacesApiStub({
80
65
 
81
66
  if (Object.hasOwn(filters, "id")) {
82
67
  const row = rowsById.get(String(filters.id)) || null;
83
- return { data: row ? [toWorkspaceResource(row)] : [] };
68
+ return asCollectionDocument(row ? [toWorkspaceRow(row)] : []);
84
69
  }
85
70
 
86
71
  if (Object.hasOwn(filters, "slug")) {
87
72
  const row = rowsBySlug.get(String(filters.slug)) || null;
88
- return { data: row ? [toWorkspaceResource(row)] : [] };
73
+ return asCollectionDocument(row ? [toWorkspaceRow(row)] : []);
89
74
  }
90
75
 
91
76
  if (Object.hasOwn(filters, "owner") && Object.hasOwn(filters, "isPersonal")) {
92
77
  const rows = personalRowsByOwnerId.get(String(filters.owner)) || [];
93
- return { data: rows.map((row) => toWorkspaceResource(row)) };
78
+ return asCollectionDocument(rows.map((row) => toWorkspaceRow(row)));
94
79
  }
95
80
 
96
- return { data: [] };
81
+ return asCollectionDocument([]);
97
82
  },
98
83
  async post(payload) {
99
- assert.equal(payload?.simplified, false);
100
84
  const inputRecord = payload?.inputRecord?.data || {};
101
85
  state.postPayload = inputRecord;
102
86
  if (insertError) {
@@ -118,10 +102,9 @@ function createWorkspacesApiStub({
118
102
  if (row.slug) {
119
103
  rowsBySlug.set(row.slug, row);
120
104
  }
121
- return { data: toWorkspaceResource(row) };
105
+ return toWorkspaceRow(row);
122
106
  },
123
107
  async patch(payload) {
124
- assert.equal(payload?.simplified, false);
125
108
  const inputRecord = payload?.inputRecord?.data || {};
126
109
  state.patchPayload = inputRecord;
127
110
  const existing = rowsById.get(String(inputRecord.id)) || {
@@ -139,29 +122,21 @@ function createWorkspacesApiStub({
139
122
  if (updated.slug) {
140
123
  rowsBySlug.set(String(updated.slug), updated);
141
124
  }
142
- return { data: toWorkspaceResource(updated) };
125
+ return toWorkspaceRow(updated);
143
126
  }
144
127
  },
145
128
  workspaceMemberships: {
146
129
  async query({ queryParams }) {
147
130
  const filters = queryParams?.filters || {};
148
- const includeWorkspace = Array.isArray(queryParams?.include) && queryParams.include.includes("workspace");
149
131
  if (Object.hasOwn(filters, "user") && Object.hasOwn(filters, "status")) {
150
132
  const rows = membershipRows.filter((row) => (
151
133
  String(row?.user?.id || "") === String(filters.user) &&
152
134
  String(row?.status || "") === String(filters.status)
153
135
  ));
154
- return {
155
- data: rows.map((row) => toWorkspaceMembershipResource(row)),
156
- included: includeWorkspace
157
- ? rows
158
- .filter((row) => row?.workspace?.id != null)
159
- .map((row) => toWorkspaceResource(row.workspace))
160
- : []
161
- };
136
+ return asCollectionDocument(rows.map((row) => toWorkspaceMembershipRow(row)));
162
137
  }
163
138
 
164
- return { data: [] };
139
+ return asCollectionDocument([]);
165
140
  }
166
141
  }
167
142
  }