@ai-matrx/records 0.99.32 → 0.99.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -1
- package/dist/{client-CrwedBYU.d.ts → client-CSfkP7Xf.d.ts} +5 -74
- package/dist/{client-D1EwyWfh.d.cts → client-jKf1Z-kp.d.cts} +5 -74
- package/dist/core/index.cjs +149 -105
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +9 -331
- package/dist/core/index.d.ts +9 -331
- package/dist/core/index.js +149 -105
- package/dist/core/index.js.map +1 -1
- package/dist/data/index.cjs +280 -236
- package/dist/data/index.cjs.map +1 -1
- package/dist/data/index.d.cts +3 -2
- package/dist/data/index.d.ts +3 -2
- package/dist/data/index.js +280 -236
- package/dist/data/index.js.map +1 -1
- package/dist/{declareTable-CC5rTTIA.d.ts → declareTable-0emxEewn.d.ts} +1 -1
- package/dist/{declareTable-BIIt0Wqt.d.cts → declareTable-800bwUn3.d.cts} +1 -1
- package/dist/door-call/index.cjs +1287 -0
- package/dist/door-call/index.cjs.map +1 -0
- package/dist/door-call/index.d.cts +20 -0
- package/dist/door-call/index.d.ts +20 -0
- package/dist/door-call/index.js +1264 -0
- package/dist/door-call/index.js.map +1 -0
- package/dist/{doors-D1yAs0a0.d.cts → doors-BgjRUdxw.d.cts} +13 -1
- package/dist/{doors-D2z3kH2i.d.ts → doors-D7_jEKtg.d.ts} +13 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/{objectOrganization-DazBoDAq.d.cts → objectOrganization-B5YFGVUB.d.cts} +1 -1
- package/dist/{objectOrganization-D1ox3gUx.d.ts → objectOrganization-DozoVIxS.d.ts} +1 -1
- package/dist/pickListDoors-C-_eAEGL.d.cts +135 -0
- package/dist/pickListDoors-DgWVnNRI.d.ts +135 -0
- package/dist/questions/index.d.cts +3 -2
- package/dist/questions/index.d.ts +3 -2
- package/dist/react/index.cjs +363 -319
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +37 -22
- package/dist/react/index.d.ts +37 -22
- package/dist/react/index.js +363 -319
- package/dist/react/index.js.map +1 -1
- package/dist/scopes/index.cjs +7 -0
- package/dist/scopes/index.cjs.map +1 -1
- package/dist/scopes/index.d.cts +2 -2
- package/dist/scopes/index.d.ts +2 -2
- package/dist/scopes/index.js +7 -0
- package/dist/scopes/index.js.map +1 -1
- package/dist/setup/index.cjs +289 -245
- package/dist/setup/index.cjs.map +1 -1
- package/dist/setup/index.d.cts +4 -3
- package/dist/setup/index.d.ts +4 -3
- package/dist/setup/index.js +289 -245
- package/dist/setup/index.js.map +1 -1
- package/dist/table-logic-BPquabNN.d.ts +328 -0
- package/dist/table-logic-CTh6lwaq.d.cts +328 -0
- package/dist/typed-table/index.cjs +280 -236
- package/dist/typed-table/index.cjs.map +1 -1
- package/dist/typed-table/index.d.cts +4 -3
- package/dist/typed-table/index.d.ts +4 -3
- package/dist/typed-table/index.js +280 -236
- package/dist/typed-table/index.js.map +1 -1
- package/dist/views/index.d.cts +3 -2
- package/dist/views/index.d.ts +3 -2
- package/package.json +13 -3
package/dist/setup/index.cjs
CHANGED
|
@@ -89,137 +89,6 @@ function isWritingDoor(door) {
|
|
|
89
89
|
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);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
// src/core/recordChanges.ts
|
|
93
|
-
var import_global_slot = require("@ai-matrx/kit/global-slot");
|
|
94
|
-
var listeners = (0, import_global_slot.globalSlot)("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
|
|
95
|
-
function announceRecordChanged(recordId) {
|
|
96
|
-
for (const listener of [...listeners]) {
|
|
97
|
-
try {
|
|
98
|
-
listener(recordId);
|
|
99
|
-
} catch (thrown) {
|
|
100
|
-
console.error("[@ai-matrx/records] a record-change listener threw", thrown);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
var removed = (0, import_global_slot.globalSlot)("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
|
|
105
|
-
function markRecordRemoved(recordId) {
|
|
106
|
-
removed.add(recordId);
|
|
107
|
-
}
|
|
108
|
-
function markRecordRestored(recordId) {
|
|
109
|
-
removed.delete(recordId);
|
|
110
|
-
}
|
|
111
|
-
function onRecordChanged(listener) {
|
|
112
|
-
listeners.add(listener);
|
|
113
|
-
return () => listeners.delete(listener);
|
|
114
|
-
}
|
|
115
|
-
var tableListeners = (0, import_global_slot.globalSlot)("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
|
|
116
|
-
function announceTableStructureChanged(tableId) {
|
|
117
|
-
for (const listener of [...tableListeners]) {
|
|
118
|
-
try {
|
|
119
|
-
listener(tableId);
|
|
120
|
-
} catch (thrown) {
|
|
121
|
-
console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/archive.ts
|
|
127
|
-
var DEFAULT_ARCHIVE_LANE = "org";
|
|
128
|
-
|
|
129
|
-
// src/aggregate.ts
|
|
130
|
-
function isRuleFilter(filter) {
|
|
131
|
-
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
|
|
132
|
-
const node = filter;
|
|
133
|
-
return typeof node.op === "string" && Array.isArray(node.args);
|
|
134
|
-
}
|
|
135
|
-
function stableFilterKey(filter) {
|
|
136
|
-
if (!filter) return "{}";
|
|
137
|
-
if (isRuleFilter(filter)) return JSON.stringify(filter);
|
|
138
|
-
const keys = Object.keys(filter).sort();
|
|
139
|
-
if (keys.length === 0) return "{}";
|
|
140
|
-
const parts = keys.map((key) => {
|
|
141
|
-
const value = filter[key];
|
|
142
|
-
if (value !== null && typeof value === "object") {
|
|
143
|
-
const window = value;
|
|
144
|
-
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
|
|
145
|
-
}
|
|
146
|
-
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
147
|
-
});
|
|
148
|
-
return `{${parts.join(",")}}`;
|
|
149
|
-
}
|
|
150
|
-
function liftWithheld(rows) {
|
|
151
|
-
let shared;
|
|
152
|
-
for (const row of rows) {
|
|
153
|
-
const m = (row.measures ?? {})["_withheld"];
|
|
154
|
-
if (m !== void 0 && m !== null && typeof m === "object") {
|
|
155
|
-
shared = m;
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return rows.map((row) => {
|
|
160
|
-
const measures = row.measures ?? {};
|
|
161
|
-
const own = measures["_withheld"];
|
|
162
|
-
const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
|
|
163
|
-
const rowCount = row.row_count ?? 0;
|
|
164
|
-
if (marker === void 0 || marker === null || typeof marker !== "object") {
|
|
165
|
-
return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
|
|
166
|
-
}
|
|
167
|
-
const { _withheld: _drop, ...rest } = measures;
|
|
168
|
-
const withheld = {};
|
|
169
|
-
for (const [name, raw] of Object.entries(marker)) {
|
|
170
|
-
const m = raw ?? {};
|
|
171
|
-
withheld[name] = {
|
|
172
|
-
reason: m.withheld?.reason ?? null,
|
|
173
|
-
needs: m.withheld?.needs ?? null,
|
|
174
|
-
or: m.withheld?.or ?? null,
|
|
175
|
-
...m.says ? { says: m.says } : {},
|
|
176
|
-
...m.label ? { label: m.label } : {},
|
|
177
|
-
...m.field_key ? { field_key: m.field_key } : {}
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
return { ...row, measures: rest, withheld, row_count: rowCount };
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/record.ts
|
|
185
|
-
function isLockedStub(row) {
|
|
186
|
-
if (!row) return false;
|
|
187
|
-
if (row.level !== null && row.level !== void 0) return false;
|
|
188
|
-
const doc = row.document;
|
|
189
|
-
if (!doc || typeof doc !== "object") return false;
|
|
190
|
-
const keys = Object.keys(doc);
|
|
191
|
-
if (keys.length === 0 || keys.length > 3) return false;
|
|
192
|
-
const d = doc;
|
|
193
|
-
return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
|
|
194
|
-
}
|
|
195
|
-
function splitLockedRows(rows) {
|
|
196
|
-
const open = [];
|
|
197
|
-
let locked = 0;
|
|
198
|
-
for (const row of rows) {
|
|
199
|
-
if (isLockedStub(row)) locked += 1;
|
|
200
|
-
else open.push(row);
|
|
201
|
-
}
|
|
202
|
-
return { rows: open, locked };
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// src/subscription.ts
|
|
206
|
-
function callersTimeZone() {
|
|
207
|
-
try {
|
|
208
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
|
|
209
|
-
} catch {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function withCallersClock(spec, zone = callersTimeZone()) {
|
|
214
|
-
if (!zone || spec.quiet_hours?.tz) return spec;
|
|
215
|
-
return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// src/rowLabel.ts
|
|
219
|
-
function clearsRowLabel(formula) {
|
|
220
|
-
return formula == null || formula.trim() === "";
|
|
221
|
-
}
|
|
222
|
-
|
|
223
92
|
// src/results.ts
|
|
224
93
|
var ok = (data) => ({ ok: true, data });
|
|
225
94
|
var err = (error) => ({ ok: false, error });
|
|
@@ -390,6 +259,230 @@ function mapPgError(error, where) {
|
|
|
390
259
|
return mapped;
|
|
391
260
|
}
|
|
392
261
|
|
|
262
|
+
// src/core/doorCall.ts
|
|
263
|
+
var DEFAULT_DOOR_SCHEMA = "custom";
|
|
264
|
+
function canonicalArgs(value) {
|
|
265
|
+
return JSON.stringify(
|
|
266
|
+
value,
|
|
267
|
+
(_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
|
|
271
|
+
"refused_by_rule",
|
|
272
|
+
"stale_write",
|
|
273
|
+
"invalid_argument",
|
|
274
|
+
"already_exists",
|
|
275
|
+
"missing_reference"
|
|
276
|
+
]);
|
|
277
|
+
function isAPersonsRefusal(code) {
|
|
278
|
+
return A_PERSONS_REFUSAL.has(code);
|
|
279
|
+
}
|
|
280
|
+
function recordsErrorSink(onError) {
|
|
281
|
+
return onError ?? ((e) => {
|
|
282
|
+
const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
|
|
283
|
+
if (isAPersonsRefusal(e.code)) console.info(line);
|
|
284
|
+
else console.error(line);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function doorAbsentRefusal(name, owedBy) {
|
|
288
|
+
return {
|
|
289
|
+
code: "door_absent",
|
|
290
|
+
message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
|
|
291
|
+
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\`.`
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function primedDoorAnswer(door, args) {
|
|
295
|
+
const look = LOOK_WRITES[door];
|
|
296
|
+
if (look) {
|
|
297
|
+
dropPrimedDoorAnswers(look);
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
if (isWritingDoor(door)) {
|
|
301
|
+
dropPrimedDoorAnswers();
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
|
|
305
|
+
}
|
|
306
|
+
function createDoorCall(options) {
|
|
307
|
+
const { dataSource, doorReady: doorReady2, held, wrote } = options;
|
|
308
|
+
const schema = options.schema ?? DEFAULT_DOOR_SCHEMA;
|
|
309
|
+
const scream = recordsErrorSink(options.onError);
|
|
310
|
+
const absent = options.absent ?? ((door) => doorAbsentRefusal(door));
|
|
311
|
+
const readsInFlight = /* @__PURE__ */ new Map();
|
|
312
|
+
const say = (refusal2, where) => scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
|
|
313
|
+
return async function callDoor(door, args, where, opts) {
|
|
314
|
+
const primed = primedDoorAnswer(door, args);
|
|
315
|
+
if (primed) return ok(primed.data);
|
|
316
|
+
if (held) {
|
|
317
|
+
const bundled = await held(door, args);
|
|
318
|
+
if (bundled) return ok(bundled.data);
|
|
319
|
+
}
|
|
320
|
+
if (doorReady2 && !doorReady2(door)) {
|
|
321
|
+
const refusal2 = absent(door);
|
|
322
|
+
say(refusal2, where);
|
|
323
|
+
return err(refusal2);
|
|
324
|
+
}
|
|
325
|
+
const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
|
|
326
|
+
const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
|
|
327
|
+
const response = await (flying ?? (() => {
|
|
328
|
+
const call = Promise.resolve(dataSource.rpc(`${door}`, args, { schema }));
|
|
329
|
+
if (flightKey) {
|
|
330
|
+
readsInFlight.set(flightKey, call);
|
|
331
|
+
const forget = () => {
|
|
332
|
+
if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
|
|
333
|
+
};
|
|
334
|
+
call.then(forget, forget);
|
|
335
|
+
}
|
|
336
|
+
return call;
|
|
337
|
+
})());
|
|
338
|
+
if (response.error) {
|
|
339
|
+
const code = response.error.code;
|
|
340
|
+
const refusal2 = !doorReady2 && (code === "PGRST202" || code === "42883") ? absent(door) : mapPgError(response.error, where);
|
|
341
|
+
if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
|
|
342
|
+
else say(refusal2, where);
|
|
343
|
+
return err(refusal2);
|
|
344
|
+
}
|
|
345
|
+
if (isWritingDoor(door) || LOOK_WRITES[door]) {
|
|
346
|
+
const tableId = args["p_table_id"];
|
|
347
|
+
wrote?.(door, args);
|
|
348
|
+
forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
|
|
349
|
+
dropPrimedDoorAnswers(LOOK_WRITES[door]);
|
|
350
|
+
}
|
|
351
|
+
return ok(response.data);
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/core/recordChanges.ts
|
|
356
|
+
var import_global_slot = require("@ai-matrx/kit/global-slot");
|
|
357
|
+
var listeners = (0, import_global_slot.globalSlot)("ai-matrx.records.record-change-listeners", () => /* @__PURE__ */ new Set());
|
|
358
|
+
function announceRecordChanged(recordId) {
|
|
359
|
+
for (const listener of [...listeners]) {
|
|
360
|
+
try {
|
|
361
|
+
listener(recordId);
|
|
362
|
+
} catch (thrown) {
|
|
363
|
+
console.error("[@ai-matrx/records] a record-change listener threw", thrown);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
var removed = (0, import_global_slot.globalSlot)("ai-matrx.records.removed-records", () => /* @__PURE__ */ new Set());
|
|
368
|
+
function markRecordRemoved(recordId) {
|
|
369
|
+
removed.add(recordId);
|
|
370
|
+
}
|
|
371
|
+
function markRecordRestored(recordId) {
|
|
372
|
+
removed.delete(recordId);
|
|
373
|
+
}
|
|
374
|
+
function onRecordChanged(listener) {
|
|
375
|
+
listeners.add(listener);
|
|
376
|
+
return () => listeners.delete(listener);
|
|
377
|
+
}
|
|
378
|
+
var tableListeners = (0, import_global_slot.globalSlot)("ai-matrx.records.table-structure-listeners", () => /* @__PURE__ */ new Set());
|
|
379
|
+
function announceTableStructureChanged(tableId) {
|
|
380
|
+
for (const listener of [...tableListeners]) {
|
|
381
|
+
try {
|
|
382
|
+
listener(tableId);
|
|
383
|
+
} catch (thrown) {
|
|
384
|
+
console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/archive.ts
|
|
390
|
+
var DEFAULT_ARCHIVE_LANE = "org";
|
|
391
|
+
|
|
392
|
+
// src/aggregate.ts
|
|
393
|
+
function isRuleFilter(filter) {
|
|
394
|
+
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return false;
|
|
395
|
+
const node = filter;
|
|
396
|
+
return typeof node.op === "string" && Array.isArray(node.args);
|
|
397
|
+
}
|
|
398
|
+
function stableFilterKey(filter) {
|
|
399
|
+
if (!filter) return "{}";
|
|
400
|
+
if (isRuleFilter(filter)) return JSON.stringify(filter);
|
|
401
|
+
const keys = Object.keys(filter).sort();
|
|
402
|
+
if (keys.length === 0) return "{}";
|
|
403
|
+
const parts = keys.map((key) => {
|
|
404
|
+
const value = filter[key];
|
|
405
|
+
if (value !== null && typeof value === "object") {
|
|
406
|
+
const window = value;
|
|
407
|
+
return `${JSON.stringify(key)}:{"from":${JSON.stringify(window.from ?? null)},"to":${JSON.stringify(window.to ?? null)}}`;
|
|
408
|
+
}
|
|
409
|
+
return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
|
|
410
|
+
});
|
|
411
|
+
return `{${parts.join(",")}}`;
|
|
412
|
+
}
|
|
413
|
+
function liftWithheld(rows) {
|
|
414
|
+
let shared;
|
|
415
|
+
for (const row of rows) {
|
|
416
|
+
const m = (row.measures ?? {})["_withheld"];
|
|
417
|
+
if (m !== void 0 && m !== null && typeof m === "object") {
|
|
418
|
+
shared = m;
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return rows.map((row) => {
|
|
423
|
+
const measures = row.measures ?? {};
|
|
424
|
+
const own = measures["_withheld"];
|
|
425
|
+
const marker = own !== void 0 && own !== null && typeof own === "object" ? own : shared;
|
|
426
|
+
const rowCount = row.row_count ?? 0;
|
|
427
|
+
if (marker === void 0 || marker === null || typeof marker !== "object") {
|
|
428
|
+
return rowCount === row.row_count ? row : { ...row, row_count: rowCount };
|
|
429
|
+
}
|
|
430
|
+
const { _withheld: _drop, ...rest } = measures;
|
|
431
|
+
const withheld = {};
|
|
432
|
+
for (const [name, raw] of Object.entries(marker)) {
|
|
433
|
+
const m = raw ?? {};
|
|
434
|
+
withheld[name] = {
|
|
435
|
+
reason: m.withheld?.reason ?? null,
|
|
436
|
+
needs: m.withheld?.needs ?? null,
|
|
437
|
+
or: m.withheld?.or ?? null,
|
|
438
|
+
...m.says ? { says: m.says } : {},
|
|
439
|
+
...m.label ? { label: m.label } : {},
|
|
440
|
+
...m.field_key ? { field_key: m.field_key } : {}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
return { ...row, measures: rest, withheld, row_count: rowCount };
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/record.ts
|
|
448
|
+
function isLockedStub(row) {
|
|
449
|
+
if (!row) return false;
|
|
450
|
+
if (row.level !== null && row.level !== void 0) return false;
|
|
451
|
+
const doc = row.document;
|
|
452
|
+
if (!doc || typeof doc !== "object") return false;
|
|
453
|
+
const keys = Object.keys(doc);
|
|
454
|
+
if (keys.length === 0 || keys.length > 3) return false;
|
|
455
|
+
const d = doc;
|
|
456
|
+
return d["exists"] === true && keys.every((k) => k === "id" || k === "exists" || k === "submitted_at");
|
|
457
|
+
}
|
|
458
|
+
function splitLockedRows(rows) {
|
|
459
|
+
const open = [];
|
|
460
|
+
let locked = 0;
|
|
461
|
+
for (const row of rows) {
|
|
462
|
+
if (isLockedStub(row)) locked += 1;
|
|
463
|
+
else open.push(row);
|
|
464
|
+
}
|
|
465
|
+
return { rows: open, locked };
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/subscription.ts
|
|
469
|
+
function callersTimeZone() {
|
|
470
|
+
try {
|
|
471
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
|
|
472
|
+
} catch {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function withCallersClock(spec, zone = callersTimeZone()) {
|
|
477
|
+
if (!zone || spec.quiet_hours?.tz) return spec;
|
|
478
|
+
return { ...spec, quiet_hours: { ...spec.quiet_hours ?? {}, tz: zone } };
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/rowLabel.ts
|
|
482
|
+
function clearsRowLabel(formula) {
|
|
483
|
+
return formula == null || formula.trim() === "";
|
|
484
|
+
}
|
|
485
|
+
|
|
393
486
|
// src/relation.ts
|
|
394
487
|
var import_uuid = require("@ai-matrx/kit/uuid");
|
|
395
488
|
function isReverseField(field) {
|
|
@@ -1172,11 +1265,51 @@ function createScopeDoors(call) {
|
|
|
1172
1265
|
source_type: String(envelope.data?.source_type ?? cell.source_type ?? "ai_enriched")
|
|
1173
1266
|
}
|
|
1174
1267
|
};
|
|
1268
|
+
},
|
|
1269
|
+
tableProvision({ organization_id, item_id, scope_id, home_id }) {
|
|
1270
|
+
return call(
|
|
1271
|
+
"scope_table_provision",
|
|
1272
|
+
{ p_organization_id: organization_id, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
|
|
1273
|
+
"scopeTableProvision"
|
|
1274
|
+
);
|
|
1175
1275
|
}
|
|
1176
1276
|
};
|
|
1177
1277
|
return doors;
|
|
1178
1278
|
}
|
|
1179
1279
|
|
|
1280
|
+
// src/core/pickListDoors.ts
|
|
1281
|
+
var PICK_LIST_DOORS = {
|
|
1282
|
+
pickListGet: "pick_list_get",
|
|
1283
|
+
pickListForSelection: "pick_list_for_selection",
|
|
1284
|
+
pickListUpdate: "pick_list_update"
|
|
1285
|
+
};
|
|
1286
|
+
function createPickListDoors(callDoor) {
|
|
1287
|
+
return {
|
|
1288
|
+
async pickListGet({ list_id }) {
|
|
1289
|
+
return callDoor(PICK_LIST_DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
|
|
1290
|
+
},
|
|
1291
|
+
async pickListForSelection({ list_id }) {
|
|
1292
|
+
return callDoor(
|
|
1293
|
+
PICK_LIST_DOORS.pickListForSelection,
|
|
1294
|
+
{ p_list_id: list_id },
|
|
1295
|
+
"pickListForSelection"
|
|
1296
|
+
);
|
|
1297
|
+
},
|
|
1298
|
+
async pickListUpdate({ list_id, list_name, description, items }) {
|
|
1299
|
+
return callDoor(
|
|
1300
|
+
PICK_LIST_DOORS.pickListUpdate,
|
|
1301
|
+
{
|
|
1302
|
+
p_list_id: list_id,
|
|
1303
|
+
p_list_name: list_name ?? null,
|
|
1304
|
+
p_description: description ?? null,
|
|
1305
|
+
p_items: items ? [...items] : null
|
|
1306
|
+
},
|
|
1307
|
+
"pickListUpdate"
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1180
1313
|
// src/choice.ts
|
|
1181
1314
|
var import_uuid3 = require("@ai-matrx/kit/uuid");
|
|
1182
1315
|
var CHOICE_NUDGES = ["ask", "always_add", "never_add"];
|
|
@@ -2498,12 +2631,7 @@ function doorReady(config, name) {
|
|
|
2498
2631
|
return DOOR_NAMES.has(name) || Boolean(config?.knownDoors?.includes(name));
|
|
2499
2632
|
}
|
|
2500
2633
|
function doorAbsent(name) {
|
|
2501
|
-
|
|
2502
|
-
return {
|
|
2503
|
-
code: "door_absent",
|
|
2504
|
-
message: `The record store has no door \`custom.${name}\` yet, so this call was not made. Nothing was read and nothing was written.`,
|
|
2505
|
-
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\`.`
|
|
2506
|
-
};
|
|
2634
|
+
return doorAbsentRefusal(name, OWED_BY[name]);
|
|
2507
2635
|
}
|
|
2508
2636
|
var DOORS = {
|
|
2509
2637
|
// THE READ DOOR (DOOR-1). Every read of a record's values goes through these
|
|
@@ -3283,29 +3411,6 @@ function intersectIds(sets) {
|
|
|
3283
3411
|
|
|
3284
3412
|
// src/core/client.ts
|
|
3285
3413
|
var DEFAULT_SCHEMA = "custom";
|
|
3286
|
-
function canonicalArgs(value) {
|
|
3287
|
-
return JSON.stringify(
|
|
3288
|
-
value,
|
|
3289
|
-
(_key, held) => held && typeof held === "object" && !Array.isArray(held) ? Object.fromEntries(Object.keys(held).sort().map((k) => [k, held[k]])) : held
|
|
3290
|
-
);
|
|
3291
|
-
}
|
|
3292
|
-
var A_PERSONS_REFUSAL = /* @__PURE__ */ new Set([
|
|
3293
|
-
"refused_by_rule",
|
|
3294
|
-
"stale_write",
|
|
3295
|
-
"invalid_argument",
|
|
3296
|
-
"already_exists",
|
|
3297
|
-
"missing_reference"
|
|
3298
|
-
]);
|
|
3299
|
-
function isAPersonsRefusal(code) {
|
|
3300
|
-
return A_PERSONS_REFUSAL.has(code);
|
|
3301
|
-
}
|
|
3302
|
-
function sink(config) {
|
|
3303
|
-
return config.onError ?? ((e) => {
|
|
3304
|
-
const line = `[@ai-matrx/records] ${e.where}: ${e.code} \u2014 ${e.message}${e.hint ? ` (${e.hint})` : ""}`;
|
|
3305
|
-
if (isAPersonsRefusal(e.code)) console.info(line);
|
|
3306
|
-
else console.error(line);
|
|
3307
|
-
});
|
|
3308
|
-
}
|
|
3309
3414
|
var TABLE_LIST_PAGE = 500;
|
|
3310
3415
|
var TABLE_ARCHIVE_PASS = 20;
|
|
3311
3416
|
var TABLE_RESTORE_PASS = 20;
|
|
@@ -3318,7 +3423,7 @@ function createRecordsClient(given) {
|
|
|
3318
3423
|
const org = config.organizationId;
|
|
3319
3424
|
const ledger = config.opLedger ?? defaultOpLedger;
|
|
3320
3425
|
const mintOp = () => ledger.mint();
|
|
3321
|
-
const scream =
|
|
3426
|
+
const scream = recordsErrorSink(config.onError);
|
|
3322
3427
|
const BUNDLE_TTL_MS = 1e4;
|
|
3323
3428
|
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"]);
|
|
3324
3429
|
const bundleParts = /* @__PURE__ */ new Map();
|
|
@@ -3460,56 +3565,20 @@ function createRecordsClient(given) {
|
|
|
3460
3565
|
bundleAsked.delete(tableId);
|
|
3461
3566
|
for (const key of [...bundleParts.keys()]) if (key.includes(tableId)) bundleParts.delete(key);
|
|
3462
3567
|
}
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
}
|
|
3473
|
-
return takePrimedDoorAnswer(`${door}|${canonicalArgs(args)}`);
|
|
3474
|
-
}
|
|
3475
|
-
const readsInFlight = /* @__PURE__ */ new Map();
|
|
3476
|
-
async function callDoor(door, args, where, opts) {
|
|
3477
|
-
const primed = primedFor(door, args);
|
|
3478
|
-
if (primed) return ok(primed.data);
|
|
3479
|
-
const bundled = await fromBundle(door, args);
|
|
3480
|
-
if (bundled) return ok(bundled.data);
|
|
3481
|
-
if (!doorReady(config, door)) {
|
|
3482
|
-
const refusal2 = doorAbsent(door);
|
|
3483
|
-
scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
|
|
3484
|
-
return err(refusal2);
|
|
3485
|
-
}
|
|
3486
|
-
const flightKey = isWritingDoor(door) ? null : `${door}|${canonicalArgs(args)}`;
|
|
3487
|
-
const flying = flightKey ? readsInFlight.get(flightKey) : void 0;
|
|
3488
|
-
const response = await (flying ?? (() => {
|
|
3489
|
-
const call = Promise.resolve(config.dataSource.rpc(`${door}`, args, { schema }));
|
|
3490
|
-
if (flightKey) {
|
|
3491
|
-
readsInFlight.set(flightKey, call);
|
|
3492
|
-
const forget = () => {
|
|
3493
|
-
if (readsInFlight.get(flightKey) === call) readsInFlight.delete(flightKey);
|
|
3494
|
-
};
|
|
3495
|
-
call.then(forget, forget);
|
|
3496
|
-
}
|
|
3497
|
-
return call;
|
|
3498
|
-
})());
|
|
3499
|
-
if (response.error) {
|
|
3500
|
-
const refusal2 = mapPgError(response.error, where);
|
|
3501
|
-
if (opts?.quiet) console.info(`[@ai-matrx/records] ${where}: ${refusal2.code} - ${refusal2.message}`);
|
|
3502
|
-
else scream({ code: refusal2.code, message: refusal2.message, ...refusal2.hint ? { hint: refusal2.hint } : {}, where });
|
|
3503
|
-
return err(refusal2);
|
|
3504
|
-
}
|
|
3505
|
-
if (isWritingDoor(door) || LOOK_WRITES[door]) {
|
|
3568
|
+
const primedFor = primedDoorAnswer;
|
|
3569
|
+
const callDoor = createDoorCall({
|
|
3570
|
+
dataSource: config.dataSource,
|
|
3571
|
+
schema,
|
|
3572
|
+
onError: scream,
|
|
3573
|
+
doorReady: (door) => doorReady(config, door),
|
|
3574
|
+
absent: doorAbsent,
|
|
3575
|
+
held: fromBundle,
|
|
3576
|
+
wrote: (_door, args) => {
|
|
3506
3577
|
const tableId = args["p_table_id"];
|
|
3507
3578
|
bundleDrop(typeof tableId === "string" ? tableId : null);
|
|
3508
|
-
forgetPrimedTablePageBundlesOf(typeof tableId === "string" ? tableId : null);
|
|
3509
|
-
dropPrimedDoorAnswers(LOOK_WRITES[door]);
|
|
3510
3579
|
}
|
|
3511
|
-
|
|
3512
|
-
|
|
3580
|
+
});
|
|
3581
|
+
const scopes = createScopeDoors(callDoor);
|
|
3513
3582
|
function structureMoved(tableId, result) {
|
|
3514
3583
|
if (result.ok) {
|
|
3515
3584
|
bundleDrop(tableId);
|
|
@@ -3708,7 +3777,7 @@ function createRecordsClient(given) {
|
|
|
3708
3777
|
const unavailableReason = (error) => `${error.message}${error.hint ? ` ${error.hint}` : ""}`;
|
|
3709
3778
|
const client = {
|
|
3710
3779
|
config,
|
|
3711
|
-
scopes
|
|
3780
|
+
scopes,
|
|
3712
3781
|
async recordWrite({ table_id, data }) {
|
|
3713
3782
|
const result = await callDoor(
|
|
3714
3783
|
DOORS.recordWrite,
|
|
@@ -4407,28 +4476,7 @@ function createRecordsClient(given) {
|
|
|
4407
4476
|
"fieldOptions"
|
|
4408
4477
|
);
|
|
4409
4478
|
},
|
|
4410
|
-
|
|
4411
|
-
return callDoor(DOORS.pickListGet, { p_list_id: list_id }, "pickListGet");
|
|
4412
|
-
},
|
|
4413
|
-
async pickListForSelection({ list_id }) {
|
|
4414
|
-
return callDoor(
|
|
4415
|
-
DOORS.pickListForSelection,
|
|
4416
|
-
{ p_list_id: list_id },
|
|
4417
|
-
"pickListForSelection"
|
|
4418
|
-
);
|
|
4419
|
-
},
|
|
4420
|
-
async pickListUpdate({ list_id, list_name, description, items }) {
|
|
4421
|
-
return callDoor(
|
|
4422
|
-
DOORS.pickListUpdate,
|
|
4423
|
-
{
|
|
4424
|
-
p_list_id: list_id,
|
|
4425
|
-
p_list_name: list_name ?? null,
|
|
4426
|
-
p_description: description ?? null,
|
|
4427
|
-
p_items: items ? [...items] : null
|
|
4428
|
-
},
|
|
4429
|
-
"pickListUpdate"
|
|
4430
|
-
);
|
|
4431
|
-
},
|
|
4479
|
+
...createPickListDoors(callDoor),
|
|
4432
4480
|
async fieldChoiceUsage({ field_id }) {
|
|
4433
4481
|
const result = await callDoor(
|
|
4434
4482
|
DOORS.fieldChoiceUsage,
|
|
@@ -6962,11 +7010,7 @@ function createRecordsClient(given) {
|
|
|
6962
7010
|
);
|
|
6963
7011
|
},
|
|
6964
7012
|
async scopeTableProvision({ home_id, item_id, scope_id }) {
|
|
6965
|
-
return
|
|
6966
|
-
DOORS.scopeTableProvision,
|
|
6967
|
-
{ p_organization_id: org, p_item_id: item_id, p_scope_id: scope_id, p_home_id: home_id ?? null },
|
|
6968
|
-
"scopeTableProvision"
|
|
6969
|
-
);
|
|
7013
|
+
return scopes.tableProvision({ organization_id: org, item_id, scope_id, home_id: home_id ?? null });
|
|
6970
7014
|
},
|
|
6971
7015
|
async tableRowCounts({ table_ids }) {
|
|
6972
7016
|
return callDoor(
|
|
@@ -7596,7 +7640,7 @@ function createEntityDataPort(options) {
|
|
|
7596
7640
|
let stopped = false;
|
|
7597
7641
|
let joined = [];
|
|
7598
7642
|
let stopLive = null;
|
|
7599
|
-
const
|
|
7643
|
+
const sink = { rows: (ids) => listener({ ids: ids === null ? null : [...ids] }) };
|
|
7600
7644
|
const plan = async () => {
|
|
7601
7645
|
const organizationIds = binding.organizationId ? [binding.organizationId] : orderOrganizationTopics({
|
|
7602
7646
|
active: activeOrganization(),
|
|
@@ -7608,7 +7652,7 @@ function createEntityDataPort(options) {
|
|
|
7608
7652
|
if (organizationIds.length === joined.length && organizationIds.every((org, i) => org === joined[i])) return;
|
|
7609
7653
|
const previous = stopLive;
|
|
7610
7654
|
joined = organizationIds;
|
|
7611
|
-
stopLive = realtime.subscribe({ token: binding.token, organizationIds },
|
|
7655
|
+
stopLive = realtime.subscribe({ token: binding.token, organizationIds }, sink);
|
|
7612
7656
|
previous?.();
|
|
7613
7657
|
};
|
|
7614
7658
|
const replan = () => void plan();
|
|
@@ -7730,7 +7774,7 @@ function createRecordsRealtimePort(options = {}) {
|
|
|
7730
7774
|
return channel;
|
|
7731
7775
|
};
|
|
7732
7776
|
return {
|
|
7733
|
-
subscribeRecords({ table_id },
|
|
7777
|
+
subscribeRecords({ table_id }, sink) {
|
|
7734
7778
|
let timer = null;
|
|
7735
7779
|
let pending = /* @__PURE__ */ new Set();
|
|
7736
7780
|
let wholePage = false;
|
|
@@ -7740,15 +7784,15 @@ function createRecordsRealtimePort(options = {}) {
|
|
|
7740
7784
|
const all = wholePage;
|
|
7741
7785
|
pending = /* @__PURE__ */ new Set();
|
|
7742
7786
|
wholePage = false;
|
|
7743
|
-
if (all)
|
|
7744
|
-
else if (ids.length > 0)
|
|
7787
|
+
if (all) sink.records(null);
|
|
7788
|
+
else if (ids.length > 0) sink.records(ids);
|
|
7745
7789
|
};
|
|
7746
7790
|
const nudge = () => {
|
|
7747
7791
|
if (timer === null) timer = setTimeout(flush, NUDGE_DEBOUNCE_MS);
|
|
7748
7792
|
};
|
|
7749
7793
|
const listener = {
|
|
7750
7794
|
notice(notice) {
|
|
7751
|
-
if (notice.kind === "field" || notice.kind === "table")
|
|
7795
|
+
if (notice.kind === "field" || notice.kind === "table") sink.shape();
|
|
7752
7796
|
if (notice.kind === "field") return;
|
|
7753
7797
|
if (notice.record_ids == null) wholePage = true;
|
|
7754
7798
|
else for (const id of notice.record_ids) pending.add(id);
|
|
@@ -7869,7 +7913,7 @@ async function createRecords(options) {
|
|
|
7869
7913
|
realtime,
|
|
7870
7914
|
search: (request) => searchRecords(dataSource, request),
|
|
7871
7915
|
recordCandidates: (args) => listStoreRecordCandidates(dataSource, args),
|
|
7872
|
-
watch(tableId,
|
|
7916
|
+
watch(tableId, sink, organizationId2) {
|
|
7873
7917
|
const activeOrganizationId = organizationIdChosen;
|
|
7874
7918
|
const org = organizationId2 ?? activeOrganizationId;
|
|
7875
7919
|
if (!realtimePort || !org) {
|
|
@@ -7880,8 +7924,8 @@ async function createRecords(options) {
|
|
|
7880
7924
|
return () => {
|
|
7881
7925
|
};
|
|
7882
7926
|
}
|
|
7883
|
-
return realtimePort.subscribeRecords({ organization_id: org, table_id: tableId }, { records:
|
|
7884
|
-
}), shape:
|
|
7927
|
+
return realtimePort.subscribeRecords({ organization_id: org, table_id: tableId }, { records: sink.records ?? (() => {
|
|
7928
|
+
}), shape: sink.shape ?? (() => {
|
|
7885
7929
|
}) });
|
|
7886
7930
|
},
|
|
7887
7931
|
associations: options.associations,
|