@jskit-ai/workspaces-core 0.1.163 → 0.1.165

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.
@@ -3,18 +3,6 @@ import test from "node:test";
3
3
  import { toIsoString } from "@jskit-ai/database-runtime/shared";
4
4
  import { createRepository } from "../src/server/common/repositories/workspaceMembershipsRepository.js";
5
5
 
6
- function createKnexStub() {
7
- const knex = Object.assign(() => {
8
- throw new Error("query execution not expected");
9
- }, {
10
- async transaction(work) {
11
- return work({ trxId: "trx-1" });
12
- }
13
- });
14
-
15
- return knex;
16
- }
17
-
18
6
  function asCollectionDocument(rows = []) {
19
7
  return {
20
8
  data: Array.isArray(rows) ? rows : []
@@ -55,7 +43,8 @@ function createWorkspaceMembershipsApiStub({
55
43
  const api = {
56
44
  resources: {
57
45
  workspaceMemberships: {
58
- async query({ queryParams }) {
46
+ async query({ queryParams, format }) {
47
+ assert.equal(format, "plain");
59
48
  state.queryCalls.push(queryParams || {});
60
49
  const filters = queryParams?.filters || {};
61
50
  const includeUser = Array.isArray(queryParams?.include) && queryParams.include.includes("user");
@@ -100,14 +89,18 @@ function createWorkspaceMembershipsApiStub({
100
89
  return asCollectionDocument([]);
101
90
  },
102
91
  async post(payload) {
103
- const inputRecord = payload?.inputRecord?.data || {};
104
- state.postPayload = inputRecord;
92
+ const data = payload?.data || {};
93
+ assert.equal(payload.format, "plain");
94
+ assert.equal(payload.returning, "full");
95
+ assert.equal(payload.inputRecord, undefined);
96
+ assert.equal(payload.document, undefined);
97
+ state.postPayload = payload;
105
98
  const row = rowById.get("1") || {
106
99
  id: "1",
107
- workspace: { id: String(inputRecord.relationships?.workspace?.data?.id || "") },
108
- user: { id: String(inputRecord.relationships?.user?.data?.id || "") },
109
- roleSid: String(inputRecord.attributes?.roleSid || ""),
110
- status: String(inputRecord.attributes?.status || ""),
100
+ workspace: { id: String(data.workspace || "") },
101
+ user: { id: String(data.user || "") },
102
+ roleSid: String(data.roleSid || ""),
103
+ status: String(data.status || ""),
111
104
  createdAt: "2026-03-09 00:26:35.710",
112
105
  updatedAt: "2026-03-09 00:26:35.710"
113
106
  };
@@ -116,13 +109,17 @@ function createWorkspaceMembershipsApiStub({
116
109
  return toWorkspaceMembershipRow(row);
117
110
  },
118
111
  async patch(payload) {
119
- const inputRecord = payload?.inputRecord?.data || {};
120
- state.patchPayload = inputRecord;
121
- const existing = rowById.get(String(inputRecord.id));
112
+ const data = payload?.data || {};
113
+ assert.equal(payload.format, "plain");
114
+ assert.equal(payload.returning, "full");
115
+ assert.equal(payload.inputRecord, undefined);
116
+ assert.equal(payload.document, undefined);
117
+ state.patchPayload = payload;
118
+ const existing = rowById.get(String(payload.id));
122
119
  const updated = {
123
120
  ...(existing || {}),
124
- ...(inputRecord.attributes || {}),
125
- id: String(inputRecord.id),
121
+ ...data,
122
+ id: String(payload.id),
126
123
  workspace: existing?.workspace || { id: "" },
127
124
  user: existing?.user || { id: "" }
128
125
  };
@@ -150,7 +147,7 @@ test("workspaceMembershipsRepository.findByWorkspaceIdAndUserId normalizes canon
150
147
  const { api } = createWorkspaceMembershipsApiStub({
151
148
  rowByComposite: new Map([["7:9", membershipRow]])
152
149
  });
153
- const repository = createRepository({ api, knex: createKnexStub() });
150
+ const repository = createRepository({ api });
154
151
 
155
152
  const membership = await repository.findByWorkspaceIdAndUserId("7", "9");
156
153
 
@@ -185,13 +182,13 @@ test("workspaceMembershipsRepository.ensureOwnerMembership upgrades an existing
185
182
  rowById: new Map([["11", refreshedRow]]),
186
183
  rowByComposite: new Map([["7:9", existingRow]])
187
184
  });
188
- const repository = createRepository({ api, knex: createKnexStub() });
185
+ const repository = createRepository({ api });
189
186
 
190
187
  const membership = await repository.ensureOwnerMembership("7", "9");
191
188
 
192
- assert.equal(state.patchPayload.attributes?.roleSid, "owner");
193
- assert.equal(state.patchPayload.attributes?.status, "active");
194
- assert.equal(typeof state.patchPayload.attributes?.updatedAt, "string");
189
+ assert.equal(state.patchPayload.data.roleSid, "owner");
190
+ assert.equal(state.patchPayload.data.status, "active");
191
+ assert.equal(typeof state.patchPayload.data.updatedAt, "string");
195
192
  assert.deepEqual(membership, {
196
193
  id: "11",
197
194
  workspaceId: "7",
@@ -199,7 +196,7 @@ test("workspaceMembershipsRepository.ensureOwnerMembership upgrades an existing
199
196
  roleSid: "owner",
200
197
  status: "active",
201
198
  createdAt: toIsoString("2026-03-09 00:26:35.710"),
202
- updatedAt: toIsoString(state.patchPayload.attributes.updatedAt)
199
+ updatedAt: toIsoString(state.patchPayload.data.updatedAt)
203
200
  });
204
201
  });
205
202
 
@@ -217,17 +214,17 @@ test("workspaceMembershipsRepository.upsertMembership creates normalized members
217
214
  rowById: new Map([["1", createdRow]]),
218
215
  rowByComposite: new Map()
219
216
  });
220
- const repository = createRepository({ api, knex: createKnexStub() });
217
+ const repository = createRepository({ api });
221
218
 
222
219
  await repository.upsertMembership("7", "9", {
223
220
  roleSid: "ADMIN",
224
221
  status: "ACTIVE"
225
222
  });
226
223
 
227
- assert.equal(state.postPayload.relationships?.workspace?.data?.id, "7");
228
- assert.equal(state.postPayload.relationships?.user?.data?.id, "9");
229
- assert.equal(state.postPayload.attributes?.roleSid, "admin");
230
- assert.equal(state.postPayload.attributes?.status, "active");
224
+ assert.equal(state.postPayload.data.workspace, "7");
225
+ assert.equal(state.postPayload.data.user, "9");
226
+ assert.equal(state.postPayload.data.roleSid, "admin");
227
+ assert.equal(state.postPayload.data.status, "active");
231
228
  });
232
229
 
233
230
  test("workspaceMembershipsRepository.listActiveByWorkspaceId keeps summary rows separate from the canonical membership resource", async () => {
@@ -244,7 +241,7 @@ test("workspaceMembershipsRepository.listActiveByWorkspaceId keeps summary rows
244
241
  }
245
242
  ]
246
243
  });
247
- const repository = createRepository({ api, knex: createKnexStub() });
244
+ const repository = createRepository({ api });
248
245
 
249
246
  const members = await repository.listActiveByWorkspaceId("7");
250
247
 
@@ -272,7 +269,7 @@ test("workspaceMembershipsRepository.listActiveWorkspaceIdsByUserId returns norm
272
269
  const { api, state } = createWorkspaceMembershipsApiStub({
273
270
  rowByComposite: new Map([["7:9", membershipRow]])
274
271
  });
275
- const repository = createRepository({ api, knex: createKnexStub() });
272
+ const repository = createRepository({ api });
276
273
 
277
274
  const workspaceIds = await repository.listActiveWorkspaceIdsByUserId("9");
278
275
 
@@ -4,18 +4,6 @@ import { toIsoString } from "@jskit-ai/database-runtime/shared";
4
4
  import { resolveWorkspaceThemePalettes } from "@jskit-ai/workspaces-core/shared/settings";
5
5
  import { createRepository } from "../src/server/workspaceSettings/workspaceSettingsRepository.js";
6
6
 
7
- function createKnexStub() {
8
- const knex = Object.assign(() => {
9
- throw new Error("query execution not expected");
10
- }, {
11
- async transaction(work) {
12
- return work({ trxId: "trx-1" });
13
- }
14
- });
15
-
16
- return knex;
17
- }
18
-
19
7
  function normalizeWorkspaceColor(value) {
20
8
  return typeof value === "string" ? value.toUpperCase() : value;
21
9
  }
@@ -54,7 +42,8 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
54
42
  const api = {
55
43
  resources: {
56
44
  workspaceSettings: {
57
- async query({ queryParams }) {
45
+ async query({ queryParams, format }) {
46
+ assert.equal(format, "plain");
58
47
  const id = String(queryParams?.filters?.id || "");
59
48
  if (!state.row || (id && String(state.row.id) !== id)) {
60
49
  return asCollectionDocument([]);
@@ -66,20 +55,23 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
66
55
  }]);
67
56
  },
68
57
  async post(payload) {
69
- const inputRecord = payload?.inputRecord?.data || {};
70
- const attributes = inputRecord.attributes || {};
71
- state.postPayload = inputRecord;
58
+ const data = payload?.data || {};
59
+ assert.equal(payload.format, "plain");
60
+ assert.equal(payload.returning, "full");
61
+ assert.equal(payload.inputRecord, undefined);
62
+ assert.equal(payload.document, undefined);
63
+ state.postPayload = payload;
72
64
  state.row = {
73
- id: String(inputRecord.id),
74
- lightPrimaryColor: normalizeWorkspaceColor(attributes.lightPrimaryColor ?? DEFAULT_WORKSPACE_THEME.light.color),
75
- lightSecondaryColor: normalizeWorkspaceColor(attributes.lightSecondaryColor ?? DEFAULT_WORKSPACE_THEME.light.secondaryColor),
76
- lightSurfaceColor: normalizeWorkspaceColor(attributes.lightSurfaceColor ?? DEFAULT_WORKSPACE_THEME.light.surfaceColor),
77
- lightSurfaceVariantColor: normalizeWorkspaceColor(attributes.lightSurfaceVariantColor ?? DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor),
78
- darkPrimaryColor: normalizeWorkspaceColor(attributes.darkPrimaryColor ?? DEFAULT_WORKSPACE_THEME.dark.color),
79
- darkSecondaryColor: normalizeWorkspaceColor(attributes.darkSecondaryColor ?? DEFAULT_WORKSPACE_THEME.dark.secondaryColor),
80
- darkSurfaceColor: normalizeWorkspaceColor(attributes.darkSurfaceColor ?? DEFAULT_WORKSPACE_THEME.dark.surfaceColor),
81
- darkSurfaceVariantColor: normalizeWorkspaceColor(attributes.darkSurfaceVariantColor ?? DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor),
82
- invitesEnabled: attributes.invitesEnabled ?? true,
65
+ id: String(data.id),
66
+ lightPrimaryColor: normalizeWorkspaceColor(data.lightPrimaryColor ?? DEFAULT_WORKSPACE_THEME.light.color),
67
+ lightSecondaryColor: normalizeWorkspaceColor(data.lightSecondaryColor ?? DEFAULT_WORKSPACE_THEME.light.secondaryColor),
68
+ lightSurfaceColor: normalizeWorkspaceColor(data.lightSurfaceColor ?? DEFAULT_WORKSPACE_THEME.light.surfaceColor),
69
+ lightSurfaceVariantColor: normalizeWorkspaceColor(data.lightSurfaceVariantColor ?? DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor),
70
+ darkPrimaryColor: normalizeWorkspaceColor(data.darkPrimaryColor ?? DEFAULT_WORKSPACE_THEME.dark.color),
71
+ darkSecondaryColor: normalizeWorkspaceColor(data.darkSecondaryColor ?? DEFAULT_WORKSPACE_THEME.dark.secondaryColor),
72
+ darkSurfaceColor: normalizeWorkspaceColor(data.darkSurfaceColor ?? DEFAULT_WORKSPACE_THEME.dark.surfaceColor),
73
+ darkSurfaceVariantColor: normalizeWorkspaceColor(data.darkSurfaceVariantColor ?? DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor),
74
+ invitesEnabled: data.invitesEnabled ?? true,
83
75
  createdAt: toIsoString("2026-03-10 00:00:00.000"),
84
76
  updatedAt: toIsoString("2026-03-10 00:00:00.000")
85
77
  };
@@ -89,21 +81,24 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
89
81
  };
90
82
  },
91
83
  async patch(payload) {
92
- const inputRecord = payload?.inputRecord?.data || {};
93
- const attributes = inputRecord.attributes || {};
94
- state.patchPayload = inputRecord;
84
+ const data = payload?.data || {};
85
+ assert.equal(payload.format, "plain");
86
+ assert.equal(payload.returning, "full");
87
+ assert.equal(payload.inputRecord, undefined);
88
+ assert.equal(payload.document, undefined);
89
+ state.patchPayload = payload;
95
90
  state.row = {
96
91
  ...state.row,
97
- ...attributes,
98
- ...(Object.hasOwn(attributes, "lightPrimaryColor") ? { lightPrimaryColor: normalizeWorkspaceColor(attributes.lightPrimaryColor) } : {}),
99
- ...(Object.hasOwn(attributes, "lightSecondaryColor") ? { lightSecondaryColor: normalizeWorkspaceColor(attributes.lightSecondaryColor) } : {}),
100
- ...(Object.hasOwn(attributes, "lightSurfaceColor") ? { lightSurfaceColor: normalizeWorkspaceColor(attributes.lightSurfaceColor) } : {}),
101
- ...(Object.hasOwn(attributes, "lightSurfaceVariantColor") ? { lightSurfaceVariantColor: normalizeWorkspaceColor(attributes.lightSurfaceVariantColor) } : {}),
102
- ...(Object.hasOwn(attributes, "darkPrimaryColor") ? { darkPrimaryColor: normalizeWorkspaceColor(attributes.darkPrimaryColor) } : {}),
103
- ...(Object.hasOwn(attributes, "darkSecondaryColor") ? { darkSecondaryColor: normalizeWorkspaceColor(attributes.darkSecondaryColor) } : {}),
104
- ...(Object.hasOwn(attributes, "darkSurfaceColor") ? { darkSurfaceColor: normalizeWorkspaceColor(attributes.darkSurfaceColor) } : {}),
105
- ...(Object.hasOwn(attributes, "darkSurfaceVariantColor") ? { darkSurfaceVariantColor: normalizeWorkspaceColor(attributes.darkSurfaceVariantColor) } : {}),
106
- id: String(inputRecord.id || state.row?.id || "")
92
+ ...data,
93
+ ...(Object.hasOwn(data, "lightPrimaryColor") ? { lightPrimaryColor: normalizeWorkspaceColor(data.lightPrimaryColor) } : {}),
94
+ ...(Object.hasOwn(data, "lightSecondaryColor") ? { lightSecondaryColor: normalizeWorkspaceColor(data.lightSecondaryColor) } : {}),
95
+ ...(Object.hasOwn(data, "lightSurfaceColor") ? { lightSurfaceColor: normalizeWorkspaceColor(data.lightSurfaceColor) } : {}),
96
+ ...(Object.hasOwn(data, "lightSurfaceVariantColor") ? { lightSurfaceVariantColor: normalizeWorkspaceColor(data.lightSurfaceVariantColor) } : {}),
97
+ ...(Object.hasOwn(data, "darkPrimaryColor") ? { darkPrimaryColor: normalizeWorkspaceColor(data.darkPrimaryColor) } : {}),
98
+ ...(Object.hasOwn(data, "darkSecondaryColor") ? { darkSecondaryColor: normalizeWorkspaceColor(data.darkSecondaryColor) } : {}),
99
+ ...(Object.hasOwn(data, "darkSurfaceColor") ? { darkSurfaceColor: normalizeWorkspaceColor(data.darkSurfaceColor) } : {}),
100
+ ...(Object.hasOwn(data, "darkSurfaceVariantColor") ? { darkSurfaceVariantColor: normalizeWorkspaceColor(data.darkSurfaceVariantColor) } : {}),
101
+ id: String(payload.id || state.row?.id || "")
107
102
  };
108
103
  return {
109
104
  ...state.row,
@@ -120,8 +115,7 @@ function createWorkspaceSettingsApiStub(rowOverrides = {}) {
120
115
  test("workspaceSettingsRepository.findByWorkspaceId returns the canonical workspace-settings row", async () => {
121
116
  const { api, DEFAULT_WORKSPACE_THEME, STUB_CREATED_AT } = createWorkspaceSettingsApiStub();
122
117
  const repository = createRepository({
123
- api,
124
- knex: createKnexStub()
118
+ api
125
119
  });
126
120
 
127
121
  const record = await repository.findByWorkspaceId("1");
@@ -145,15 +139,14 @@ test("workspaceSettingsRepository.findByWorkspaceId returns the canonical worksp
145
139
  test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates invitesEnabled only", async () => {
146
140
  const { api, state } = createWorkspaceSettingsApiStub();
147
141
  const repository = createRepository({
148
- api,
149
- knex: createKnexStub()
142
+ api
150
143
  });
151
144
 
152
145
  const updated = await repository.updateSettingsByWorkspaceId("1", {
153
146
  invitesEnabled: false
154
147
  });
155
148
 
156
- assert.equal(state.patchPayload.attributes?.invitesEnabled, false);
149
+ assert.equal(state.patchPayload.data.invitesEnabled, false);
157
150
  assert.equal(updated.invitesEnabled, false);
158
151
  });
159
152
 
@@ -161,22 +154,21 @@ test("workspaceSettingsRepository.ensureForWorkspaceId delegates defaults to the
161
154
  const { api, state, DEFAULT_WORKSPACE_THEME } = createWorkspaceSettingsApiStub();
162
155
  state.row = null;
163
156
  const repository = createRepository({
164
- api,
165
- knex: createKnexStub()
157
+ api
166
158
  });
167
159
 
168
160
  const record = await repository.ensureForWorkspaceId("5");
169
161
 
170
- assert.equal(state.postPayload.id, "5");
171
- assert.equal(state.postPayload.attributes?.lightPrimaryColor, DEFAULT_WORKSPACE_THEME.light.color);
172
- assert.equal(state.postPayload.attributes?.lightSecondaryColor, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
173
- assert.equal(state.postPayload.attributes?.lightSurfaceColor, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
174
- assert.equal(state.postPayload.attributes?.lightSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor);
175
- assert.equal(state.postPayload.attributes?.darkPrimaryColor, DEFAULT_WORKSPACE_THEME.dark.color);
176
- assert.equal(state.postPayload.attributes?.darkSecondaryColor, DEFAULT_WORKSPACE_THEME.dark.secondaryColor);
177
- assert.equal(state.postPayload.attributes?.darkSurfaceColor, DEFAULT_WORKSPACE_THEME.dark.surfaceColor);
178
- assert.equal(state.postPayload.attributes?.darkSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor);
179
- assert.equal(state.postPayload.attributes?.invitesEnabled, true);
162
+ assert.equal(state.postPayload.data.id, "5");
163
+ assert.equal(state.postPayload.data.lightPrimaryColor, DEFAULT_WORKSPACE_THEME.light.color);
164
+ assert.equal(state.postPayload.data.lightSecondaryColor, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
165
+ assert.equal(state.postPayload.data.lightSurfaceColor, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
166
+ assert.equal(state.postPayload.data.lightSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.light.surfaceVariantColor);
167
+ assert.equal(state.postPayload.data.darkPrimaryColor, DEFAULT_WORKSPACE_THEME.dark.color);
168
+ assert.equal(state.postPayload.data.darkSecondaryColor, DEFAULT_WORKSPACE_THEME.dark.secondaryColor);
169
+ assert.equal(state.postPayload.data.darkSurfaceColor, DEFAULT_WORKSPACE_THEME.dark.surfaceColor);
170
+ assert.equal(state.postPayload.data.darkSurfaceVariantColor, DEFAULT_WORKSPACE_THEME.dark.surfaceVariantColor);
171
+ assert.equal(state.postPayload.data.invitesEnabled, true);
180
172
  assert.equal(record.lightPrimaryColor, DEFAULT_WORKSPACE_THEME.light.color);
181
173
  assert.equal(record.lightSecondaryColor, DEFAULT_WORKSPACE_THEME.light.secondaryColor);
182
174
  assert.equal(record.lightSurfaceColor, DEFAULT_WORKSPACE_THEME.light.surfaceColor);
@@ -192,15 +184,14 @@ test("workspaceSettingsRepository.ensureForWorkspaceId delegates defaults to the
192
184
  test("workspaceSettingsRepository.updateSettingsByWorkspaceId updates workspace settings fields", async () => {
193
185
  const { api, state } = createWorkspaceSettingsApiStub();
194
186
  const repository = createRepository({
195
- api,
196
- knex: createKnexStub()
187
+ api
197
188
  });
198
189
 
199
190
  const updated = await repository.updateSettingsByWorkspaceId("1", {
200
191
  lightPrimaryColor: "#123abc"
201
192
  });
202
193
 
203
- assert.equal(state.patchPayload.attributes?.lightPrimaryColor, "#123abc");
194
+ assert.equal(state.patchPayload.data.lightPrimaryColor, "#123abc");
204
195
  assert.equal(updated.lightPrimaryColor, "#123ABC");
205
196
  });
206
197
 
@@ -208,8 +199,7 @@ test("workspaceSettingsRepository can be constructed without validating app conf
208
199
  const { api } = createWorkspaceSettingsApiStub();
209
200
 
210
201
  const repository = createRepository({
211
- api,
212
- knex: createKnexStub()
202
+ api
213
203
  });
214
204
 
215
205
  assert.ok(repository);
@@ -3,16 +3,6 @@ import test from "node:test";
3
3
  import { toIsoString } from "@jskit-ai/database-runtime/shared";
4
4
  import { createRepository } from "../src/server/common/repositories/workspacesRepository.js";
5
5
 
6
- function createKnexStub() {
7
- return Object.assign(() => {
8
- throw new Error("query execution not expected");
9
- }, {
10
- async transaction(work) {
11
- return work({ trxId: "trx-1" });
12
- }
13
- });
14
- }
15
-
16
6
  function asCollectionDocument(rows = []) {
17
7
  return {
18
8
  data: Array.isArray(rows) ? rows : []
@@ -24,7 +14,7 @@ function toWorkspaceRow(row = {}) {
24
14
  id: String(row.id || ""),
25
15
  slug: row.slug,
26
16
  name: row.name,
27
- ownerUserId: row.ownerUserId == null ? null : String(row.ownerUserId),
17
+ owner: row.ownerUserId == null ? null : { id: String(row.ownerUserId) },
28
18
  isPersonal: row.isPersonal,
29
19
  avatarUrl: row.avatarUrl,
30
20
  createdAt: row.createdAt,
@@ -60,7 +50,8 @@ function createWorkspacesApiStub({
60
50
  const api = {
61
51
  resources: {
62
52
  workspaces: {
63
- async query({ queryParams }) {
53
+ async query({ queryParams, format }) {
54
+ assert.equal(format, "plain");
64
55
  const filters = queryParams?.filters || {};
65
56
 
66
57
  if (Object.hasOwn(filters, "id")) {
@@ -81,21 +72,25 @@ function createWorkspacesApiStub({
81
72
  return asCollectionDocument([]);
82
73
  },
83
74
  async post(payload) {
84
- const inputRecord = payload?.inputRecord?.data || {};
85
- state.postPayload = inputRecord;
75
+ const data = payload?.data || {};
76
+ assert.equal(payload.format, "plain");
77
+ assert.equal(payload.returning, "full");
78
+ assert.equal(payload.inputRecord, undefined);
79
+ assert.equal(payload.document, undefined);
80
+ state.postPayload = payload;
86
81
  if (insertError) {
87
82
  throw insertError;
88
83
  }
89
84
 
90
85
  const row = {
91
86
  id: "1",
92
- slug: String(inputRecord.attributes?.slug || ""),
93
- name: String(inputRecord.attributes?.name || ""),
94
- ownerUserId: String(inputRecord.relationships?.owner?.data?.id || ""),
95
- isPersonal: Boolean(inputRecord.attributes?.isPersonal),
96
- avatarUrl: String(inputRecord.attributes?.avatarUrl || ""),
97
- createdAt: inputRecord.attributes?.createdAt,
98
- updatedAt: inputRecord.attributes?.updatedAt,
87
+ slug: String(data.slug || ""),
88
+ name: String(data.name || ""),
89
+ ownerUserId: String(data.owner || ""),
90
+ isPersonal: Boolean(data.isPersonal),
91
+ avatarUrl: String(data.avatarUrl || ""),
92
+ createdAt: data.createdAt,
93
+ updatedAt: data.updatedAt,
99
94
  deletedAt: null
100
95
  };
101
96
  rowsById.set(row.id, row);
@@ -105,18 +100,22 @@ function createWorkspacesApiStub({
105
100
  return toWorkspaceRow(row);
106
101
  },
107
102
  async patch(payload) {
108
- const inputRecord = payload?.inputRecord?.data || {};
109
- state.patchPayload = inputRecord;
110
- const existing = rowsById.get(String(inputRecord.id)) || {
111
- id: String(inputRecord.id)
103
+ const data = payload?.data || {};
104
+ assert.equal(payload.format, "plain");
105
+ assert.equal(payload.returning, "full");
106
+ assert.equal(payload.inputRecord, undefined);
107
+ assert.equal(payload.document, undefined);
108
+ state.patchPayload = payload;
109
+ const existing = rowsById.get(String(payload.id)) || {
110
+ id: String(payload.id)
112
111
  };
113
112
  const updated = {
114
113
  ...existing,
115
- ...(inputRecord.attributes || {}),
116
- ...(inputRecord.relationships?.owner?.data?.id
117
- ? { ownerUserId: String(inputRecord.relationships.owner.data.id) }
114
+ ...data,
115
+ ...(data.owner
116
+ ? { ownerUserId: String(data.owner) }
118
117
  : {}),
119
- id: String(inputRecord.id)
118
+ id: String(payload.id)
120
119
  };
121
120
  rowsById.set(updated.id, updated);
122
121
  if (updated.slug) {
@@ -126,7 +125,8 @@ function createWorkspacesApiStub({
126
125
  }
127
126
  },
128
127
  workspaceMemberships: {
129
- async query({ queryParams }) {
128
+ async query({ queryParams, format }) {
129
+ assert.equal(format, "plain");
130
130
  const filters = queryParams?.filters || {};
131
131
  if (Object.hasOwn(filters, "user") && Object.hasOwn(filters, "status")) {
132
132
  const rows = membershipRows.filter((row) => (
@@ -161,7 +161,7 @@ test("workspacesRepository.findById reads a canonical workspace row through json
161
161
  }]
162
162
  ])
163
163
  });
164
- const repository = createRepository({ api, knex: createKnexStub() });
164
+ const repository = createRepository({ api });
165
165
 
166
166
  const workspace = await repository.findById("7");
167
167
 
@@ -207,7 +207,7 @@ test("workspacesRepository.findPersonalByOwnerUserId returns the first personal
207
207
  ]]
208
208
  ])
209
209
  });
210
- const repository = createRepository({ api, knex: createKnexStub() });
210
+ const repository = createRepository({ api });
211
211
 
212
212
  const workspace = await repository.findPersonalByOwnerUserId("9");
213
213
 
@@ -217,7 +217,7 @@ test("workspacesRepository.findPersonalByOwnerUserId returns the first personal
217
217
 
218
218
  test("workspacesRepository.insert writes canonical fields through json-rest-api", async () => {
219
219
  const { api, state } = createWorkspacesApiStub();
220
- const repository = createRepository({ api, knex: createKnexStub() });
220
+ const repository = createRepository({ api });
221
221
 
222
222
  const inserted = await repository.insert({
223
223
  slug: "TonyMobily3",
@@ -227,13 +227,13 @@ test("workspacesRepository.insert writes canonical fields through json-rest-api"
227
227
  isPersonal: false
228
228
  });
229
229
 
230
- assert.equal(state.postPayload.relationships?.owner?.data?.id, "9");
231
- assert.equal(state.postPayload.attributes?.slug, "TonyMobily3");
232
- assert.equal(state.postPayload.attributes?.name, "TonyMobily3");
233
- assert.equal(state.postPayload.attributes?.isPersonal, false);
234
- assert.equal(state.postPayload.attributes?.avatarUrl, "");
235
- assert.equal(typeof state.postPayload.attributes?.createdAt, "string");
236
- assert.equal(state.postPayload.attributes?.updatedAt, state.postPayload.attributes?.createdAt);
230
+ assert.equal(state.postPayload.data.owner, "9");
231
+ assert.equal(state.postPayload.data.slug, "TonyMobily3");
232
+ assert.equal(state.postPayload.data.name, "TonyMobily3");
233
+ assert.equal(state.postPayload.data.isPersonal, false);
234
+ assert.equal(state.postPayload.data.avatarUrl, "");
235
+ assert.equal(typeof state.postPayload.data.createdAt, "string");
236
+ assert.equal(state.postPayload.data.updatedAt, state.postPayload.data.createdAt);
237
237
  assert.equal(inserted.id, "1");
238
238
  assert.equal(inserted.ownerUserId, "9");
239
239
  });
@@ -252,9 +252,9 @@ test("workspacesRepository.insert falls back to slug lookup on duplicate slug",
252
252
  };
253
253
  const { api } = createWorkspacesApiStub({
254
254
  rowsBySlug: new Map([["shared-workspace", existingRow]]),
255
- insertError: { code: "ER_DUP_ENTRY" }
255
+ insertError: { code: "REST_API_WRITE", transactionOutcome: "rolledBack", cause: { code: "ER_DUP_ENTRY" } }
256
256
  });
257
- const repository = createRepository({ api, knex: createKnexStub() });
257
+ const repository = createRepository({ api });
258
258
 
259
259
  const inserted = await repository.insert({
260
260
  slug: "shared-workspace",
@@ -282,15 +282,15 @@ test("workspacesRepository.updateById patches canonical fields and updatedAt", a
282
282
  }]
283
283
  ])
284
284
  });
285
- const repository = createRepository({ api, knex: createKnexStub() });
285
+ const repository = createRepository({ api });
286
286
 
287
287
  await repository.updateById("7", {
288
288
  name: "TonyMobily 4"
289
289
  });
290
290
 
291
291
  assert.equal(state.patchPayload.id, "7");
292
- assert.equal(state.patchPayload.attributes?.name, "TonyMobily 4");
293
- assert.equal(typeof state.patchPayload.attributes?.updatedAt, "string");
292
+ assert.equal(state.patchPayload.data.name, "TonyMobily 4");
293
+ assert.equal(typeof state.patchPayload.data.updatedAt, "string");
294
294
  });
295
295
 
296
296
  test("workspacesRepository.listForUserId keeps membership fields outside the canonical workspace row", async () => {
@@ -346,7 +346,7 @@ test("workspacesRepository.listForUserId keeps membership fields outside the can
346
346
  }
347
347
  ]
348
348
  });
349
- const repository = createRepository({ api, knex: createKnexStub() });
349
+ const repository = createRepository({ api });
350
350
 
351
351
  const workspaces = await repository.listForUserId("9");
352
352