@ai-matrx/records 0.99.31 → 0.99.33

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 (106) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/{client-Dthx26hr.d.ts → client-CSfkP7Xf.d.ts} +11 -80
  3. package/dist/{client-B7KEs9hi.d.cts → client-jKf1Z-kp.d.cts} +11 -80
  4. package/dist/core/index.cjs +149 -105
  5. package/dist/core/index.cjs.map +1 -1
  6. package/dist/core/index.d.cts +18 -359
  7. package/dist/core/index.d.ts +18 -359
  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 +12 -11
  13. package/dist/data/index.d.ts +12 -11
  14. package/dist/data/index.js +280 -236
  15. package/dist/data/index.js.map +1 -1
  16. package/dist/{declareTable-CvBu5dTJ.d.ts → declareTable-0emxEewn.d.ts} +3 -3
  17. package/dist/{declareTable-enQs2N0E.d.cts → declareTable-800bwUn3.d.cts} +3 -3
  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-KbjyhBW-.d.cts → doors-BgjRUdxw.d.cts} +14 -2
  25. package/dist/{doors-C2-sFvAk.d.ts → doors-D7_jEKtg.d.ts} +14 -2
  26. package/dist/entity/index.d.cts +7 -7
  27. package/dist/entity/index.d.ts +7 -7
  28. package/dist/{field-ppX29ddi.d.cts → field-B8loYt-A.d.cts} +1 -1
  29. package/dist/{field-BHlhq24W.d.ts → field-DaE90BZ7.d.ts} +1 -1
  30. package/dist/forms/index.d.cts +3 -3
  31. package/dist/forms/index.d.ts +3 -3
  32. package/dist/index.d.cts +14 -13
  33. package/dist/index.d.ts +14 -13
  34. package/dist/memory/index.d.cts +7 -7
  35. package/dist/memory/index.d.ts +7 -7
  36. package/dist/{objectOrganization-Cu73SBxH.d.cts → objectOrganization-B5YFGVUB.d.cts} +2 -2
  37. package/dist/{objectOrganization-DtR3lWG2.d.ts → objectOrganization-DozoVIxS.d.ts} +2 -2
  38. package/dist/pickListDoors-C-_eAEGL.d.cts +135 -0
  39. package/dist/pickListDoors-DgWVnNRI.d.ts +135 -0
  40. package/dist/{port-Bk7TG0aE.d.ts → port-D6wepPvr.d.ts} +3 -3
  41. package/dist/{port-rqQEGhew.d.cts → port-O-UdH1HS.d.cts} +3 -3
  42. package/dist/{portal-DmxuUr2f.d.ts → portal-CAssJHRZ.d.ts} +1 -1
  43. package/dist/{portal-ffH13fsE.d.cts → portal-L_mN8l9P.d.cts} +1 -1
  44. package/dist/{ports-BCNNghmf.d.ts → ports-CmmvR8OI.d.ts} +2 -2
  45. package/dist/{ports-iATV-A2v.d.cts → ports-alv3bgKY.d.cts} +2 -2
  46. package/dist/questions/index.d.cts +10 -9
  47. package/dist/questions/index.d.ts +10 -9
  48. package/dist/react/index.cjs +363 -319
  49. package/dist/react/index.cjs.map +1 -1
  50. package/dist/react/index.d.cts +37 -22
  51. package/dist/react/index.d.ts +37 -22
  52. package/dist/react/index.js +363 -319
  53. package/dist/react/index.js.map +1 -1
  54. package/dist/realtime/index.d.cts +3 -3
  55. package/dist/realtime/index.d.ts +3 -3
  56. package/dist/{record-C8q21jjB.d.cts → record-CTgSgWe3.d.cts} +1 -1
  57. package/dist/{record-C8q21jjB.d.ts → record-CTgSgWe3.d.ts} +1 -1
  58. package/dist/{relation-Bwp8iuei.d.cts → relation-BjjjXyqn.d.cts} +2 -2
  59. package/dist/{relation-Bsjwkn6N.d.ts → relation-T4biacnz.d.ts} +2 -2
  60. package/dist/results/index.cjs +245 -0
  61. package/dist/results/index.cjs.map +1 -0
  62. package/dist/results/index.d.cts +24 -0
  63. package/dist/results/index.d.ts +24 -0
  64. package/dist/results/index.js +222 -0
  65. package/dist/results/index.js.map +1 -0
  66. package/dist/{rule-BQwUtKk5.d.cts → rule-49jO7lN-.d.cts} +1 -1
  67. package/dist/{rule-cGqclk_0.d.ts → rule-DzNj0QvN.d.ts} +1 -1
  68. package/dist/scopes/index.cjs +7 -0
  69. package/dist/scopes/index.cjs.map +1 -1
  70. package/dist/scopes/index.d.cts +3 -3
  71. package/dist/scopes/index.d.ts +3 -3
  72. package/dist/scopes/index.js +7 -0
  73. package/dist/scopes/index.js.map +1 -1
  74. package/dist/search/index.d.cts +1 -1
  75. package/dist/search/index.d.ts +1 -1
  76. package/dist/setup/index.cjs +289 -245
  77. package/dist/setup/index.cjs.map +1 -1
  78. package/dist/setup/index.d.cts +13 -12
  79. package/dist/setup/index.d.ts +13 -12
  80. package/dist/setup/index.js +289 -245
  81. package/dist/setup/index.js.map +1 -1
  82. package/dist/{subscription-eNzL9scc.d.ts → subscription-Bp1RSb6p.d.ts} +2 -2
  83. package/dist/{subscription-Ba8RKtPA.d.cts → subscription-CuaGi3lC.d.cts} +2 -2
  84. package/dist/table-logic-BPquabNN.d.ts +328 -0
  85. package/dist/table-logic-CTh6lwaq.d.cts +328 -0
  86. package/dist/templates/index.d.cts +10 -10
  87. package/dist/templates/index.d.ts +10 -10
  88. package/dist/typed-table/index.cjs +280 -236
  89. package/dist/typed-table/index.cjs.map +1 -1
  90. package/dist/typed-table/index.d.cts +11 -10
  91. package/dist/typed-table/index.d.ts +11 -10
  92. package/dist/typed-table/index.js +280 -236
  93. package/dist/typed-table/index.js.map +1 -1
  94. package/dist/{types-C4XCuv8O.d.cts → types-B54BeQzf.d.cts} +2 -2
  95. package/dist/{types-BlzdL4Vd.d.cts → types-BWfL38XJ.d.cts} +2 -2
  96. package/dist/{types-BBR2NGqj.d.ts → types-BZcYXFK3.d.ts} +2 -2
  97. package/dist/{types-EKwXJfxY.d.cts → types-Bztv0-pH.d.cts} +2 -2
  98. package/dist/{types-CmkHpvll.d.ts → types-CjGuR5ks.d.ts} +2 -2
  99. package/dist/{types-CrkzINrb.d.ts → types-bN7dG2ji.d.ts} +2 -2
  100. package/dist/use-cases/index.d.cts +5 -5
  101. package/dist/use-cases/index.d.ts +5 -5
  102. package/dist/{validate-BKeBAVSi.d.cts → validate-8VBa2xIU.d.cts} +1 -1
  103. package/dist/{validate-BB6DWgCP.d.ts → validate-xBnply7J.d.ts} +1 -1
  104. package/dist/views/index.d.cts +10 -9
  105. package/dist/views/index.d.ts +10 -9
  106. package/package.json +24 -4
@@ -1,13 +1,14 @@
1
- import { N as NewFieldSpec } from '../declareTable-enQs2N0E.cjs';
2
- import { U as Uuid, R as RecordsResult, k as RecordPageSort } from '../record-C8q21jjB.cjs';
3
- import { F as FieldDrift, R as RecordsClient, T as TableArchiveProgress } from '../client-B7KEs9hi.cjs';
4
- import '../field-ppX29ddi.cjs';
5
- import '../subscription-Ba8RKtPA.cjs';
6
- import '../rule-BQwUtKk5.cjs';
7
- import '../relation-Bwp8iuei.cjs';
8
- import '../ports-iATV-A2v.cjs';
9
- import '../doors-KbjyhBW-.cjs';
10
- import '../portal-ffH13fsE.cjs';
1
+ import { N as NewFieldSpec } from '../declareTable-800bwUn3.cjs';
2
+ import { U as Uuid, R as RecordsResult, k as RecordPageSort } from '../record-CTgSgWe3.cjs';
3
+ import { F as FieldDrift, R as RecordsClient, T as TableArchiveProgress } from '../client-jKf1Z-kp.cjs';
4
+ import '../field-B8loYt-A.cjs';
5
+ import '../subscription-CuaGi3lC.cjs';
6
+ import '../rule-49jO7lN-.cjs';
7
+ import '../relation-BjjjXyqn.cjs';
8
+ import '../ports-alv3bgKY.cjs';
9
+ import '../doors-BgjRUdxw.cjs';
10
+ import '../pickListDoors-C-_eAEGL.cjs';
11
+ import '../portal-L_mN8l9P.cjs';
11
12
  import '../table-kind/index.cjs';
12
13
 
13
14
  /** Where a declared field's value goes in the graduated table. */
@@ -1,13 +1,14 @@
1
- import { N as NewFieldSpec } from '../declareTable-CvBu5dTJ.js';
2
- import { U as Uuid, R as RecordsResult, k as RecordPageSort } from '../record-C8q21jjB.js';
3
- import { F as FieldDrift, R as RecordsClient, T as TableArchiveProgress } from '../client-Dthx26hr.js';
4
- import '../field-BHlhq24W.js';
5
- import '../subscription-eNzL9scc.js';
6
- import '../rule-cGqclk_0.js';
7
- import '../relation-Bsjwkn6N.js';
8
- import '../ports-BCNNghmf.js';
9
- import '../doors-C2-sFvAk.js';
10
- import '../portal-DmxuUr2f.js';
1
+ import { N as NewFieldSpec } from '../declareTable-0emxEewn.js';
2
+ import { U as Uuid, R as RecordsResult, k as RecordPageSort } from '../record-CTgSgWe3.js';
3
+ import { F as FieldDrift, R as RecordsClient, T as TableArchiveProgress } from '../client-CSfkP7Xf.js';
4
+ import '../field-DaE90BZ7.js';
5
+ import '../subscription-Bp1RSb6p.js';
6
+ import '../rule-DzNj0QvN.js';
7
+ import '../relation-T4biacnz.js';
8
+ import '../ports-CmmvR8OI.js';
9
+ import '../doors-D7_jEKtg.js';
10
+ import '../pickListDoors-DgWVnNRI.js';
11
+ import '../portal-CAssJHRZ.js';
11
12
  import '../table-kind/index.js';
12
13
 
13
14
  /** Where a declared field's value goes in the graduated table. */
@@ -329,137 +329,6 @@ function isWritingDoor(door) {
329
329
  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);
330
330
  }
331
331
 
332
- // src/core/recordChanges.ts
333
- import { globalSlot } from "@ai-matrx/kit/global-slot";
334
- var listeners = globalSlot("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
335
- function announceRecordChanged(recordId) {
336
- for (const listener of [...listeners]) {
337
- try {
338
- listener(recordId);
339
- } catch (thrown) {
340
- console.error("[@ai-matrx/records] a record-change listener threw", thrown);
341
- }
342
- }
343
- }
344
- var removed = globalSlot("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
345
- function markRecordRemoved(recordId) {
346
- removed.add(recordId);
347
- }
348
- function markRecordRestored(recordId) {
349
- removed.delete(recordId);
350
- }
351
- function onRecordChanged(listener) {
352
- listeners.add(listener);
353
- return () => listeners.delete(listener);
354
- }
355
- var tableListeners = globalSlot("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
356
- function announceTableStructureChanged(tableId) {
357
- for (const listener of [...tableListeners]) {
358
- try {
359
- listener(tableId);
360
- } catch (thrown) {
361
- console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
362
- }
363
- }
364
- }
365
-
366
- // src/archive.ts
367
- var DEFAULT_ARCHIVE_LANE = "org";
368
-
369
- // src/aggregate.ts
370
- function isRuleFilter(filter) {
371
- if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
372
- const node = filter;
373
- return typeof node.op === "string" && Array.isArray(node.args);
374
- }
375
- function stableFilterKey(filter) {
376
- if (!filter) return "{}";
377
- if (isRuleFilter(filter)) return JSON.stringify(filter);
378
- const keys = Object.keys(filter).sort();
379
- if (keys.length === 0) return "{}";
380
- const parts = keys.map((key) => {
381
- const value = filter[key];
382
- if (value !== null && typeof value === "object") {
383
- const window = value;
384
- return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
385
- }
386
- return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
387
- });
388
- return `{${parts.join(",")}}`;
389
- }
390
- function liftWithheld(rows) {
391
- let shared;
392
- for (const row of rows) {
393
- const m = (row.measures ?? {})["_withheld"];
394
- if (m !== void 0 && m !== null && typeof m === "object") {
395
- shared = m;
396
- break;
397
- }
398
- }
399
- return rows.map((row) => {
400
- const measures = row.measures ?? {};
401
- const own = measures["_withheld"];
402
- const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
403
- const rowCount = row.row_count ?? 0;
404
- if (marker === void 0 || marker === null || typeof marker !== "object") {
405
- return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
406
- }
407
- const { _withheld: _drop, ...rest } = measures;
408
- const withheld = {};
409
- for (const [name, raw] of Object.entries(marker)) {
410
- const m = raw ?? {};
411
- withheld[name] = {
412
- reason: m.withheld?.reason ?? null,
413
- needs: m.withheld?.needs ?? null,
414
- or: m.withheld?.or ?? null,
415
- ...m.says ? { says: m.says } : {},
416
- ...m.label ? { label: m.label } : {},
417
- ...m.field_key ? { field_key: m.field_key } : {}
418
- };
419
- }
420
- return { ...row, measures: rest, withheld, row_count: rowCount };
421
- });
422
- }
423
-
424
- // src/record.ts
425
- function isLockedStub(row) {
426
- if (!row) return false;
427
- if (row.level !== null && row.level !== void 0) return false;
428
- const doc = row.document;
429
- if (!doc || typeof doc !== "object") return false;
430
- const keys = Object.keys(doc);
431
- if (keys.length === 0 || keys.length > 3) return false;
432
- const d = doc;
433
- return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
434
- }
435
- function splitLockedRows(rows) {
436
- const open = [];
437
- let locked = 0;
438
- for (const row of rows) {
439
- if (isLockedStub(row)) locked += 1;
440
- else open.push(row);
441
- }
442
- return { rows: open, locked };
443
- }
444
-
445
- // src/subscription.ts
446
- function callersTimeZone() {
447
- try {
448
- return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
449
- } catch {
450
- return null;
451
- }
452
- }
453
- function withCallersClock(spec, zone = callersTimeZone()) {
454
- if (!zone || spec.quiet_hours?.tz) return spec;
455
- return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
456
- }
457
-
458
- // src/rowLabel.ts
459
- function clearsRowLabel(formula) {
460
- return formula == null || formula.trim() === "";
461
- }
462
-
463
332
  // src/results.ts
464
333
  var ok = (data) => ({ ok: true, data });
465
334
  var err = (error) => ({ ok: false, error });
@@ -630,6 +499,230 @@ function mapPgError(error, where) {
630
499
  return mapped;
631
500
  }
632
501
 
502
+ // src/core/doorCall.ts
503
+ var DEFAULT_DOOR_SCHEMA = "custom";
504
+ function canonicalArgs(value) {
505
+ return JSON.stringify(
506
+ value,
507
+ (_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
508
+ );
509
+ }
510
+ var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
511
+ "refused_by_rule",
512
+ "stale_write",
513
+ "invalid_argument",
514
+ "already_exists",
515
+ "missing_reference"
516
+ ]);
517
+ function isAPersonsRefusal(code) {
518
+ return A_PERSONS_REFUSAL.has(code);
519
+ }
520
+ function recordsErrorSink(onError) {
521
+ return onError ?? ((e) => {
522
+ const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
523
+ if (isAPersonsRefusal(e.code)) console.info(line);
524
+ else console.error(line);
525
+ });
526
+ }
527
+ function doorAbsentRefusal(name, owedBy) {
528
+ return {
529
+ code: "door_absent",
530
+ message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
531
+ 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\`.`
532
+ };
533
+ }
534
+ function primedDoorAnswer(door, args) {
535
+ const look = LOOK_WRITES[door];
536
+ if (look) {
537
+ dropPrimedDoorAnswers(look);
538
+ return null;
539
+ }
540
+ if (isWritingDoor(door)) {
541
+ dropPrimedDoorAnswers();
542
+ return null;
543
+ }
544
+ return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
545
+ }
546
+ function createDoorCall(options) {
547
+ const { dataSource, doorReady: doorReady2, held, wrote } = options;
548
+ const schema = options.schema ?? DEFAULT_DOOR_SCHEMA;
549
+ const scream = recordsErrorSink(options.onError);
550
+ const absent = options.absent ?? ((door) => doorAbsentRefusal(door));
551
+ const readsInFlight = /* @__PURE__ */ new Map();
552
+ const say = (refusal2, where) => scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
553
+ return async function callDoor(door, args, where, opts) {
554
+ const primed = primedDoorAnswer(door, args);
555
+ if (primed) return ok(primed.data);
556
+ if (held) {
557
+ const bundled = await held(door, args);
558
+ if (bundled) return ok(bundled.data);
559
+ }
560
+ if (doorReady2 && !doorReady2(door)) {
561
+ const refusal2 = absent(door);
562
+ say(refusal2, where);
563
+ return err(refusal2);
564
+ }
565
+ const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
566
+ const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
567
+ const response = await (flying ?? (() => {
568
+ const call = Promise.resolve(dataSource.rpc(`${door}`, args, { schema }));
569
+ if (flightKey) {
570
+ readsInFlight.set(flightKey, call);
571
+ const forget = () => {
572
+ if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
573
+ };
574
+ call.then(forget, forget);
575
+ }
576
+ return call;
577
+ })());
578
+ if (response.error) {
579
+ const code = response.error.code;
580
+ const refusal2 = !doorReady2 && (code === "PGRST202" || code === "42883") ? absent(door) : mapPgError(response.error, where);
581
+ if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
582
+ else say(refusal2, where);
583
+ return err(refusal2);
584
+ }
585
+ if (isWritingDoor(door) || LOOK_WRITES[door]) {
586
+ const tableId = args["p_table_id"];
587
+ wrote?.(door, args);
588
+ forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
589
+ dropPrimedDoorAnswers(LOOK_WRITES[door]);
590
+ }
591
+ return ok(response.data);
592
+ };
593
+ }
594
+
595
+ // src/core/recordChanges.ts
596
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
597
+ var listeners = globalSlot("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
598
+ function announceRecordChanged(recordId) {
599
+ for (const listener of [...listeners]) {
600
+ try {
601
+ listener(recordId);
602
+ } catch (thrown) {
603
+ console.error("[@ai-matrx/records] a record-change listener threw", thrown);
604
+ }
605
+ }
606
+ }
607
+ var removed = globalSlot("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
608
+ function markRecordRemoved(recordId) {
609
+ removed.add(recordId);
610
+ }
611
+ function markRecordRestored(recordId) {
612
+ removed.delete(recordId);
613
+ }
614
+ function onRecordChanged(listener) {
615
+ listeners.add(listener);
616
+ return () => listeners.delete(listener);
617
+ }
618
+ var tableListeners = globalSlot("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
619
+ function announceTableStructureChanged(tableId) {
620
+ for (const listener of [...tableListeners]) {
621
+ try {
622
+ listener(tableId);
623
+ } catch (thrown) {
624
+ console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
625
+ }
626
+ }
627
+ }
628
+
629
+ // src/archive.ts
630
+ var DEFAULT_ARCHIVE_LANE = "org";
631
+
632
+ // src/aggregate.ts
633
+ function isRuleFilter(filter) {
634
+ if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
635
+ const node = filter;
636
+ return typeof node.op === "string" && Array.isArray(node.args);
637
+ }
638
+ function stableFilterKey(filter) {
639
+ if (!filter) return "{}";
640
+ if (isRuleFilter(filter)) return JSON.stringify(filter);
641
+ const keys = Object.keys(filter).sort();
642
+ if (keys.length === 0) return "{}";
643
+ const parts = keys.map((key) => {
644
+ const value = filter[key];
645
+ if (value !== null && typeof value === "object") {
646
+ const window = value;
647
+ return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
648
+ }
649
+ return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
650
+ });
651
+ return `{${parts.join(",")}}`;
652
+ }
653
+ function liftWithheld(rows) {
654
+ let shared;
655
+ for (const row of rows) {
656
+ const m = (row.measures ?? {})["_withheld"];
657
+ if (m !== void 0 && m !== null && typeof m === "object") {
658
+ shared = m;
659
+ break;
660
+ }
661
+ }
662
+ return rows.map((row) => {
663
+ const measures = row.measures ?? {};
664
+ const own = measures["_withheld"];
665
+ const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
666
+ const rowCount = row.row_count ?? 0;
667
+ if (marker === void 0 || marker === null || typeof marker !== "object") {
668
+ return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
669
+ }
670
+ const { _withheld: _drop, ...rest } = measures;
671
+ const withheld = {};
672
+ for (const [name, raw] of Object.entries(marker)) {
673
+ const m = raw ?? {};
674
+ withheld[name] = {
675
+ reason: m.withheld?.reason ?? null,
676
+ needs: m.withheld?.needs ?? null,
677
+ or: m.withheld?.or ?? null,
678
+ ...m.says ? { says: m.says } : {},
679
+ ...m.label ? { label: m.label } : {},
680
+ ...m.field_key ? { field_key: m.field_key } : {}
681
+ };
682
+ }
683
+ return { ...row, measures: rest, withheld, row_count: rowCount };
684
+ });
685
+ }
686
+
687
+ // src/record.ts
688
+ function isLockedStub(row) {
689
+ if (!row) return false;
690
+ if (row.level !== null && row.level !== void 0) return false;
691
+ const doc = row.document;
692
+ if (!doc || typeof doc !== "object") return false;
693
+ const keys = Object.keys(doc);
694
+ if (keys.length === 0 || keys.length > 3) return false;
695
+ const d = doc;
696
+ return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
697
+ }
698
+ function splitLockedRows(rows) {
699
+ const open = [];
700
+ let locked = 0;
701
+ for (const row of rows) {
702
+ if (isLockedStub(row)) locked += 1;
703
+ else open.push(row);
704
+ }
705
+ return { rows: open, locked };
706
+ }
707
+
708
+ // src/subscription.ts
709
+ function callersTimeZone() {
710
+ try {
711
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
712
+ } catch {
713
+ return null;
714
+ }
715
+ }
716
+ function withCallersClock(spec, zone = callersTimeZone()) {
717
+ if (!zone || spec.quiet_hours?.tz) return spec;
718
+ return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
719
+ }
720
+
721
+ // src/rowLabel.ts
722
+ function clearsRowLabel(formula) {
723
+ return formula == null || formula.trim() === "";
724
+ }
725
+
633
726
  // src/relation.ts
634
727
  import { isUuidShape as isUuidShape2 } from "@ai-matrx/kit/uuid";
635
728
  function isReverseField(field2) {
@@ -1409,11 +1502,51 @@ function createScopeDoors(call) {
1409
1502
  source_type: String(envelope.data?.source_type ?? cell.source_type ?? "ai_enriched")
1410
1503
  }
1411
1504
  };
1505
+ },
1506
+ tableProvision({ organization_id, item_id, scope_id, home_id }) {
1507
+ return call(
1508
+ "scope_table_provision",
1509
+ { p_organization_id: organization_id, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
1510
+ "scopeTableProvision"
1511
+ );
1412
1512
  }
1413
1513
  };
1414
1514
  return doors;
1415
1515
  }
1416
1516
 
1517
+ // src/core/pickListDoors.ts
1518
+ var PICK_LIST_DOORS = {
1519
+ pickListGet: "pick_list_get",
1520
+ pickListForSelection: "pick_list_for_selection",
1521
+ pickListUpdate: "pick_list_update"
1522
+ };
1523
+ function createPickListDoors(callDoor) {
1524
+ return {
1525
+ async pickListGet({ list_id }) {
1526
+ return callDoor(PICK_LIST_DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
1527
+ },
1528
+ async pickListForSelection({ list_id }) {
1529
+ return callDoor(
1530
+ PICK_LIST_DOORS.pickListForSelection,
1531
+ { p_list_id: list_id },
1532
+ "pickListForSelection"
1533
+ );
1534
+ },
1535
+ async pickListUpdate({ list_id, list_name, description, items }) {
1536
+ return callDoor(
1537
+ PICK_LIST_DOORS.pickListUpdate,
1538
+ {
1539
+ p_list_id: list_id,
1540
+ p_list_name: list_name ?? null,
1541
+ p_description: description ?? null,
1542
+ p_items: items ? [...items] : null
1543
+ },
1544
+ "pickListUpdate"
1545
+ );
1546
+ }
1547
+ };
1548
+ }
1549
+
1417
1550
  // src/choice.ts
1418
1551
  import { isUuidShape as isUuidShape4 } from "@ai-matrx/kit/uuid";
1419
1552
  var CHOICE_NUDGES = ["ask", "always_add", "never_add"];
@@ -2735,12 +2868,7 @@ function doorReady(config, name) {
2735
2868
  return DOOR_NAMES.has(name) || Boolean(config?.knownDoors?.includes(name));
2736
2869
  }
2737
2870
  function doorAbsent(name) {
2738
- const owed = OWED_BY[name];
2739
- return {
2740
- code: "door_absent",
2741
- message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
2742
- 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\`.`
2743
- };
2871
+ return doorAbsentRefusal(name, OWED_BY[name]);
2744
2872
  }
2745
2873
  var DOORS = {
2746
2874
  // THE READ DOOR (DOOR-1). Every read of a record's values goes through these
@@ -3520,29 +3648,6 @@ function intersectIds(sets) {
3520
3648
 
3521
3649
  // src/core/client.ts
3522
3650
  var DEFAULT_SCHEMA = "custom";
3523
- function canonicalArgs(value) {
3524
- return JSON.stringify(
3525
- value,
3526
- (_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
3527
- );
3528
- }
3529
- var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
3530
- "refused_by_rule",
3531
- "stale_write",
3532
- "invalid_argument",
3533
- "already_exists",
3534
- "missing_reference"
3535
- ]);
3536
- function isAPersonsRefusal(code) {
3537
- return A_PERSONS_REFUSAL.has(code);
3538
- }
3539
- function sink(config) {
3540
- return config.onError ?? ((e) => {
3541
- const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
3542
- if (isAPersonsRefusal(e.code)) console.info(line);
3543
- else console.error(line);
3544
- });
3545
- }
3546
3651
  var TABLE_LIST_PAGE = 500;
3547
3652
  var TABLE_ARCHIVE_PASS = 20;
3548
3653
  var TABLE_RESTORE_PASS = 20;
@@ -3555,7 +3660,7 @@ function createRecordsClient(given) {
3555
3660
  const org = config.organizationId;
3556
3661
  const ledger = config.opLedger ?? defaultOpLedger;
3557
3662
  const mintOp = () => ledger.mint();
3558
- const scream = sink(config);
3663
+ const scream = recordsErrorSink(config.onError);
3559
3664
  const BUNDLE_TTL_MS = 1e4;
3560
3665
  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"]);
3561
3666
  const bundleParts = /* @__PURE__ */ new Map();
@@ -3697,56 +3802,20 @@ function createRecordsClient(given) {
3697
3802
  bundleAsked.delete(tableId);
3698
3803
  for (const key of [...bundleParts.keys()]) if (key.includes(tableId)) bundleParts.delete(key);
3699
3804
  }
3700
- function primedFor(door, args) {
3701
- const look = LOOK_WRITES[door];
3702
- if (look) {
3703
- dropPrimedDoorAnswers(look);
3704
- return null;
3705
- }
3706
- if (isWritingDoor(door)) {
3707
- dropPrimedDoorAnswers();
3708
- return null;
3709
- }
3710
- return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
3711
- }
3712
- const readsInFlight = /* @__PURE__ */ new Map();
3713
- async function callDoor(door, args, where, opts) {
3714
- const primed = primedFor(door, args);
3715
- if (primed) return ok(primed.data);
3716
- const bundled = await fromBundle(door, args);
3717
- if (bundled) return ok(bundled.data);
3718
- if (!doorReady(config, door)) {
3719
- const refusal2 = doorAbsent(door);
3720
- scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
3721
- return err(refusal2);
3722
- }
3723
- const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
3724
- const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
3725
- const response = await (flying ?? (() => {
3726
- const call = Promise.resolve(config.dataSource.rpc(`${door}`, args, { schema }));
3727
- if (flightKey) {
3728
- readsInFlight.set(flightKey, call);
3729
- const forget = () => {
3730
- if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
3731
- };
3732
- call.then(forget, forget);
3733
- }
3734
- return call;
3735
- })());
3736
- if (response.error) {
3737
- const refusal2 = mapPgError(response.error, where);
3738
- if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
3739
- else scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
3740
- return err(refusal2);
3741
- }
3742
- if (isWritingDoor(door) || LOOK_WRITES[door]) {
3805
+ const primedFor = primedDoorAnswer;
3806
+ const callDoor = createDoorCall({
3807
+ dataSource: config.dataSource,
3808
+ schema,
3809
+ onError: scream,
3810
+ doorReady: (door) => doorReady(config, door),
3811
+ absent: doorAbsent,
3812
+ held: fromBundle,
3813
+ wrote: (_door, args) => {
3743
3814
  const tableId = args["p_table_id"];
3744
3815
  bundleDrop(typeof tableId === "string" ? tableId : null);
3745
- forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
3746
- dropPrimedDoorAnswers(LOOK_WRITES[door]);
3747
3816
  }
3748
- return ok(response.data);
3749
- }
3817
+ });
3818
+ const scopes = createScopeDoors(callDoor);
3750
3819
  function structureMoved(tableId, result) {
3751
3820
  if (result.ok) {
3752
3821
  bundleDrop(tableId);
@@ -3945,7 +4014,7 @@ function createRecordsClient(given) {
3945
4014
  const unavailableReason = (error) => `${error.message}${error.hint ? ` ${error.hint}` : ""}`;
3946
4015
  const client = {
3947
4016
  config,
3948
- scopes: createScopeDoors(callDoor),
4017
+ scopes,
3949
4018
  async recordWrite({ table_id, data }) {
3950
4019
  const result = await callDoor(
3951
4020
  DOORS.recordWrite,
@@ -4644,28 +4713,7 @@ function createRecordsClient(given) {
4644
4713
  "fieldOptions"
4645
4714
  );
4646
4715
  },
4647
- async pickListGet({ list_id }) {
4648
- return callDoor(DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
4649
- },
4650
- async pickListForSelection({ list_id }) {
4651
- return callDoor(
4652
- DOORS.pickListForSelection,
4653
- { p_list_id: list_id },
4654
- "pickListForSelection"
4655
- );
4656
- },
4657
- async pickListUpdate({ list_id, list_name, description, items }) {
4658
- return callDoor(
4659
- DOORS.pickListUpdate,
4660
- {
4661
- p_list_id: list_id,
4662
- p_list_name: list_name ?? null,
4663
- p_description: description ?? null,
4664
- p_items: items ? [...items] : null
4665
- },
4666
- "pickListUpdate"
4667
- );
4668
- },
4716
+ ...createPickListDoors(callDoor),
4669
4717
  async fieldChoiceUsage({ field_id }) {
4670
4718
  const result = await callDoor(
4671
4719
  DOORS.fieldChoiceUsage,
@@ -7199,11 +7247,7 @@ function createRecordsClient(given) {
7199
7247
  );
7200
7248
  },
7201
7249
  async scopeTableProvision({ home_id, item_id, scope_id }) {
7202
- return callDoor(
7203
- DOORS.scopeTableProvision,
7204
- { p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
7205
- "scopeTableProvision"
7206
- );
7250
+ return scopes.tableProvision({ organization_id: org, item_id, scope_id, home_id: home_id ?? null });
7207
7251
  },
7208
7252
  async tableRowCounts({ table_ids }) {
7209
7253
  return callDoor(