@ai-matrx/records 0.99.32 → 0.99.34

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 (62) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/{client-CrwedBYU.d.ts → client-CSfkP7Xf.d.ts} +5 -74
  3. package/dist/{client-D1EwyWfh.d.cts → client-jKf1Z-kp.d.cts} +5 -74
  4. package/dist/core/index.cjs +149 -105
  5. package/dist/core/index.cjs.map +1 -1
  6. package/dist/core/index.d.cts +9 -331
  7. package/dist/core/index.d.ts +9 -331
  8. package/dist/core/index.js +149 -105
  9. package/dist/core/index.js.map +1 -1
  10. package/dist/data/index.cjs +280 -236
  11. package/dist/data/index.cjs.map +1 -1
  12. package/dist/data/index.d.cts +3 -2
  13. package/dist/data/index.d.ts +3 -2
  14. package/dist/data/index.js +280 -236
  15. package/dist/data/index.js.map +1 -1
  16. package/dist/{declareTable-CC5rTTIA.d.ts → declareTable-0emxEewn.d.ts} +1 -1
  17. package/dist/{declareTable-BIIt0Wqt.d.cts → declareTable-800bwUn3.d.cts} +1 -1
  18. package/dist/door-call/index.cjs +1287 -0
  19. package/dist/door-call/index.cjs.map +1 -0
  20. package/dist/door-call/index.d.cts +20 -0
  21. package/dist/door-call/index.d.ts +20 -0
  22. package/dist/door-call/index.js +1264 -0
  23. package/dist/door-call/index.js.map +1 -0
  24. package/dist/{doors-D1yAs0a0.d.cts → doors-BgjRUdxw.d.cts} +13 -1
  25. package/dist/{doors-D2z3kH2i.d.ts → doors-D7_jEKtg.d.ts} +13 -1
  26. package/dist/index.d.cts +5 -4
  27. package/dist/index.d.ts +5 -4
  28. package/dist/{objectOrganization-DazBoDAq.d.cts → objectOrganization-B5YFGVUB.d.cts} +1 -1
  29. package/dist/{objectOrganization-D1ox3gUx.d.ts → objectOrganization-DozoVIxS.d.ts} +1 -1
  30. package/dist/pickListDoors-C-_eAEGL.d.cts +135 -0
  31. package/dist/pickListDoors-DgWVnNRI.d.ts +135 -0
  32. package/dist/questions/index.d.cts +3 -2
  33. package/dist/questions/index.d.ts +3 -2
  34. package/dist/react/index.cjs +363 -319
  35. package/dist/react/index.cjs.map +1 -1
  36. package/dist/react/index.d.cts +37 -22
  37. package/dist/react/index.d.ts +37 -22
  38. package/dist/react/index.js +363 -319
  39. package/dist/react/index.js.map +1 -1
  40. package/dist/scopes/index.cjs +7 -0
  41. package/dist/scopes/index.cjs.map +1 -1
  42. package/dist/scopes/index.d.cts +2 -2
  43. package/dist/scopes/index.d.ts +2 -2
  44. package/dist/scopes/index.js +7 -0
  45. package/dist/scopes/index.js.map +1 -1
  46. package/dist/setup/index.cjs +289 -245
  47. package/dist/setup/index.cjs.map +1 -1
  48. package/dist/setup/index.d.cts +4 -3
  49. package/dist/setup/index.d.ts +4 -3
  50. package/dist/setup/index.js +289 -245
  51. package/dist/setup/index.js.map +1 -1
  52. package/dist/table-logic-BPquabNN.d.ts +328 -0
  53. package/dist/table-logic-CTh6lwaq.d.cts +328 -0
  54. package/dist/typed-table/index.cjs +280 -236
  55. package/dist/typed-table/index.cjs.map +1 -1
  56. package/dist/typed-table/index.d.cts +4 -3
  57. package/dist/typed-table/index.d.ts +4 -3
  58. package/dist/typed-table/index.js +280 -236
  59. package/dist/typed-table/index.js.map +1 -1
  60. package/dist/views/index.d.cts +3 -2
  61. package/dist/views/index.d.ts +3 -2
  62. package/package.json +13 -3
@@ -1,7 +1,7 @@
1
1
  import { RealtimeManager } from '@ai-matrx/data/realtime';
2
- import { R as RecordsClient } from '../client-D1EwyWfh.cjs';
2
+ import { R as RecordsClient } from '../client-jKf1Z-kp.cjs';
3
3
  import { C as CreateEntityDataPortOptions, E as EntityDataPort } from '../port-O-UdH1HS.cjs';
4
- import { R as RecordOrganizationPort, O as ObjectOrganizationAnswer } from '../objectOrganization-DazBoDAq.cjs';
4
+ import { R as RecordOrganizationPort, a as ObjectOrganizationAnswer } from '../objectOrganization-B5YFGVUB.cjs';
5
5
  import { a as RecordsConfig, b as RowAgentPort, c as RecordsErrorSink, d as RecordsDataSource, e as RecordsChangeSink, f as RowAgentTarget } from '../ports-alv3bgKY.cjs';
6
6
  import { U as Uuid, R as RecordsResult } from '../record-CTgSgWe3.cjs';
7
7
  import { RecordSearchRequest, RecordSearchHit, listStoreRecordCandidates } from '../search/index.cjs';
@@ -9,7 +9,8 @@ import '../subscription-CuaGi3lC.cjs';
9
9
  import '../rule-49jO7lN-.cjs';
10
10
  import '../relation-BjjjXyqn.cjs';
11
11
  import '../field-B8loYt-A.cjs';
12
- import '../doors-D1yAs0a0.cjs';
12
+ import '../doors-BgjRUdxw.cjs';
13
+ import '../pickListDoors-C-_eAEGL.cjs';
13
14
  import '../portal-L_mN8l9P.cjs';
14
15
  import '../table-kind/index.cjs';
15
16
  import '../types-B54BeQzf.cjs';
@@ -1,7 +1,7 @@
1
1
  import { RealtimeManager } from '@ai-matrx/data/realtime';
2
- import { R as RecordsClient } from '../client-CrwedBYU.js';
2
+ import { R as RecordsClient } from '../client-CSfkP7Xf.js';
3
3
  import { C as CreateEntityDataPortOptions, E as EntityDataPort } from '../port-D6wepPvr.js';
4
- import { R as RecordOrganizationPort, O as ObjectOrganizationAnswer } from '../objectOrganization-D1ox3gUx.js';
4
+ import { R as RecordOrganizationPort, a as ObjectOrganizationAnswer } from '../objectOrganization-DozoVIxS.js';
5
5
  import { a as RecordsConfig, b as RowAgentPort, c as RecordsErrorSink, d as RecordsDataSource, e as RecordsChangeSink, f as RowAgentTarget } from '../ports-CmmvR8OI.js';
6
6
  import { U as Uuid, R as RecordsResult } from '../record-CTgSgWe3.js';
7
7
  import { RecordSearchRequest, RecordSearchHit, listStoreRecordCandidates } from '../search/index.js';
@@ -9,7 +9,8 @@ import '../subscription-Bp1RSb6p.js';
9
9
  import '../rule-DzNj0QvN.js';
10
10
  import '../relation-T4biacnz.js';
11
11
  import '../field-DaE90BZ7.js';
12
- import '../doors-D2z3kH2i.js';
12
+ import '../doors-D7_jEKtg.js';
13
+ import '../pickListDoors-DgWVnNRI.js';
13
14
  import '../portal-CAssJHRZ.js';
14
15
  import '../table-kind/index.js';
15
16
  import '../types-bN7dG2ji.js';
@@ -54,137 +54,6 @@ function isWritingDoor(door) {
54
54
  return /(_declare|_set(_|$)|_update|_write|_delete|_restore|_archive|_upsert|_reparent|_change|_duplicate|_move|_decide|_run$|_submit|_publish|_import_|_start$|_complete|_sign$|_add$|_retire|_propose|_promote|_land$|_pin$|_mute|_snooze|_unsnooze|_clear|_unclear|_revoke|_issue|_bind|_unbind|_apply|_backfill|_sync$|_decorate|_designate|_ensure|^migrate_|^set_table_|^home_add|^capture_|^claim_|^record_stage|^anon_|^io_import_|^io_comment_resolve|^enrich_(declare|land|pin)|^field_(declare|duplicate|propose|restore|retire|update)|^table_(declare|ensure|from_example|move|sync)|^value_restore|^relation_own)/.test(door);
55
55
  }
56
56
 
57
- // src/core/recordChanges.ts
58
- import { globalSlot } from "@ai-matrx/kit/global-slot";
59
- var listeners = globalSlot("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
60
- function announceRecordChanged(recordId) {
61
- for (const listener of [...listeners]) {
62
- try {
63
- listener(recordId);
64
- } catch (thrown) {
65
- console.error("[@ai-matrx/records] a record-change listener threw", thrown);
66
- }
67
- }
68
- }
69
- var removed = globalSlot("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
70
- function markRecordRemoved(recordId) {
71
- removed.add(recordId);
72
- }
73
- function markRecordRestored(recordId) {
74
- removed.delete(recordId);
75
- }
76
- function onRecordChanged(listener) {
77
- listeners.add(listener);
78
- return () => listeners.delete(listener);
79
- }
80
- var tableListeners = globalSlot("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
81
- function announceTableStructureChanged(tableId) {
82
- for (const listener of [...tableListeners]) {
83
- try {
84
- listener(tableId);
85
- } catch (thrown) {
86
- console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
87
- }
88
- }
89
- }
90
-
91
- // src/archive.ts
92
- var DEFAULT_ARCHIVE_LANE = "org";
93
-
94
- // src/aggregate.ts
95
- function isRuleFilter(filter) {
96
- if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
97
- const node = filter;
98
- return typeof node.op === "string" && Array.isArray(node.args);
99
- }
100
- function stableFilterKey(filter) {
101
- if (!filter) return "{}";
102
- if (isRuleFilter(filter)) return JSON.stringify(filter);
103
- const keys = Object.keys(filter).sort();
104
- if (keys.length === 0) return "{}";
105
- const parts = keys.map((key) => {
106
- const value = filter[key];
107
- if (value !== null && typeof value === "object") {
108
- const window = value;
109
- return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
110
- }
111
- return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
112
- });
113
- return `{${parts.join(",")}}`;
114
- }
115
- function liftWithheld(rows) {
116
- let shared;
117
- for (const row of rows) {
118
- const m = (row.measures ?? {})["_withheld"];
119
- if (m !== void 0 && m !== null && typeof m === "object") {
120
- shared = m;
121
- break;
122
- }
123
- }
124
- return rows.map((row) => {
125
- const measures = row.measures ?? {};
126
- const own = measures["_withheld"];
127
- const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
128
- const rowCount = row.row_count ?? 0;
129
- if (marker === void 0 || marker === null || typeof marker !== "object") {
130
- return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
131
- }
132
- const { _withheld: _drop, ...rest } = measures;
133
- const withheld = {};
134
- for (const [name, raw] of Object.entries(marker)) {
135
- const m = raw ?? {};
136
- withheld[name] = {
137
- reason: m.withheld?.reason ?? null,
138
- needs: m.withheld?.needs ?? null,
139
- or: m.withheld?.or ?? null,
140
- ...m.says ? { says: m.says } : {},
141
- ...m.label ? { label: m.label } : {},
142
- ...m.field_key ? { field_key: m.field_key } : {}
143
- };
144
- }
145
- return { ...row, measures: rest, withheld, row_count: rowCount };
146
- });
147
- }
148
-
149
- // src/record.ts
150
- function isLockedStub(row) {
151
- if (!row) return false;
152
- if (row.level !== null && row.level !== void 0) return false;
153
- const doc = row.document;
154
- if (!doc || typeof doc !== "object") return false;
155
- const keys = Object.keys(doc);
156
- if (keys.length === 0 || keys.length > 3) return false;
157
- const d = doc;
158
- return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
159
- }
160
- function splitLockedRows(rows) {
161
- const open = [];
162
- let locked = 0;
163
- for (const row of rows) {
164
- if (isLockedStub(row)) locked += 1;
165
- else open.push(row);
166
- }
167
- return { rows: open, locked };
168
- }
169
-
170
- // src/subscription.ts
171
- function callersTimeZone() {
172
- try {
173
- return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
174
- } catch {
175
- return null;
176
- }
177
- }
178
- function withCallersClock(spec, zone = callersTimeZone()) {
179
- if (!zone || spec.quiet_hours?.tz) return spec;
180
- return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
181
- }
182
-
183
- // src/rowLabel.ts
184
- function clearsRowLabel(formula) {
185
- return formula == null || formula.trim() === "";
186
- }
187
-
188
57
  // src/results.ts
189
58
  var ok = (data) => ({ ok: true, data });
190
59
  var err = (error) => ({ ok: false, error });
@@ -355,6 +224,230 @@ function mapPgError(error, where) {
355
224
  return mapped;
356
225
  }
357
226
 
227
+ // src/core/doorCall.ts
228
+ var DEFAULT_DOOR_SCHEMA = "custom";
229
+ function canonicalArgs(value) {
230
+ return JSON.stringify(
231
+ value,
232
+ (_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
233
+ );
234
+ }
235
+ var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
236
+ "refused_by_rule",
237
+ "stale_write",
238
+ "invalid_argument",
239
+ "already_exists",
240
+ "missing_reference"
241
+ ]);
242
+ function isAPersonsRefusal(code) {
243
+ return A_PERSONS_REFUSAL.has(code);
244
+ }
245
+ function recordsErrorSink(onError) {
246
+ return onError ?? ((e) => {
247
+ const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
248
+ if (isAPersonsRefusal(e.code)) console.info(line);
249
+ else console.error(line);
250
+ });
251
+ }
252
+ function doorAbsentRefusal(name, owedBy) {
253
+ return {
254
+ code: "door_absent",
255
+ message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
256
+ hint: owedBy ? `That door is ${owedBy}. Until it lands, this call refuses rather than guessing: an empty answer here would read like "there is nothing", which is a different sentence.` : `No lane in the build book claims this door. Either the name is wrong, or the door was removed from the store and this package has not been regenerated \u2014 run \`pnpm records:generate\`.`
257
+ };
258
+ }
259
+ function primedDoorAnswer(door, args) {
260
+ const look = LOOK_WRITES[door];
261
+ if (look) {
262
+ dropPrimedDoorAnswers(look);
263
+ return null;
264
+ }
265
+ if (isWritingDoor(door)) {
266
+ dropPrimedDoorAnswers();
267
+ return null;
268
+ }
269
+ return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
270
+ }
271
+ function createDoorCall(options) {
272
+ const { dataSource, doorReady: doorReady2, held, wrote } = options;
273
+ const schema = options.schema ?? DEFAULT_DOOR_SCHEMA;
274
+ const scream = recordsErrorSink(options.onError);
275
+ const absent = options.absent ?? ((door) => doorAbsentRefusal(door));
276
+ const readsInFlight = /* @__PURE__ */ new Map();
277
+ const say = (refusal2, where) => scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
278
+ return async function callDoor(door, args, where, opts) {
279
+ const primed = primedDoorAnswer(door, args);
280
+ if (primed) return ok(primed.data);
281
+ if (held) {
282
+ const bundled = await held(door, args);
283
+ if (bundled) return ok(bundled.data);
284
+ }
285
+ if (doorReady2 && !doorReady2(door)) {
286
+ const refusal2 = absent(door);
287
+ say(refusal2, where);
288
+ return err(refusal2);
289
+ }
290
+ const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
291
+ const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
292
+ const response = await (flying ?? (() => {
293
+ const call = Promise.resolve(dataSource.rpc(`${door}`, args, { schema }));
294
+ if (flightKey) {
295
+ readsInFlight.set(flightKey, call);
296
+ const forget = () => {
297
+ if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
298
+ };
299
+ call.then(forget, forget);
300
+ }
301
+ return call;
302
+ })());
303
+ if (response.error) {
304
+ const code = response.error.code;
305
+ const refusal2 = !doorReady2 && (code === "PGRST202" || code === "42883") ? absent(door) : mapPgError(response.error, where);
306
+ if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
307
+ else say(refusal2, where);
308
+ return err(refusal2);
309
+ }
310
+ if (isWritingDoor(door) || LOOK_WRITES[door]) {
311
+ const tableId = args["p_table_id"];
312
+ wrote?.(door, args);
313
+ forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
314
+ dropPrimedDoorAnswers(LOOK_WRITES[door]);
315
+ }
316
+ return ok(response.data);
317
+ };
318
+ }
319
+
320
+ // src/core/recordChanges.ts
321
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
322
+ var listeners = globalSlot("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
323
+ function announceRecordChanged(recordId) {
324
+ for (const listener of [...listeners]) {
325
+ try {
326
+ listener(recordId);
327
+ } catch (thrown) {
328
+ console.error("[@ai-matrx/records] a record-change listener threw", thrown);
329
+ }
330
+ }
331
+ }
332
+ var removed = globalSlot("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
333
+ function markRecordRemoved(recordId) {
334
+ removed.add(recordId);
335
+ }
336
+ function markRecordRestored(recordId) {
337
+ removed.delete(recordId);
338
+ }
339
+ function onRecordChanged(listener) {
340
+ listeners.add(listener);
341
+ return () => listeners.delete(listener);
342
+ }
343
+ var tableListeners = globalSlot("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
344
+ function announceTableStructureChanged(tableId) {
345
+ for (const listener of [...tableListeners]) {
346
+ try {
347
+ listener(tableId);
348
+ } catch (thrown) {
349
+ console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
350
+ }
351
+ }
352
+ }
353
+
354
+ // src/archive.ts
355
+ var DEFAULT_ARCHIVE_LANE = "org";
356
+
357
+ // src/aggregate.ts
358
+ function isRuleFilter(filter) {
359
+ if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
360
+ const node = filter;
361
+ return typeof node.op === "string" && Array.isArray(node.args);
362
+ }
363
+ function stableFilterKey(filter) {
364
+ if (!filter) return "{}";
365
+ if (isRuleFilter(filter)) return JSON.stringify(filter);
366
+ const keys = Object.keys(filter).sort();
367
+ if (keys.length === 0) return "{}";
368
+ const parts = keys.map((key) => {
369
+ const value = filter[key];
370
+ if (value !== null && typeof value === "object") {
371
+ const window = value;
372
+ return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
373
+ }
374
+ return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
375
+ });
376
+ return `{${parts.join(",")}}`;
377
+ }
378
+ function liftWithheld(rows) {
379
+ let shared;
380
+ for (const row of rows) {
381
+ const m = (row.measures ?? {})["_withheld"];
382
+ if (m !== void 0 && m !== null && typeof m === "object") {
383
+ shared = m;
384
+ break;
385
+ }
386
+ }
387
+ return rows.map((row) => {
388
+ const measures = row.measures ?? {};
389
+ const own = measures["_withheld"];
390
+ const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
391
+ const rowCount = row.row_count ?? 0;
392
+ if (marker === void 0 || marker === null || typeof marker !== "object") {
393
+ return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
394
+ }
395
+ const { _withheld: _drop, ...rest } = measures;
396
+ const withheld = {};
397
+ for (const [name, raw] of Object.entries(marker)) {
398
+ const m = raw ?? {};
399
+ withheld[name] = {
400
+ reason: m.withheld?.reason ?? null,
401
+ needs: m.withheld?.needs ?? null,
402
+ or: m.withheld?.or ?? null,
403
+ ...m.says ? { says: m.says } : {},
404
+ ...m.label ? { label: m.label } : {},
405
+ ...m.field_key ? { field_key: m.field_key } : {}
406
+ };
407
+ }
408
+ return { ...row, measures: rest, withheld, row_count: rowCount };
409
+ });
410
+ }
411
+
412
+ // src/record.ts
413
+ function isLockedStub(row) {
414
+ if (!row) return false;
415
+ if (row.level !== null && row.level !== void 0) return false;
416
+ const doc = row.document;
417
+ if (!doc || typeof doc !== "object") return false;
418
+ const keys = Object.keys(doc);
419
+ if (keys.length === 0 || keys.length > 3) return false;
420
+ const d = doc;
421
+ return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
422
+ }
423
+ function splitLockedRows(rows) {
424
+ const open = [];
425
+ let locked = 0;
426
+ for (const row of rows) {
427
+ if (isLockedStub(row)) locked += 1;
428
+ else open.push(row);
429
+ }
430
+ return { rows: open, locked };
431
+ }
432
+
433
+ // src/subscription.ts
434
+ function callersTimeZone() {
435
+ try {
436
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
437
+ } catch {
438
+ return null;
439
+ }
440
+ }
441
+ function withCallersClock(spec, zone = callersTimeZone()) {
442
+ if (!zone || spec.quiet_hours?.tz) return spec;
443
+ return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
444
+ }
445
+
446
+ // src/rowLabel.ts
447
+ function clearsRowLabel(formula) {
448
+ return formula == null || formula.trim() === "";
449
+ }
450
+
358
451
  // src/relation.ts
359
452
  import { isUuidShape } from "@ai-matrx/kit/uuid";
360
453
  function isReverseField(field) {
@@ -1137,11 +1230,51 @@ function createScopeDoors(call) {
1137
1230
  source_type: String(envelope.data?.source_type ?? cell.source_type ?? "ai_enriched")
1138
1231
  }
1139
1232
  };
1233
+ },
1234
+ tableProvision({ organization_id, item_id, scope_id, home_id }) {
1235
+ return call(
1236
+ "scope_table_provision",
1237
+ { p_organization_id: organization_id, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
1238
+ "scopeTableProvision"
1239
+ );
1140
1240
  }
1141
1241
  };
1142
1242
  return doors;
1143
1243
  }
1144
1244
 
1245
+ // src/core/pickListDoors.ts
1246
+ var PICK_LIST_DOORS = {
1247
+ pickListGet: "pick_list_get",
1248
+ pickListForSelection: "pick_list_for_selection",
1249
+ pickListUpdate: "pick_list_update"
1250
+ };
1251
+ function createPickListDoors(callDoor) {
1252
+ return {
1253
+ async pickListGet({ list_id }) {
1254
+ return callDoor(PICK_LIST_DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
1255
+ },
1256
+ async pickListForSelection({ list_id }) {
1257
+ return callDoor(
1258
+ PICK_LIST_DOORS.pickListForSelection,
1259
+ { p_list_id: list_id },
1260
+ "pickListForSelection"
1261
+ );
1262
+ },
1263
+ async pickListUpdate({ list_id, list_name, description, items }) {
1264
+ return callDoor(
1265
+ PICK_LIST_DOORS.pickListUpdate,
1266
+ {
1267
+ p_list_id: list_id,
1268
+ p_list_name: list_name ?? null,
1269
+ p_description: description ?? null,
1270
+ p_items: items ? [...items] : null
1271
+ },
1272
+ "pickListUpdate"
1273
+ );
1274
+ }
1275
+ };
1276
+ }
1277
+
1145
1278
  // src/choice.ts
1146
1279
  import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
1147
1280
  var CHOICE_NUDGES = ["ask", "always_add", "never_add"];
@@ -2463,12 +2596,7 @@ function doorReady(config, name) {
2463
2596
  return DOOR_NAMES.has(name) || Boolean(config?.knownDoors?.includes(name));
2464
2597
  }
2465
2598
  function doorAbsent(name) {
2466
- const owed = OWED_BY[name];
2467
- return {
2468
- code: "door_absent",
2469
- message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
2470
- hint: owed ? `That door is ${owed}. Until it lands, this call refuses rather than guessing: an empty answer here would read like "there is nothing", which is a different sentence.` : `No lane in the build book claims this door. Either the name is wrong, or the door was removed from the store and this package has not been regenerated \u2014 run \`pnpm records:generate\`.`
2471
- };
2599
+ return doorAbsentRefusal(name, OWED_BY[name]);
2472
2600
  }
2473
2601
  var DOORS = {
2474
2602
  // THE READ DOOR (DOOR-1). Every read of a record's values goes through these
@@ -3248,29 +3376,6 @@ function intersectIds(sets) {
3248
3376
 
3249
3377
  // src/core/client.ts
3250
3378
  var DEFAULT_SCHEMA = "custom";
3251
- function canonicalArgs(value) {
3252
- return JSON.stringify(
3253
- value,
3254
- (_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
3255
- );
3256
- }
3257
- var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
3258
- "refused_by_rule",
3259
- "stale_write",
3260
- "invalid_argument",
3261
- "already_exists",
3262
- "missing_reference"
3263
- ]);
3264
- function isAPersonsRefusal(code) {
3265
- return A_PERSONS_REFUSAL.has(code);
3266
- }
3267
- function sink(config) {
3268
- return config.onError ?? ((e) => {
3269
- const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
3270
- if (isAPersonsRefusal(e.code)) console.info(line);
3271
- else console.error(line);
3272
- });
3273
- }
3274
3379
  var TABLE_LIST_PAGE = 500;
3275
3380
  var TABLE_ARCHIVE_PASS = 20;
3276
3381
  var TABLE_RESTORE_PASS = 20;
@@ -3283,7 +3388,7 @@ function createRecordsClient(given) {
3283
3388
  const org = config.organizationId;
3284
3389
  const ledger = config.opLedger ?? defaultOpLedger;
3285
3390
  const mintOp = () => ledger.mint();
3286
- const scream = sink(config);
3391
+ const scream = recordsErrorSink(config.onError);
3287
3392
  const BUNDLE_TTL_MS = 1e4;
3288
3393
  const BUNDLE_OPENERS = /* @__PURE__ */ new Set(["applicable_fields", "views", "view_look_read", "table_decorations", "row_actions", "reverse_columns", "record_change_actions", "grid_layout", "io_imports"]);
3289
3394
  const bundleParts = /* @__PURE__ */ new Map();
@@ -3425,56 +3530,20 @@ function createRecordsClient(given) {
3425
3530
  bundleAsked.delete(tableId);
3426
3531
  for (const key of [...bundleParts.keys()]) if (key.includes(tableId)) bundleParts.delete(key);
3427
3532
  }
3428
- function primedFor(door, args) {
3429
- const look = LOOK_WRITES[door];
3430
- if (look) {
3431
- dropPrimedDoorAnswers(look);
3432
- return null;
3433
- }
3434
- if (isWritingDoor(door)) {
3435
- dropPrimedDoorAnswers();
3436
- return null;
3437
- }
3438
- return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
3439
- }
3440
- const readsInFlight = /* @__PURE__ */ new Map();
3441
- async function callDoor(door, args, where, opts) {
3442
- const primed = primedFor(door, args);
3443
- if (primed) return ok(primed.data);
3444
- const bundled = await fromBundle(door, args);
3445
- if (bundled) return ok(bundled.data);
3446
- if (!doorReady(config, door)) {
3447
- const refusal2 = doorAbsent(door);
3448
- scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
3449
- return err(refusal2);
3450
- }
3451
- const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
3452
- const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
3453
- const response = await (flying ?? (() => {
3454
- const call = Promise.resolve(config.dataSource.rpc(`${door}`, args, { schema }));
3455
- if (flightKey) {
3456
- readsInFlight.set(flightKey, call);
3457
- const forget = () => {
3458
- if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
3459
- };
3460
- call.then(forget, forget);
3461
- }
3462
- return call;
3463
- })());
3464
- if (response.error) {
3465
- const refusal2 = mapPgError(response.error, where);
3466
- if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
3467
- else scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
3468
- return err(refusal2);
3469
- }
3470
- if (isWritingDoor(door) || LOOK_WRITES[door]) {
3533
+ const primedFor = primedDoorAnswer;
3534
+ const callDoor = createDoorCall({
3535
+ dataSource: config.dataSource,
3536
+ schema,
3537
+ onError: scream,
3538
+ doorReady: (door) => doorReady(config, door),
3539
+ absent: doorAbsent,
3540
+ held: fromBundle,
3541
+ wrote: (_door, args) => {
3471
3542
  const tableId = args["p_table_id"];
3472
3543
  bundleDrop(typeof tableId === "string" ? tableId : null);
3473
- forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
3474
- dropPrimedDoorAnswers(LOOK_WRITES[door]);
3475
3544
  }
3476
- return ok(response.data);
3477
- }
3545
+ });
3546
+ const scopes = createScopeDoors(callDoor);
3478
3547
  function structureMoved(tableId, result) {
3479
3548
  if (result.ok) {
3480
3549
  bundleDrop(tableId);
@@ -3673,7 +3742,7 @@ function createRecordsClient(given) {
3673
3742
  const unavailableReason = (error) => `${error.message}${error.hint ? ` ${error.hint}` : ""}`;
3674
3743
  const client = {
3675
3744
  config,
3676
- scopes: createScopeDoors(callDoor),
3745
+ scopes,
3677
3746
  async recordWrite({ table_id, data }) {
3678
3747
  const result = await callDoor(
3679
3748
  DOORS.recordWrite,
@@ -4372,28 +4441,7 @@ function createRecordsClient(given) {
4372
4441
  "fieldOptions"
4373
4442
  );
4374
4443
  },
4375
- async pickListGet({ list_id }) {
4376
- return callDoor(DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
4377
- },
4378
- async pickListForSelection({ list_id }) {
4379
- return callDoor(
4380
- DOORS.pickListForSelection,
4381
- { p_list_id: list_id },
4382
- "pickListForSelection"
4383
- );
4384
- },
4385
- async pickListUpdate({ list_id, list_name, description, items }) {
4386
- return callDoor(
4387
- DOORS.pickListUpdate,
4388
- {
4389
- p_list_id: list_id,
4390
- p_list_name: list_name ?? null,
4391
- p_description: description ?? null,
4392
- p_items: items ? [...items] : null
4393
- },
4394
- "pickListUpdate"
4395
- );
4396
- },
4444
+ ...createPickListDoors(callDoor),
4397
4445
  async fieldChoiceUsage({ field_id }) {
4398
4446
  const result = await callDoor(
4399
4447
  DOORS.fieldChoiceUsage,
@@ -6927,11 +6975,7 @@ function createRecordsClient(given) {
6927
6975
  );
6928
6976
  },
6929
6977
  async scopeTableProvision({ home_id, item_id, scope_id }) {
6930
- return callDoor(
6931
- DOORS.scopeTableProvision,
6932
- { p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
6933
- "scopeTableProvision"
6934
- );
6978
+ return scopes.tableProvision({ organization_id: org, item_id, scope_id, home_id: home_id ?? null });
6935
6979
  },
6936
6980
  async tableRowCounts({ table_ids }) {
6937
6981
  return callDoor(
@@ -7564,7 +7608,7 @@ function createEntityDataPort(options) {
7564
7608
  let stopped = false;
7565
7609
  let joined = [];
7566
7610
  let stopLive = null;
7567
- const sink2 = { rows: (ids) => listener({ ids: ids === null ? null : [...ids] }) };
7611
+ const sink = { rows: (ids) => listener({ ids: ids === null ? null : [...ids] }) };
7568
7612
  const plan = async () => {
7569
7613
  const organizationIds = binding.organizationId ? [binding.organizationId] : orderOrganizationTopics({
7570
7614
  active: activeOrganization(),
@@ -7576,7 +7620,7 @@ function createEntityDataPort(options) {
7576
7620
  if (organizationIds.length === joined.length && organizationIds.every((org, i) => org === joined[i])) return;
7577
7621
  const previous = stopLive;
7578
7622
  joined = organizationIds;
7579
- stopLive = realtime.subscribe({ token: binding.token, organizationIds }, sink2);
7623
+ stopLive = realtime.subscribe({ token: binding.token, organizationIds }, sink);
7580
7624
  previous?.();
7581
7625
  };
7582
7626
  const replan = () => void plan();
@@ -7701,7 +7745,7 @@ function createRecordsRealtimePort(options = {}) {
7701
7745
  return channel;
7702
7746
  };
7703
7747
  return {
7704
- subscribeRecords({ table_id }, sink2) {
7748
+ subscribeRecords({ table_id }, sink) {
7705
7749
  let timer = null;
7706
7750
  let pending = /* @__PURE__ */ new Set();
7707
7751
  let wholePage = false;
@@ -7711,15 +7755,15 @@ function createRecordsRealtimePort(options = {}) {
7711
7755
  const all = wholePage;
7712
7756
  pending = /* @__PURE__ */ new Set();
7713
7757
  wholePage = false;
7714
- if (all) sink2.records(null);
7715
- else if (ids.length > 0) sink2.records(ids);
7758
+ if (all) sink.records(null);
7759
+ else if (ids.length > 0) sink.records(ids);
7716
7760
  };
7717
7761
  const nudge = () => {
7718
7762
  if (timer === null) timer = setTimeout(flush, NUDGE_DEBOUNCE_MS);
7719
7763
  };
7720
7764
  const listener = {
7721
7765
  notice(notice) {
7722
- if (notice.kind === "field" || notice.kind === "table") sink2.shape();
7766
+ if (notice.kind === "field" || notice.kind === "table") sink.shape();
7723
7767
  if (notice.kind === "field") return;
7724
7768
  if (notice.record_ids == null) wholePage = true;
7725
7769
  else for (const id of notice.record_ids) pending.add(id);
@@ -7840,7 +7884,7 @@ async function createRecords(options) {
7840
7884
  realtime,
7841
7885
  search: (request) => searchRecords(dataSource, request),
7842
7886
  recordCandidates: (args) => listStoreRecordCandidates(dataSource, args),
7843
- watch(tableId, sink2, organizationId2) {
7887
+ watch(tableId, sink, organizationId2) {
7844
7888
  const activeOrganizationId = organizationIdChosen;
7845
7889
  const org = organizationId2 ?? activeOrganizationId;
7846
7890
  if (!realtimePort || !org) {
@@ -7851,8 +7895,8 @@ async function createRecords(options) {
7851
7895
  return () => {
7852
7896
  };
7853
7897
  }
7854
- return realtimePort.subscribeRecords({ organization_id: org, table_id: tableId }, { records: sink2.records ?? (() => {
7855
- }), shape: sink2.shape ?? (() => {
7898
+ return realtimePort.subscribeRecords({ organization_id: org, table_id: tableId }, { records: sink.records ?? (() => {
7899
+ }), shape: sink.shape ?? (() => {
7856
7900
  }) });
7857
7901
  },
7858
7902
  associations: options.associations,