@ai-matrx/records 0.99.32 → 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 (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
@@ -0,0 +1,1287 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/door-call/index.ts
21
+ var door_call_exports = {};
22
+ __export(door_call_exports, {
23
+ A_PERSONS_REFUSAL: () => A_PERSONS_REFUSAL,
24
+ DEFAULT_DOOR_SCHEMA: () => DEFAULT_DOOR_SCHEMA,
25
+ PICK_LIST_DOORS: () => PICK_LIST_DOORS,
26
+ STORE_SCHEMA: () => STORE_SCHEMA,
27
+ asRecordsDataSource: () => asRecordsDataSource,
28
+ canonicalArgs: () => canonicalArgs,
29
+ createDoorCall: () => createDoorCall,
30
+ createPickListDoors: () => createPickListDoors,
31
+ createScopeDoors: () => createScopeDoors,
32
+ describeBulkFailures: () => describeBulkFailures,
33
+ doorAbsentRefusal: () => doorAbsentRefusal,
34
+ isAPersonsRefusal: () => isAPersonsRefusal,
35
+ isBulkOpError: () => isBulkOpError,
36
+ isServiceFailure: () => isServiceFailure,
37
+ lightDoorCall: () => lightDoorCall,
38
+ lightPickListDoors: () => lightPickListDoors,
39
+ lightScopeDoors: () => lightScopeDoors,
40
+ primedDoorAnswer: () => primedDoorAnswer,
41
+ readObjectOrganizationAnswer: () => readObjectOrganizationAnswer,
42
+ recordsErrorSink: () => recordsErrorSink,
43
+ resolveObjectOrganization: () => resolveObjectOrganization,
44
+ storeDoors: () => storeDoors,
45
+ supabaseDataSource: () => supabaseDataSource
46
+ });
47
+ module.exports = __toCommonJS(door_call_exports);
48
+
49
+ // src/core/supabase.ts
50
+ function refuse(code, message, hint) {
51
+ return { data: null, error: { code, message, hint, details: "" } };
52
+ }
53
+ function supabaseDataSource(client) {
54
+ if (isBound(client)) return client;
55
+ const supabase = client;
56
+ const hasSchema = typeof supabase.schema === "function";
57
+ const bound = {
58
+ // PAGE-BUNDLE: the real adapter opens a table page with one `custom.table_page_bundle` call.
59
+ opensInOneCall: true,
60
+ rpc(fn, args, options) {
61
+ if (!hasSchema) {
62
+ return Promise.resolve(
63
+ refuse(
64
+ "data_source_unbound",
65
+ `The records client was given something that is not a supabase client: it has no schema() method, so the door ${fn} cannot be called in the schema it lives in.`,
66
+ "Pass a supabase-js v2 client (createClient(...)) to supabaseDataSource()."
67
+ )
68
+ );
69
+ }
70
+ const name = options?.schema;
71
+ if (!name) {
72
+ return Promise.resolve(
73
+ refuse(
74
+ "schema_unsaid",
75
+ `The door ${fn} was called without saying which schema it lives in. Every door of this store is custom.${fn} and every trust door is iam.${fn}; an unqualified call reaches PostgREST's default profile (public) and is refused there.`,
76
+ "This is a bug in the caller, not in your data: /core says the schema on every call."
77
+ )
78
+ );
79
+ }
80
+ return supabase.schema(name).rpc(fn, args);
81
+ },
82
+ schema(name) {
83
+ return supabase.schema(name);
84
+ }
85
+ };
86
+ Object.defineProperty(bound, BOUND, { value: true, enumerable: false });
87
+ return bound;
88
+ }
89
+ var BOUND = /* @__PURE__ */ Symbol.for("@ai-matrx/records/supabaseDataSource");
90
+ function isBound(source) {
91
+ return source[BOUND] === true;
92
+ }
93
+ function asRecordsDataSource(source) {
94
+ if (source === null || typeof source !== "object") return supabaseDataSource({});
95
+ if (isBound(source)) return source;
96
+ const candidate = source;
97
+ const looksLikeSupabaseJs = typeof candidate.schema === "function" && typeof candidate.from === "function" && candidate.auth !== null && typeof candidate.auth === "object";
98
+ if (looksLikeSupabaseJs || typeof candidate.rpc !== "function") return supabaseDataSource(source);
99
+ return source;
100
+ }
101
+
102
+ // src/results.ts
103
+ var ok = (data) => ({ ok: true, data });
104
+ var err = (error) => ({ ok: false, error });
105
+
106
+ // src/core/pgError.ts
107
+ var BY_SQLSTATE = {
108
+ PT409: "stale_write",
109
+ "42501": "door",
110
+ "23514": "refused_by_rule",
111
+ "22004": "invalid_argument",
112
+ "22023": "invalid_argument",
113
+ // MX005 — a value the store cannot take as asked: since 2026-10-06 (AP-3 U3) a word that names more than one
114
+ // choice or linked record raises it (it used to borrow PT409 and read as somebody else's write winning).
115
+ MX005: "invalid_argument",
116
+ // MXD01 — the held-change door tried the proposed values before filing an
117
+ // approval request and the store refused them. Nothing is waiting for a
118
+ // person to decide; correct the value before asking again, which is the same
119
+ // caller-side condition as the other invalid-argument refusals.
120
+ MXD01: "invalid_argument",
121
+ // 22P02 — a value does not fit the type the store holds for it. The class is
122
+ // real and was hit live: an organization whose copy of a package table grew
123
+ // `status` as a uuid-valued Field was sent the text "open", and the store
124
+ // answered `invalid input syntax for type uuid: "open"`. It is the CALL that
125
+ // is wrong for the shape the store holds, which is what `invalid_argument`
126
+ // already means — the store's own sentence names the value and the type.
127
+ "22P02": "invalid_argument",
128
+ // 42703 — a column that is not there. The store raises it from
129
+ // `custom.entity_table`, which is asked for a column by NAME, so the class is
130
+ // exactly "the call named something the shape does not have": the same thing
131
+ // `invalid_argument` already means, and the store's own sentence names the
132
+ // column. Added 2026-09-20 (lane FORMS) because the package's live-door suite
133
+ // caught it raised by a door this package did not know about — which is the
134
+ // suite working, and is why the map is a census rather than a guess.
135
+ "42703": "invalid_argument",
136
+ // 22007 — a date or a time the store could not read as one. It is raised by
137
+ // `custom.dashboard_window_sql`, which is handed a window a caller wrote
138
+ // ("last 30 days", a literal date), so the class is again "the call named
139
+ // something the shape does not accept" and the store's own sentence names the
140
+ // text it could not read. Added 2026-09-20 (lane SCREEN-BREAK) after the
141
+ // live-door census caught it — the same way 42703 arrived, which is the
142
+ // census working rather than a guess.
143
+ "22007": "invalid_argument",
144
+ // 22003 — a number the store could not hold at the size it was handed. It is
145
+ // raised by `custom.context_resolve`, which is given a window or a depth a
146
+ // caller wrote, so the class is the same one 22P02, 42703 and 22007 already
147
+ // are: the CALL named a value the shape does not accept, and the store's own
148
+ // sentence names the number and the range. Added 2026-09-20 (lane GRID-TWO)
149
+ // when the live-door census caught the release gate red on it — which is the
150
+ // census working, and the fourth time it has been the thing that found a new
151
+ // refusal class rather than a person guessing one.
152
+ "22003": "invalid_argument",
153
+ // 42883 — `custom._template_call` (the template family, 2026-10-03) was handed a step that
154
+ // names a door the store does not have, or an argument that door does not take. The TEMPLATE
155
+ // named something the shape does not have — the same class 42703 is — and the store's own
156
+ // sentence names the door or the argument. Caught by the live-door census on records 0.68.1's
157
+ // tag, the eighth time the census found a class before a person did. (A bare 42883 on a door
158
+ // this package itself asks for is still `door_absent`, mapped before this funnel in
159
+ // `owedDoor`.)
160
+ "42883": "invalid_argument",
161
+ "02000": "not_found",
162
+ // P0002 — `custom.inbox_snooze` / `custom.inbox_clear` (lane S5-PRIME-2, 2026-09-24): "There is
163
+ // nothing in your inbox with that id". An invented id, another person's item and another
164
+ // organization's all answer it alike, so it reads exactly as 02000 does: not found.
165
+ "P0002": "not_found",
166
+ "23503": "missing_reference",
167
+ "23505": "already_exists",
168
+ "0A000": "not_supported",
169
+ "53400": "store_limit",
170
+ "22012": "store_limit",
171
+ // 54001 — `custom.record_delete` stops a cascade that nests past sixty-four
172
+ // levels of containment, because that is a loop somebody built rather than a
173
+ // hierarchy, and saying so beats recursing until the server runs out of
174
+ // stack. It is a LIMIT of the store, and the store's own sentence names what
175
+ // to do about it, so it reads as one.
176
+ "54001": "store_limit",
177
+ // 54000 — the grid primitives' organization ceilings (GRID-PRIMITIVES, 2026-09-23):
178
+ // `custom.action_run` on a selection past its knob, `custom.table_decorate` past the
179
+ // rule count, `custom.table_from_example` past `custom/example_rows_max`,
180
+ // `custom.table_webhook_declare` past `custom/table_webhooks_max`, and
181
+ // `custom.hub_changed_by`. Each names its knob in the hint and writes nothing, so it
182
+ // reads exactly like 54001: a limit of the store, in the store's own sentence.
183
+ "54000": "store_limit",
184
+ // VIS: `custom.has_visibility_at` refuses to answer from a snapshot older
185
+ // than a write this reader has already seen, rather than returning something
186
+ // they just lost access to. It is retryable on a fresher connection, which is
187
+ // a different instruction from every other refusal here.
188
+ // 55000 — `custom.table_move` (SC-1', 2026-09-24) refuses a move the table's present state
189
+ // does not allow: a destination that cannot take it, a table something else holds, contents
190
+ // that point at themselves in a circle. The store's own sentence names the reason and nothing
191
+ // moves, so it reads as a refusal on the merits. Caught by the live-door census on records
192
+ // 0.58.3's tag, the seventh time the census found a class before a person did.
193
+ "55000": "refused_by_rule",
194
+ // 42P17 — a worked-out column that would read itself round a circle (STORE-TAILS-3,
195
+ // 2026-09-25): `custom._field_reads_what_it_reads` refuses the declaration or edit that would
196
+ // close the circle, naming every column in it, and `custom.far_value` refuses a circle stored
197
+ // before that rule when a lookup or rollup is worked out. Refused on its merits, in the store's
198
+ // own sentence, nothing written — so it reads as 55000 does.
199
+ "42P17": "refused_by_rule",
200
+ // P0001 — `custom.context_scope_write` (2026-10-03) refuses a scope whose parent breaks the
201
+ // parent rule in the old trigger's own class and words (manager ruling H6). Refused on its
202
+ // merits, nothing written. Caught by the live-door census on records 0.65.0's tag.
203
+ P0001: "refused_by_rule",
204
+ "40001": "stale_read",
205
+ // 57014 — the store cancelled the statement at its own timeout. Like
206
+ // `stale_read` and unlike every other refusal here, the call was never
207
+ // refused on its merits: the same call on a smaller page, or once the
208
+ // organization's kernel is not being rewritten, can succeed. It gets its own
209
+ // code so a screen can offer "try again" honestly instead of showing a
210
+ // failure sentence the caller cannot act on.
211
+ "57014": "timed_out",
212
+ // PostgREST's own two: the store is not being SERVED, which is a different
213
+ // thing from the store refusing. `custom` absent from `pgrst.db_schemas`, or
214
+ // the grants not copied, land here.
215
+ PGRST202: "store_not_served",
216
+ PGRST205: "store_not_served",
217
+ PGRST301: "door",
218
+ // PT428 — NOT A FAILURE, and the release gate's live census is what found it
219
+ // missing: the store raises it and this package answered `internal`, which is
220
+ // the one classification that tells a screen nothing. A stage gate whose
221
+ // `on_fail` is `require_approval` files the request and leaves the record
222
+ // where it was; the transaction is rolled back to the pipeline's own block, so
223
+ // "nothing was written" is a fact rather than a promise. Landed by lane
224
+ // STAGE-RULES; mapped here by STAGE-RULES-2 the day after, when the census
225
+ // caught it — the sixth time that census has been the thing that found a
226
+ // refusal class rather than a person guessing one.
227
+ PT428: "needs_approval"
228
+ };
229
+ var MAPPED_SQLSTATES = Object.keys(BY_SQLSTATE);
230
+ function parseDetail(details) {
231
+ if (!details) return void 0;
232
+ const trimmed = details.trim();
233
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return details;
234
+ try {
235
+ return JSON.parse(trimmed);
236
+ } catch {
237
+ return details;
238
+ }
239
+ }
240
+ function isNotASqlstate(code) {
241
+ if (!code) return true;
242
+ return /^[0-9]{3}$/.test(code);
243
+ }
244
+ function mapPgError(error, where) {
245
+ const raw = error.code ?? void 0;
246
+ const sqlstate = raw && raw !== "" ? raw : void 0;
247
+ const mapped = {
248
+ code: "internal",
249
+ message: error.message,
250
+ ...error.hint ? { hint: error.hint } : {},
251
+ ...sqlstate ? { sqlstate } : {}
252
+ };
253
+ if (isNotASqlstate(sqlstate)) {
254
+ mapped.code = "unreachable";
255
+ } else {
256
+ mapped.code = BY_SQLSTATE[sqlstate] ?? "internal";
257
+ }
258
+ const detail = parseDetail(error.details);
259
+ if (detail !== void 0) mapped.detail = detail;
260
+ if (mapped.code === "internal") {
261
+ mapped.unmapped = true;
262
+ mapped.diagnostic = `@ai-matrx/records did not recognise SQLSTATE ${sqlstate ?? "(none)"} from ${where}; the store's own message is the thing to act on.`;
263
+ } else if (mapped.code === "unreachable") {
264
+ mapped.unmapped = true;
265
+ mapped.diagnostic = `@ai-matrx/records never reached the store from ${where}: ${raw ? `the transport answered ${raw}` : "no response"} \u2014 ${error.message}`;
266
+ mapped.message = "We could not reach your data.";
267
+ delete mapped.hint;
268
+ }
269
+ return mapped;
270
+ }
271
+
272
+ // src/core/primedBundle.ts
273
+ var REGISTRY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/primed-table-page-bundles");
274
+ function registry() {
275
+ const g = globalThis;
276
+ return g[REGISTRY] ??= /* @__PURE__ */ new Map();
277
+ }
278
+ function forgetPrimedTablePageBundlesOf(tableId) {
279
+ const primed = registry();
280
+ for (const key of [...primed.keys()]) if (tableId === null || key.split("|")[1] === tableId) primed.delete(key);
281
+ }
282
+ var DOOR_REGISTRY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/primed-door-answers");
283
+ function doorRegistry() {
284
+ const g = globalThis;
285
+ return g[DOOR_REGISTRY] ??= /* @__PURE__ */ new Map();
286
+ }
287
+ var PRIMED_DOOR_TTL_MS = 1e4;
288
+ function takePrimedDoorAnswer(key) {
289
+ const registry2 = doorRegistry();
290
+ const held = registry2.get(key);
291
+ if (!held) return null;
292
+ if (Date.now() - held.at < PRIMED_DOOR_TTL_MS) return { data: held.data };
293
+ registry2.delete(key);
294
+ return null;
295
+ }
296
+ function dropPrimedDoorAnswers(doors) {
297
+ const registry2 = doorRegistry();
298
+ if (!doors) {
299
+ registry2.clear();
300
+ return;
301
+ }
302
+ for (const key of [...registry2.keys()]) if (doors.some((door) => key.startsWith(`${door}|`))) registry2.delete(key);
303
+ }
304
+ var LOOK_WRITES = {
305
+ view_declare: ["views", "view_look_read", "grid_layout", "table_page_bundle"],
306
+ view_designate: ["views", "view_look_read", "grid_layout", "table_page_bundle"],
307
+ view_look_set: ["views", "view_look_read", "grid_layout", "table_page_bundle"],
308
+ view_record_order_set: ["views", "view_look_read", "grid_layout", "table_page_bundle"]
309
+ };
310
+ function isWritingDoor(door) {
311
+ 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);
312
+ }
313
+
314
+ // src/core/doorCall.ts
315
+ var DEFAULT_DOOR_SCHEMA = "custom";
316
+ function canonicalArgs(value) {
317
+ return JSON.stringify(
318
+ value,
319
+ (_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
320
+ );
321
+ }
322
+ var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
323
+ "refused_by_rule",
324
+ "stale_write",
325
+ "invalid_argument",
326
+ "already_exists",
327
+ "missing_reference"
328
+ ]);
329
+ function isAPersonsRefusal(code) {
330
+ return A_PERSONS_REFUSAL.has(code);
331
+ }
332
+ function recordsErrorSink(onError) {
333
+ return onError ?? ((e) => {
334
+ const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
335
+ if (isAPersonsRefusal(e.code)) console.info(line);
336
+ else console.error(line);
337
+ });
338
+ }
339
+ function doorAbsentRefusal(name, owedBy) {
340
+ return {
341
+ code: "door_absent",
342
+ message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
343
+ 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\`.`
344
+ };
345
+ }
346
+ function primedDoorAnswer(door, args) {
347
+ const look = LOOK_WRITES[door];
348
+ if (look) {
349
+ dropPrimedDoorAnswers(look);
350
+ return null;
351
+ }
352
+ if (isWritingDoor(door)) {
353
+ dropPrimedDoorAnswers();
354
+ return null;
355
+ }
356
+ return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
357
+ }
358
+ function createDoorCall(options) {
359
+ const { dataSource, doorReady, held, wrote } = options;
360
+ const schema = options.schema ?? DEFAULT_DOOR_SCHEMA;
361
+ const scream = recordsErrorSink(options.onError);
362
+ const absent = options.absent ?? ((door) => doorAbsentRefusal(door));
363
+ const readsInFlight = /* @__PURE__ */ new Map();
364
+ const say = (refusal, where) => scream({ code: refusal.code, message: refusal.message, ...refusal.hint ? { hint: refusal.hint } : {}, where });
365
+ return async function callDoor(door, args, where, opts) {
366
+ const primed = primedDoorAnswer(door, args);
367
+ if (primed) return ok(primed.data);
368
+ if (held) {
369
+ const bundled = await held(door, args);
370
+ if (bundled) return ok(bundled.data);
371
+ }
372
+ if (doorReady && !doorReady(door)) {
373
+ const refusal = absent(door);
374
+ say(refusal, where);
375
+ return err(refusal);
376
+ }
377
+ const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
378
+ const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
379
+ const response = await (flying ?? (() => {
380
+ const call = Promise.resolve(dataSource.rpc(`${door}`, args, { schema }));
381
+ if (flightKey) {
382
+ readsInFlight.set(flightKey, call);
383
+ const forget = () => {
384
+ if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
385
+ };
386
+ call.then(forget, forget);
387
+ }
388
+ return call;
389
+ })());
390
+ if (response.error) {
391
+ const code = response.error.code;
392
+ const refusal = !doorReady && (code === "PGRST202" || code === "42883") ? absent(door) : mapPgError(response.error, where);
393
+ if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal.code} - ${refusal.message}`);
394
+ else say(refusal, where);
395
+ return err(refusal);
396
+ }
397
+ if (isWritingDoor(door) || LOOK_WRITES[door]) {
398
+ const tableId = args["p_table_id"];
399
+ wrote?.(door, args);
400
+ forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
401
+ dropPrimedDoorAnswers(LOOK_WRITES[door]);
402
+ }
403
+ return ok(response.data);
404
+ };
405
+ }
406
+
407
+ // src/core/pickListDoors.ts
408
+ var PICK_LIST_DOORS = {
409
+ pickListGet: "pick_list_get",
410
+ pickListForSelection: "pick_list_for_selection",
411
+ pickListUpdate: "pick_list_update"
412
+ };
413
+ function createPickListDoors(callDoor) {
414
+ return {
415
+ async pickListGet({ list_id }) {
416
+ return callDoor(PICK_LIST_DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
417
+ },
418
+ async pickListForSelection({ list_id }) {
419
+ return callDoor(
420
+ PICK_LIST_DOORS.pickListForSelection,
421
+ { p_list_id: list_id },
422
+ "pickListForSelection"
423
+ );
424
+ },
425
+ async pickListUpdate({ list_id, list_name, description, items }) {
426
+ return callDoor(
427
+ PICK_LIST_DOORS.pickListUpdate,
428
+ {
429
+ p_list_id: list_id,
430
+ p_list_name: list_name ?? null,
431
+ p_description: description ?? null,
432
+ p_items: items ? [...items] : null
433
+ },
434
+ "pickListUpdate"
435
+ );
436
+ }
437
+ };
438
+ }
439
+
440
+ // src/scopes/types.ts
441
+ var SYSTEM_CONTEXT_TYPE_ID = "__system__";
442
+
443
+ // src/scopes/codec.ts
444
+ var import_uuid = require("@ai-matrx/kit/uuid");
445
+ var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
446
+ var strOrNull = (v) => typeof v === "string" ? v : null;
447
+ var num = (v, fallback = 0) => {
448
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
449
+ return Number.isFinite(n) ? n : fallback;
450
+ };
451
+ function scopeTypeFromStore(row) {
452
+ const singular = row.label_singular ?? row.name ?? "";
453
+ return {
454
+ id: row.id,
455
+ organization_id: row.organization_id,
456
+ label_singular: singular,
457
+ label_plural: row.label_plural ?? singular,
458
+ icon: row.icon ?? "folder",
459
+ color: row.color ?? "",
460
+ slug: row.slug ?? null,
461
+ description: row.description ?? "",
462
+ sort_order: num(row.sort_order),
463
+ max_assignments_per_entity: row.max_assignments_per_entity ?? null,
464
+ default_variable_keys: Array.isArray(row.default_variable_keys) ? row.default_variable_keys : [],
465
+ created_by: row.created_by ?? null,
466
+ created_at: row.created_at ?? "",
467
+ updated_at: row.updated_at ?? ""
468
+ };
469
+ }
470
+ function scopeTypeLabelFromStore(t) {
471
+ const singular = t.label_singular ?? t.name ?? "";
472
+ return { id: t.id, slug: t.slug ?? null, label_singular: singular, label_plural: t.label_plural ?? singular, icon: t.icon ?? null, color: t.color ?? null };
473
+ }
474
+ function settingFromStore(value) {
475
+ if (!Array.isArray(value)) return value;
476
+ return value.map((el) => {
477
+ if (typeof el !== "string") return el;
478
+ const t = el.trim();
479
+ if (!(t.startsWith("{") && t.endsWith("}")) && !(t.startsWith("[") && t.endsWith("]"))) return el;
480
+ try {
481
+ return JSON.parse(t);
482
+ } catch {
483
+ return el;
484
+ }
485
+ });
486
+ }
487
+ function scopeFromStore(row) {
488
+ const settings = {};
489
+ for (const [k, v] of Object.entries(row.settings ?? {})) settings[k] = settingFromStore(v);
490
+ return {
491
+ id: row.id,
492
+ scope_type_id: row.scope_type_id,
493
+ organization_id: row.organization_id,
494
+ name: row.name ?? "",
495
+ description: row.description ?? "",
496
+ slug: row.slug ?? null,
497
+ sort_order: num(row.sort_order),
498
+ parent_scope_id: row.parent_scope_id ?? null,
499
+ settings,
500
+ created_by: row.created_by ?? null,
501
+ created_at: row.created_at ?? "",
502
+ updated_at: row.updated_at ?? ""
503
+ };
504
+ }
505
+ function scopeWithTypeFromStore(row) {
506
+ return { ...scopeFromStore(row), scope_type: row.scope_type ? scopeTypeLabelFromStore(row.scope_type) : null };
507
+ }
508
+ function archivedScopeTypeFromStore(row) {
509
+ const singular = row.label_singular ?? "";
510
+ return {
511
+ id: row.id,
512
+ organization_id: row.organization_id,
513
+ label_singular: singular,
514
+ label_plural: row.label_plural ?? singular,
515
+ icon: row.icon ?? "folder",
516
+ color: row.color ?? "",
517
+ archived_at: row.deleted_at ?? "",
518
+ created_by: row.created_by ?? null,
519
+ archived_scope_count: row.archived_scope_count ?? 0
520
+ };
521
+ }
522
+ var FILE_KERNEL_ID = "11111111-0000-4000-8000-000000000006";
523
+ var KINDS = /* @__PURE__ */ new Set([
524
+ "string",
525
+ "markdown",
526
+ "email",
527
+ "url",
528
+ "phone",
529
+ "color",
530
+ "number",
531
+ "percent",
532
+ "currency",
533
+ "boolean",
534
+ "date",
535
+ "datetime",
536
+ "time",
537
+ "object",
538
+ "array",
539
+ "reference",
540
+ "document"
541
+ ]);
542
+ function contextFieldKind(doc, carried) {
543
+ if (carried?.as_text && carried.value_type && KINDS.has(carried.value_type)) return carried.value_type;
544
+ const behavior = String(doc.type ?? "text");
545
+ const fmt = doc.format ? String(doc.format) : "";
546
+ const shown = doc.display_format && typeof doc.display_format === "object" ? String(doc.display_format.id ?? "") : "";
547
+ const kind = String(doc.config?.kind ?? "");
548
+ const multi = Boolean(doc.multi);
549
+ if (behavior === "boolean") return "boolean";
550
+ if (behavior === "relation") return doc.relation_target === FILE_KERNEL_ID && !multi ? "document" : "reference";
551
+ if (behavior === "range") {
552
+ if (kind === "date") return "date";
553
+ if (kind === "datetime") return "datetime";
554
+ if (fmt === "percent" || fmt === "currency") return fmt;
555
+ return "number";
556
+ }
557
+ if (behavior === "text") {
558
+ if (multi) return "array";
559
+ if (fmt === "json") return "object";
560
+ for (const word of [fmt, shown]) {
561
+ if (word === "time" || word === "email" || word === "url" || word === "phone" || word === "color" || word === "markdown") return word;
562
+ }
563
+ }
564
+ return "string";
565
+ }
566
+ var POLICIES = /* @__PURE__ */ new Set(["include", "on_request", "exclude"]);
567
+ var SENSITIVITIES = /* @__PURE__ */ new Set(["public", "internal", "confidential", "restricted"]);
568
+ function contextFieldFromStore(row) {
569
+ const d = row.data ?? {};
570
+ const key = str(d.key);
571
+ const policy = str(d.context_policy, "include");
572
+ const sensitivity = str(d.sensitivity, "internal");
573
+ return {
574
+ id: row.id,
575
+ scope_type_id: row.scope_type_id,
576
+ organization_id: row.organization_id,
577
+ key,
578
+ label: str(d.label, key),
579
+ description: str(d.description),
580
+ kind: contextFieldKind(d, row.carried),
581
+ type: str(d.type, "text"),
582
+ multi: Boolean(d.multi),
583
+ format: strOrNull(d.format),
584
+ config: d.config ?? {},
585
+ relation_target: strOrNull(d.relation_target),
586
+ // The store's sort counts the scope's own two columns first (custom._ctx_store_item: + 2).
587
+ sort: Math.max(0, num(d.sort) - 2),
588
+ context_policy: POLICIES.has(policy) ? policy : "include",
589
+ sensitivity: SENSITIVITIES.has(sensitivity) ? sensitivity : "internal",
590
+ source: str(d.source, "manual"),
591
+ status: str(d.status, "active"),
592
+ status_note: strOrNull(d.status_note),
593
+ category: strOrNull(d.category),
594
+ tags: Array.isArray(d.tags) ? d.tags : [],
595
+ max_items: typeof d.max_items === "number" ? d.max_items : 1,
596
+ custom_component: d.custom_component ?? null,
597
+ reference_source: d.reference_source ?? null,
598
+ allowed_scope_type_ids: Array.isArray(d.allowed_scope_type_ids) ? d.allowed_scope_type_ids : null,
599
+ allowed_reference_types: Array.isArray(d.allowed_reference_types) ? d.allowed_reference_types : null,
600
+ review_interval_days: typeof d.review_interval_days === "number" ? d.review_interval_days : null,
601
+ depends_on: Array.isArray(d.depends_on) ? d.depends_on : [],
602
+ version: num(row.version, 1),
603
+ created_by: row.created_by ?? null,
604
+ created_at: row.created_at ?? "",
605
+ updated_at: row.updated_at ?? ""
606
+ };
607
+ }
608
+ var POLICY_TO_DOOR = { include: "always", on_request: "on_demand", exclude: "never" };
609
+ var SENSITIVITY_TO_DOOR = {
610
+ public: "public",
611
+ internal: "internal",
612
+ confidential: "restricted",
613
+ restricted: "privileged"
614
+ };
615
+ var SENSITIVITY_FROM_DOOR = {
616
+ public: "public",
617
+ internal: "internal",
618
+ restricted: "confidential",
619
+ privileged: "restricted"
620
+ };
621
+ function systemContextFieldFromStore(row, index) {
622
+ const key = str(row.key);
623
+ const kind = str(row.value_type, "string");
624
+ return {
625
+ id: str(row.id),
626
+ scope_type_id: SYSTEM_CONTEXT_TYPE_ID,
627
+ organization_id: "",
628
+ key,
629
+ label: str(row.display_name, key),
630
+ description: str(row.description),
631
+ kind: KINDS.has(kind) ? kind : "string",
632
+ type: "system",
633
+ multi: kind === "array",
634
+ format: null,
635
+ config: {},
636
+ relation_target: null,
637
+ sort: typeof row.sort_order === "number" ? row.sort_order : index,
638
+ context_policy: "include",
639
+ // The system table keeps the old sensitivity words (`restricted`/`privileged`), like the write doors.
640
+ sensitivity: SENSITIVITY_FROM_DOOR[str(row.sensitivity)] ?? "public",
641
+ source: "system",
642
+ status: "active",
643
+ status_note: null,
644
+ category: null,
645
+ tags: [],
646
+ max_items: 0,
647
+ custom_component: null,
648
+ reference_source: null,
649
+ allowed_scope_type_ids: null,
650
+ allowed_reference_types: null,
651
+ review_interval_days: null,
652
+ depends_on: [],
653
+ version: 0,
654
+ created_by: null,
655
+ created_at: "",
656
+ updated_at: "",
657
+ item_class: strOrNull(row.item_class)
658
+ };
659
+ }
660
+ function referencesOf(row) {
661
+ const v = row.value;
662
+ const list = Array.isArray(v) ? v : v == null ? [] : [v];
663
+ const labels = row.labels ?? {};
664
+ const files = row.files ?? {};
665
+ const toFile = row.field?.relation_target === FILE_KERNEL_ID;
666
+ const out = [];
667
+ for (const el of list) {
668
+ let ref = null;
669
+ if (typeof el === "string" && (0, import_uuid.isUuidShape)(el)) ref = { id: el, type: toFile ? "file" : "scope" };
670
+ else if (el && typeof el === "object" && typeof el.id === "string") {
671
+ const token = String(el.token ?? "");
672
+ const own = el.label;
673
+ ref = { id: el.id, type: token === "dataset" ? "table" : token || (toFile ? "file" : "scope") };
674
+ if (typeof own === "string" && own) ref.label = own;
675
+ }
676
+ if (!ref) continue;
677
+ const label = labels[ref.id];
678
+ if (label) ref.label = label;
679
+ const fileId = files[ref.id];
680
+ if (fileId) ref.file_id = fileId;
681
+ out.push(ref);
682
+ }
683
+ return out;
684
+ }
685
+ function contextValueFromStore(row) {
686
+ const kind = contextFieldKind(row.field ?? {}, row.field?.carried);
687
+ const carriedText = Boolean(row.field?.carried?.as_text);
688
+ const isRef = !carriedText && (kind === "reference" || kind === "document");
689
+ return {
690
+ scope_id: row.scope_id,
691
+ field_id: row.context_item_id,
692
+ key: row.key,
693
+ kind,
694
+ value: row.value ?? null,
695
+ references: isRef ? referencesOf(row) : [],
696
+ version: num(row.version, 1),
697
+ set_at: row.set_at ?? null,
698
+ source_type: row.source_type ?? null,
699
+ authored_by: row.authored_by ?? null,
700
+ whole_value: row.whole_value ?? null,
701
+ incomplete: null
702
+ };
703
+ }
704
+ async function sha256Hex(text) {
705
+ const subtle = globalThis.crypto?.subtle;
706
+ if (!subtle) return null;
707
+ const digest = await subtle.digest("SHA-256", new TextEncoder().encode(text));
708
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
709
+ }
710
+ async function completeWholeValues(values, read) {
711
+ const texts = /* @__PURE__ */ new Map();
712
+ await Promise.all(
713
+ values.map(async (cell) => {
714
+ const w = cell.whole_value;
715
+ if (!w || w.in_value || typeof cell.value !== "string") return;
716
+ const head = cell.value;
717
+ const chars = typeof w.chars === "number" ? w.chars : null;
718
+ const incomplete = (fileId, why) => {
719
+ cell.incomplete = { head, chars, file_id: fileId, why };
720
+ };
721
+ if (!w.file_id) return incomplete(null, "The rest of this text is still being saved.");
722
+ if (!read) return incomplete(w.file_id, "This place cannot open the file that holds the whole text.");
723
+ if (!texts.has(w.file_id)) texts.set(w.file_id, read(w.file_id));
724
+ try {
725
+ const text = await texts.get(w.file_id);
726
+ if (chars !== null && [...text].length !== chars) {
727
+ return incomplete(w.file_id, `The file holds ${[...text].length} characters, not ${chars}.`);
728
+ }
729
+ if (w.sha256) {
730
+ const sha = await sha256Hex(text);
731
+ if (sha === null) return incomplete(w.file_id, "This browser cannot check the file.");
732
+ if (sha !== w.sha256) return incomplete(w.file_id, "The file's content is not the text the cell points at.");
733
+ }
734
+ cell.value = text;
735
+ } catch (thrown) {
736
+ incomplete(w.file_id, thrown instanceof Error ? thrown.message : String(thrown));
737
+ }
738
+ })
739
+ );
740
+ }
741
+ function definedOnly(fields) {
742
+ const out = {};
743
+ for (const [k, v] of Object.entries(fields)) if (v !== void 0) out[k] = v;
744
+ return out;
745
+ }
746
+ function fieldSpecForDoor(spec) {
747
+ return definedOnly({
748
+ key: spec.key,
749
+ display_name: spec.label,
750
+ value_type: spec.kind,
751
+ description: spec.description,
752
+ category: spec.category,
753
+ fetch_hint: spec.context_policy ? POLICY_TO_DOOR[spec.context_policy] : void 0,
754
+ sensitivity: spec.sensitivity ? SENSITIVITY_TO_DOOR[spec.sensitivity] : void 0,
755
+ tags: spec.tags,
756
+ sort_order: spec.sort,
757
+ status: spec.status,
758
+ status_note: spec.status_note,
759
+ custom_component: spec.custom_component,
760
+ review_interval_days: spec.review_interval_days,
761
+ allowed_reference_types: spec.allowed_reference_types,
762
+ max_items: spec.max_items,
763
+ allowed_scope_type_ids: spec.allowed_scope_type_ids,
764
+ reference_source: spec.reference_source
765
+ });
766
+ }
767
+ function referenceFence(references) {
768
+ const kinds = [...new Set(references.map((r) => r.type))];
769
+ const type = kinds.length === 1 ? kinds[0] : "mixed";
770
+ const items = references.map((r) => {
771
+ if (r.type === "file" && r.file_id) return r.label ? { file_id: r.file_id, label: r.label } : { file_id: r.file_id };
772
+ const item = { id: r.id };
773
+ if (r.label) item.label = r.label;
774
+ if (kinds.length > 1) item.type = r.type;
775
+ return item;
776
+ });
777
+ return "```matrx\n" + JSON.stringify({ matrx_version: 1, kind: "reference", type, items }, null, 2) + "\n```";
778
+ }
779
+ function valuePayloadForDoor(write) {
780
+ const base = definedOnly({
781
+ scope_id: write.scope_id,
782
+ context_item_id: write.field_id,
783
+ source_type: write.source_type,
784
+ change_summary: write.change_summary
785
+ });
786
+ const v = write.value;
787
+ if (write.kind === "reference" || write.kind === "document") {
788
+ if (write.references) return { ...base, value_text: write.references.length ? referenceFence(write.references) : null };
789
+ if (write.kind === "document" && typeof v === "string") return { ...base, value_document_url: v || null };
790
+ return { ...base, value_text: typeof v === "string" ? v || null : null };
791
+ }
792
+ if (v === null || v === void 0 || v === "") {
793
+ return { ...base, value_text: null };
794
+ }
795
+ switch (write.kind) {
796
+ case "number":
797
+ case "percent":
798
+ return typeof v === "number" ? { ...base, value_number: v } : { ...base, value_text: String(v) };
799
+ case "currency":
800
+ return typeof v === "object" ? { ...base, value_json: v } : typeof v === "number" ? { ...base, value_number: v } : { ...base, value_text: String(v) };
801
+ case "boolean":
802
+ return typeof v === "boolean" ? { ...base, value_boolean: v } : { ...base, value_text: String(v) };
803
+ case "date":
804
+ return { ...base, value_date: String(v) };
805
+ case "datetime":
806
+ return { ...base, value_timestamp: String(v) };
807
+ case "time":
808
+ return { ...base, value_time: String(v) };
809
+ case "object":
810
+ case "array":
811
+ return typeof v === "object" ? { ...base, value_json: v } : { ...base, value_text: String(v) };
812
+ default:
813
+ return typeof v === "object" ? { ...base, value_json: v } : { ...base, value_text: String(v) };
814
+ }
815
+ }
816
+
817
+ // src/scopes/rules.ts
818
+ function toSlug(name) {
819
+ return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
820
+ }
821
+ function isValidSlug(s) {
822
+ return /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(s);
823
+ }
824
+ var RESERVED_SCOPE_SLUGS = /* @__PURE__ */ new Set(["context-items", "scopes", "edit", "manage", "new", "settings"]);
825
+ function isReservedSlug(s) {
826
+ return RESERVED_SCOPE_SLUGS.has(s.toLowerCase().replace(/_/g, "-"));
827
+ }
828
+ function resolveSlug(supplied, fallbackName) {
829
+ const slug = supplied?.trim() || toSlug(fallbackName);
830
+ if (!slug || !isValidSlug(slug)) {
831
+ return {
832
+ ok: false,
833
+ error: { code: "invalid_argument", message: "Use letters, numbers and single hyphens for the short name." }
834
+ };
835
+ }
836
+ if (isReservedSlug(slug)) {
837
+ return { ok: false, error: { code: "invalid_argument", message: `"${slug}" is a page name here. Pick another short name.` } };
838
+ }
839
+ return { ok: true, data: slug };
840
+ }
841
+
842
+ // src/scopes/doors.ts
843
+ var FIELD_KERNEL_ID = "11111111-0000-4000-8000-000000000002";
844
+ var SCOPES_PER_CALL = 500;
845
+ var SCOPE_TYPES_PER_FIELDS_CALL = 100;
846
+ var SCOPES_PER_VALUES_CALL = 200;
847
+ var TYPE_SCOPES_PAGE = 200;
848
+ var ARCHIVED_SCOPES_PAGE = 200;
849
+ var uniq = (ids) => [...new Set(ids.filter(Boolean))];
850
+ async function inBatches(ids, size, call) {
851
+ const unique = uniq(ids);
852
+ const batches = [];
853
+ for (let i = 0; i < unique.length; i += size) batches.push(unique.slice(i, i + size));
854
+ const answers = await Promise.all(batches.map(call));
855
+ const out = [];
856
+ for (const a of answers) {
857
+ if (!a.ok) return a;
858
+ out.push(...a.data ?? []);
859
+ }
860
+ return { ok: true, data: out };
861
+ }
862
+ function noRow(door) {
863
+ return { ok: false, error: { code: "internal", message: `${door} answered without the row it wrote.`, diagnostic: `@ai-matrx/records/scopes: ${door}` } };
864
+ }
865
+ var VALUE_DOOR_CODES = {
866
+ unauthorized: "door",
867
+ forbidden: "door",
868
+ forbidden_org: "door",
869
+ not_found: "not_found",
870
+ invalid_argument: "invalid_argument",
871
+ conflict: "stale_write",
872
+ unavailable: "not_supported"
873
+ };
874
+ function createScopeDoors(call) {
875
+ async function write(door, args) {
876
+ const res = await call(door, args, `scopes.${door}`);
877
+ if (!res.ok) return res;
878
+ const row = res.data?.row;
879
+ if (!row || typeof row !== "object") return noRow(door);
880
+ return { ok: true, data: row };
881
+ }
882
+ async function archiveOrRestore(door, args, id) {
883
+ const res = await call(door, args, `scopes.${door}`);
884
+ return res.ok ? { ok: true, data: { id } } : res;
885
+ }
886
+ async function fieldById(scopeTypeId, fieldId, door) {
887
+ const fields = await doors.fields([scopeTypeId]);
888
+ if (!fields.ok) return fields;
889
+ const field = fields.data.find((f) => f.id === fieldId);
890
+ return field ? { ok: true, data: field } : noRow(door);
891
+ }
892
+ const doors = {
893
+ async tree(organizationIds) {
894
+ const ids = uniq(organizationIds);
895
+ if (ids.length === 0) return { ok: true, data: [] };
896
+ const res = await call("context_tree", { p_organization_ids: ids }, "scopes.tree");
897
+ if (!res.ok) return res;
898
+ const byType = /* @__PURE__ */ new Map();
899
+ for (const s of res.data?.scopes ?? []) {
900
+ const scope = scopeFromStore(s);
901
+ const list = byType.get(scope.scope_type_id) ?? [];
902
+ list.push(scope);
903
+ byType.set(scope.scope_type_id, list);
904
+ }
905
+ return { ok: true, data: (res.data?.types ?? []).map((t) => ({ ...scopeTypeFromStore(t), scopes: byType.get(t.id) ?? [] })) };
906
+ },
907
+ async types(organizationIds, options) {
908
+ const withCounts = options?.withCounts ?? true;
909
+ const ids = uniq(organizationIds);
910
+ if (ids.length === 0) return { ok: true, data: { types: [], counts: withCounts ? {} : null } };
911
+ const res = await call("context_tree_types", { p_organization_ids: ids, p_with_counts: withCounts }, "scopes.types");
912
+ if (!res.ok) return res;
913
+ const rows = res.data?.types ?? [];
914
+ const counts = withCounts ? {} : null;
915
+ if (counts) for (const r of rows) counts[r.id] = Number(r.scope_count ?? 0);
916
+ return { ok: true, data: { types: rows.map(scopeTypeFromStore), counts } };
917
+ },
918
+ async typeScopesPage(scopeTypeId, offset = 0, limit = TYPE_SCOPES_PAGE) {
919
+ const res = await call(
920
+ "context_tree_type_scopes",
921
+ { p_scope_type_id: scopeTypeId, p_offset: offset, p_limit: limit },
922
+ "scopes.typeScopesPage"
923
+ );
924
+ if (!res.ok) return res;
925
+ return {
926
+ ok: true,
927
+ data: { scopes: (res.data?.scopes ?? []).map(scopeFromStore), total: Number(res.data?.total ?? 0), next_offset: res.data?.next_offset ?? null }
928
+ };
929
+ },
930
+ async search(organizationIds, query, limit = 100) {
931
+ const ids = uniq(organizationIds);
932
+ const q = query.trim();
933
+ if (ids.length === 0 || q === "") return { ok: true, data: { scopes: [], total: 0 } };
934
+ const res = await call(
935
+ "context_tree_search",
936
+ { p_organization_ids: ids, p_query: q, p_limit: limit },
937
+ "scopes.search"
938
+ );
939
+ if (!res.ok) return res;
940
+ return { ok: true, data: { scopes: (res.data?.scopes ?? []).map(scopeFromStore), total: Number(res.data?.total ?? 0) } };
941
+ },
942
+ async scopes(ids) {
943
+ const res = await inBatches(ids, SCOPES_PER_CALL, (batch) => call("context_scopes", { p_scope_ids: batch }, "scopes.scopes"));
944
+ return res.ok ? { ok: true, data: res.data.map(scopeWithTypeFromStore) } : res;
945
+ },
946
+ async fields(scopeTypeIds) {
947
+ const res = await inBatches(
948
+ scopeTypeIds,
949
+ SCOPE_TYPES_PER_FIELDS_CALL,
950
+ (batch) => call("context_items", { p_scope_type_ids: batch }, "scopes.fields")
951
+ );
952
+ return res.ok ? { ok: true, data: res.data.map(contextFieldFromStore) } : res;
953
+ },
954
+ async field(fieldId, organizationIds) {
955
+ const orgs = uniq(organizationIds);
956
+ const answers = await Promise.all(
957
+ orgs.map(
958
+ (org) => call(
959
+ "read_records_by_ids",
960
+ { p_organization_id: org, p_table_id: FIELD_KERNEL_ID, p_record_ids: [fieldId], p_by_id: false },
961
+ "scopes.field"
962
+ )
963
+ )
964
+ );
965
+ let refusal = null;
966
+ for (const answer of answers) {
967
+ if (!answer.ok) {
968
+ refusal ??= answer;
969
+ continue;
970
+ }
971
+ const typeId = answer.data?.find((r) => r.id === fieldId)?.document?.entity_definition_id;
972
+ if (typeof typeId !== "string") continue;
973
+ const fields = await doors.fields([typeId]);
974
+ if (!fields.ok) return fields;
975
+ const field = fields.data.find((f) => f.id === fieldId);
976
+ if (field) return { ok: true, data: field };
977
+ }
978
+ return refusal ?? {
979
+ ok: false,
980
+ error: { code: "not_found", message: "This context field could not be found.", diagnostic: `@ai-matrx/records/scopes: field ${fieldId}` }
981
+ };
982
+ },
983
+ async values(scopeIds, options) {
984
+ const res = await inBatches(
985
+ scopeIds,
986
+ SCOPES_PER_VALUES_CALL,
987
+ (batch) => call("context_values", { p_scope_ids: batch }, "scopes.values")
988
+ );
989
+ if (!res.ok) return res;
990
+ const cells = res.data.map(contextValueFromStore);
991
+ await completeWholeValues(cells, options?.readFileText ?? null);
992
+ return { ok: true, data: cells };
993
+ },
994
+ async archivedTypes(organizationId) {
995
+ const res = await call("context_archived_types", { p_organization_id: organizationId }, "scopes.archivedTypes");
996
+ return res.ok ? { ok: true, data: (res.data ?? []).map(archivedScopeTypeFromStore) } : res;
997
+ },
998
+ async archivedScopesOfType(organizationId, scopeTypeId, wanted) {
999
+ const out = [];
1000
+ for (let offset = 0; out.length < wanted.size; offset += ARCHIVED_SCOPES_PAGE) {
1001
+ const res = await call(
1002
+ "read_records_archived",
1003
+ { p_organization_id: organizationId, p_table_id: scopeTypeId, p_lane: "org", p_by_id: false, p_limit: ARCHIVED_SCOPES_PAGE, p_offset: offset },
1004
+ "scopes.archivedScopesOfType"
1005
+ );
1006
+ if (!res.ok) return res;
1007
+ const rows = res.data ?? [];
1008
+ for (const r of rows) {
1009
+ if (!wanted.has(r.id)) continue;
1010
+ out.push({
1011
+ id: r.id,
1012
+ name: typeof r.document?.name === "string" ? r.document.name : null,
1013
+ slug: typeof r.document?.slug === "string" ? r.document.slug : null,
1014
+ archived_at: r.archived_at ?? null
1015
+ });
1016
+ }
1017
+ if (rows.length < ARCHIVED_SCOPES_PAGE) break;
1018
+ }
1019
+ return { ok: true, data: out };
1020
+ },
1021
+ async systemItems() {
1022
+ const res = await call("context_system_items", {}, "scopes.systemItems");
1023
+ return res.ok ? { ok: true, data: (res.data ?? []).map(systemContextFieldFromStore) } : res;
1024
+ },
1025
+ async tableTemplates(organizationId) {
1026
+ const res = await call("table_templates", { p_org_id: organizationId }, "scopes.tableTemplates");
1027
+ return res.ok ? { ok: true, data: Array.isArray(res.data) ? res.data : [] } : res;
1028
+ },
1029
+ async templates() {
1030
+ const res = await call("context_templates", {}, "scopes.templates");
1031
+ return res.ok ? { ok: true, data: res.data ?? [] } : res;
1032
+ },
1033
+ async createType(organizationId, spec) {
1034
+ const slug = resolveSlug(spec.slug, spec.label_plural || spec.label_singular || "");
1035
+ if (!slug.ok) return slug;
1036
+ const res = await write("context_type_write", {
1037
+ p_organization_id: organizationId,
1038
+ p_type_id: null,
1039
+ p_spec: definedOnly({
1040
+ label_singular: spec.label_singular,
1041
+ label_plural: spec.label_plural,
1042
+ icon: spec.icon ?? "folder",
1043
+ description: spec.description ?? "",
1044
+ sort_order: spec.sort_order ?? 0,
1045
+ max_assignments: spec.max_assignments_per_entity ?? void 0,
1046
+ default_variable_keys: spec.default_variable_keys ?? [],
1047
+ color: spec.color,
1048
+ slug: slug.data
1049
+ })
1050
+ });
1051
+ return res.ok ? { ok: true, data: scopeTypeFromStore(res.data) } : res;
1052
+ },
1053
+ async updateType(typeId, spec) {
1054
+ let slug;
1055
+ if (spec.slug !== void 0) {
1056
+ const resolved = resolveSlug(spec.slug, spec.label_plural ?? spec.label_singular ?? "");
1057
+ if (!resolved.ok) return resolved;
1058
+ slug = resolved.data;
1059
+ }
1060
+ const res = await write("context_type_write", {
1061
+ p_organization_id: null,
1062
+ p_type_id: typeId,
1063
+ p_spec: definedOnly({
1064
+ label_singular: spec.label_singular,
1065
+ label_plural: spec.label_plural,
1066
+ icon: spec.icon,
1067
+ description: spec.description,
1068
+ sort_order: spec.sort_order,
1069
+ max_assignments: spec.max_assignments_per_entity,
1070
+ color: spec.color,
1071
+ slug
1072
+ })
1073
+ });
1074
+ return res.ok ? { ok: true, data: scopeTypeFromStore(res.data) } : res;
1075
+ },
1076
+ archiveType: (typeId) => archiveOrRestore("context_type_archive", { p_type_id: typeId }, typeId),
1077
+ restoreType: (typeId) => archiveOrRestore("context_type_restore", { p_type_id: typeId }, typeId),
1078
+ async createScope(organizationId, typeId, spec) {
1079
+ const slug = resolveSlug(spec.slug, spec.name ?? "");
1080
+ if (!slug.ok) return slug;
1081
+ const res = await write("context_scope_write", {
1082
+ p_organization_id: organizationId,
1083
+ p_scope_id: null,
1084
+ p_type_id: typeId,
1085
+ p_spec: definedOnly({
1086
+ name: spec.name,
1087
+ parent_scope_id: spec.parent_scope_id,
1088
+ description: spec.description ?? "",
1089
+ settings: spec.settings ?? {},
1090
+ slug: slug.data,
1091
+ sort_order: spec.sort_order
1092
+ })
1093
+ });
1094
+ return res.ok ? { ok: true, data: scopeFromStore(res.data) } : res;
1095
+ },
1096
+ async updateScope(scopeId, spec) {
1097
+ let slug;
1098
+ if (spec.slug !== void 0) {
1099
+ const resolved = resolveSlug(spec.slug, spec.name ?? "");
1100
+ if (!resolved.ok) return resolved;
1101
+ slug = resolved.data;
1102
+ }
1103
+ const res = await write("context_scope_write", {
1104
+ p_organization_id: null,
1105
+ p_scope_id: scopeId,
1106
+ p_type_id: null,
1107
+ p_spec: definedOnly({ name: spec.name, description: spec.description, settings: spec.settings, slug, sort_order: spec.sort_order })
1108
+ });
1109
+ return res.ok ? { ok: true, data: scopeFromStore(res.data) } : res;
1110
+ },
1111
+ archiveScope: (scopeId) => archiveOrRestore("context_scope_archive", { p_scope_id: scopeId }, scopeId),
1112
+ restoreScope: (scopeId) => archiveOrRestore("context_scope_restore", { p_scope_id: scopeId }, scopeId),
1113
+ async createField(scopeTypeId, spec) {
1114
+ const res = await write("context_item_write", {
1115
+ p_item_id: null,
1116
+ p_scope_type_id: scopeTypeId,
1117
+ p_spec: fieldSpecForDoor({ kind: "string", description: "", context_policy: "on_request", sensitivity: "internal", tags: [], ...spec })
1118
+ });
1119
+ if (!res.ok) return res;
1120
+ return fieldById(scopeTypeId, String(res.data.id), "context_item_write");
1121
+ },
1122
+ async updateField(fieldId, scopeTypeId, spec) {
1123
+ const res = await write("context_item_write", { p_item_id: fieldId, p_scope_type_id: null, p_spec: fieldSpecForDoor(spec) });
1124
+ if (!res.ok) return res;
1125
+ return fieldById(scopeTypeId, fieldId, "context_item_write");
1126
+ },
1127
+ archiveField: (fieldId) => archiveOrRestore("context_item_archive", { p_item_id: fieldId }, fieldId),
1128
+ restoreField: (fieldId) => archiveOrRestore("context_item_restore", { p_item_id: fieldId }, fieldId),
1129
+ async writeValue(cell) {
1130
+ const res = await call(
1131
+ "context_value_write",
1132
+ { p_payload: { source_type: "ai_enriched", ...valuePayloadForDoor(cell) } },
1133
+ "scopes.writeValue"
1134
+ );
1135
+ if (!res.ok) return res;
1136
+ const envelope = res.data ?? {};
1137
+ if (!envelope.ok) {
1138
+ const code = VALUE_DOOR_CODES[envelope.error?.code ?? ""] ?? "internal";
1139
+ return { ok: false, error: { code, message: envelope.error?.message ?? "The value was not saved." } };
1140
+ }
1141
+ return {
1142
+ ok: true,
1143
+ data: {
1144
+ scope_id: cell.scope_id,
1145
+ field_id: cell.field_id,
1146
+ version: Number(envelope.data?.version ?? 1),
1147
+ source_type: String(envelope.data?.source_type ?? cell.source_type ?? "ai_enriched")
1148
+ }
1149
+ };
1150
+ },
1151
+ tableProvision({ organization_id, item_id, scope_id, home_id }) {
1152
+ return call(
1153
+ "scope_table_provision",
1154
+ { p_organization_id: organization_id, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
1155
+ "scopeTableProvision"
1156
+ );
1157
+ }
1158
+ };
1159
+ return doors;
1160
+ }
1161
+
1162
+ // src/core/storeDoors.ts
1163
+ var STORE_SCHEMA = "custom";
1164
+ function storeDoors(client) {
1165
+ const source = supabaseDataSource(client ?? {});
1166
+ const call = (fn, args = {}) => source.rpc(fn, args, { schema: STORE_SCHEMA });
1167
+ const typed = (fn, args) => call(fn, args);
1168
+ return {
1169
+ rpc: call,
1170
+ async whereIdOpens(id) {
1171
+ const raw = await call("where_id_opens", { p_id: id });
1172
+ const e = raw.error;
1173
+ return {
1174
+ data: raw.data ?? null,
1175
+ error: e ? { code: typeof e.code === "string" ? e.code : null, message: typeof e.message === "string" ? e.message : "The record store refused." } : null
1176
+ };
1177
+ },
1178
+ tableKernelId: () => typed("table_kernel_id", {}),
1179
+ readRecordsByIds: (organizationId, tableId, ids) => typed("read_records_by_ids", { p_organization_id: organizationId, p_table_id: tableId, p_record_ids: ids }),
1180
+ readRecordsPage: (args) => typed("read_records_page", args),
1181
+ recordTable: (organizationId, recordId) => typed("record_table", { p_organization_id: organizationId, p_record_id: recordId }),
1182
+ applicableFields: (organizationId, tableId) => typed("applicable_fields", { p_organization_id: organizationId, p_table_id: tableId }),
1183
+ fieldDeclare: (organizationId, tableId, spec) => typed("field_declare", { p_organization_id: organizationId, p_table_id: tableId, p_spec: spec }),
1184
+ recordUpdate: (organizationId, recordId, patch) => typed("record_update", { p_organization_id: organizationId, p_record_id: recordId, p_patch: patch }),
1185
+ entityReferenceWords: (organizationId, refs) => typed("entity_reference_words", { p_organization_id: organizationId, p_refs: refs.map((r) => ({ token: r.token, id: r.id })) }),
1186
+ templates: (filter) => typed("templates", { p_filter: filter }),
1187
+ templateFromTables: ({ organizationId, tableIds, includeRows, rowsPerTable }) => typed("template_from_tables", {
1188
+ p_organization_id: organizationId,
1189
+ p_table_ids: tableIds,
1190
+ p_include_rows: includeRows,
1191
+ p_rows_per_table: rowsPerTable
1192
+ }),
1193
+ templateDeclare: (scope, spec) => typed("template_declare", { p_scope: scope, p_spec: spec }),
1194
+ templateKeep: (templateId) => typed("template_keep", { p_template_id: templateId }),
1195
+ templateArchive: (templateId, restore) => typed("template_archive", restore === void 0 ? { p_template_id: templateId } : { p_template_id: templateId, p_restore: restore }),
1196
+ templateInstallClaim: ({ organizationId, installId, kind, label, sourceId, leaseSeconds }) => typed("template_install_claim", {
1197
+ p_organization_id: organizationId,
1198
+ p_install_id: installId,
1199
+ p_kind: kind,
1200
+ p_label: label,
1201
+ ...sourceId ? { p_source_id: sourceId } : {},
1202
+ p_lease_seconds: leaseSeconds
1203
+ }),
1204
+ templateInstallNote: ({ organizationId, installId, kind, id, label }) => typed("template_install_note", {
1205
+ p_organization_id: organizationId,
1206
+ p_install_id: installId,
1207
+ p_kind: kind,
1208
+ p_id: id,
1209
+ p_label: label
1210
+ })
1211
+ };
1212
+ }
1213
+
1214
+ // src/core/table-logic.ts
1215
+ function isBulkOpError(r) {
1216
+ return typeof r === "object" && r !== null && "error" in r;
1217
+ }
1218
+ function describeBulkFailures(failed) {
1219
+ const inTrash = failed.filter((f) => f.error === "row_in_trash").length;
1220
+ const missing = failed.length - inTrash;
1221
+ const parts = [];
1222
+ if (inTrash > 0) {
1223
+ parts.push(
1224
+ `${inTrash} row${inTrash === 1 ? " is" : "s are"} in Trash \u2014 restore ${inTrash === 1 ? "it" : "them"} from Trash to edit`
1225
+ );
1226
+ }
1227
+ if (missing > 0) {
1228
+ parts.push(
1229
+ `${missing} row${missing === 1 ? "" : "s"} could not be found \u2014 ${missing === 1 ? "it" : "they"} may have been removed by someone else`
1230
+ );
1231
+ }
1232
+ return `${parts.join("; ")}.`;
1233
+ }
1234
+ function isServiceFailure(r) {
1235
+ return r.success === false;
1236
+ }
1237
+
1238
+ // src/objectOrganization.ts
1239
+ var WHERE_ID_OPENS_DOOR = "where_id_opens";
1240
+ function doorIsAbsent(error) {
1241
+ if (error.code === "PGRST202" || error.code === "42883") return true;
1242
+ return /could not find the function/i.test(error.message ?? "");
1243
+ }
1244
+ var DOOR_ABSENT_WHY = "custom.where_id_opens is missing from this database, so this page cannot tell which organization the record lives in and holds instead of guessing. Remedy: the chair applies migrations/campaign/openbyid_one_address_opens_any_id.sql and openbyid_the_resolver_can_be_reached.sql.";
1245
+ async function resolveObjectOrganization(dataSource, id) {
1246
+ let answered;
1247
+ try {
1248
+ answered = await dataSource.rpc(WHERE_ID_OPENS_DOOR, { p_id: id }, { schema: "custom" });
1249
+ } catch (thrown) {
1250
+ return { state: "unavailable", why: thrown instanceof Error ? thrown.message : "The record store did not answer." };
1251
+ }
1252
+ return readObjectOrganizationAnswer(answered, id);
1253
+ }
1254
+ function readObjectOrganizationAnswer(answered, id) {
1255
+ if (answered.error) {
1256
+ if (doorIsAbsent(answered.error)) {
1257
+ console.warn(`[@ai-matrx/records] ${DOOR_ABSENT_WHY}`);
1258
+ return { state: "unavailable", why: DOOR_ABSENT_WHY };
1259
+ }
1260
+ return { state: "unavailable", why: answered.error.message ?? "The record store refused to say where this is." };
1261
+ }
1262
+ const row = answered.data;
1263
+ if (row === null || row === void 0) return { state: "not-given" };
1264
+ if (typeof row !== "object" || typeof row.organization_id !== "string" || typeof row.kind !== "string") {
1265
+ return { state: "unavailable", why: "The record store answered something this page cannot read." };
1266
+ }
1267
+ return {
1268
+ state: "found",
1269
+ organizationId: row.organization_id,
1270
+ kind: row.kind,
1271
+ path: typeof row.path === "string" ? row.path : null,
1272
+ live: row.live !== false,
1273
+ resolvedId: typeof row.resolved_id === "string" ? row.resolved_id : id
1274
+ };
1275
+ }
1276
+
1277
+ // src/door-call/index.ts
1278
+ function lightDoorCall(client, options = {}) {
1279
+ return createDoorCall({ ...options, dataSource: asRecordsDataSource(client) });
1280
+ }
1281
+ function lightScopeDoors(client, options = {}) {
1282
+ return createScopeDoors(lightDoorCall(client, options));
1283
+ }
1284
+ function lightPickListDoors(client, options = {}) {
1285
+ return createPickListDoors(lightDoorCall(client, options));
1286
+ }
1287
+ //# sourceMappingURL=index.cjs.map