@ai-matrx/records 0.80.4 → 0.80.8
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 +24 -0
- package/README.md +19 -0
- package/dist/app-table/index.cjs +88 -23
- package/dist/app-table/index.cjs.map +1 -1
- package/dist/app-table/index.d.cts +7 -7
- package/dist/app-table/index.d.ts +7 -7
- package/dist/app-table/index.js +88 -23
- package/dist/app-table/index.js.map +1 -1
- package/dist/{client-CB_Klj1P.d.ts → client-D1LTezMZ.d.ts} +5 -5
- package/dist/{client-D0yGEof4.d.cts → client-DLIKeBWF.d.cts} +5 -5
- package/dist/core/index.cjs +97 -31
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +21 -12
- package/dist/core/index.d.ts +21 -12
- package/dist/core/index.js +97 -31
- package/dist/core/index.js.map +1 -1
- package/dist/data/index.cjs +88 -23
- package/dist/data/index.cjs.map +1 -1
- package/dist/data/index.d.cts +6 -6
- package/dist/data/index.d.ts +6 -6
- package/dist/data/index.js +88 -23
- package/dist/data/index.js.map +1 -1
- package/dist/{declareTable-l7ktxN6p.d.cts → declareTable-02uao-5n.d.cts} +4 -4
- package/dist/{declareTable-DoYVueVF.d.ts → declareTable-C5FlIS0z.d.ts} +4 -4
- package/dist/{field-6UtYgFeu.d.ts → field-BIJiFPc0.d.ts} +1 -1
- package/dist/{field-DpJR_5Pe.d.cts → field-snQG2jMq.d.cts} +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/index.cjs +1 -0
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.d.cts +6 -6
- package/dist/memory/index.d.ts +6 -6
- package/dist/memory/index.js +1 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/{ports-CiEYhwi5.d.ts → ports-Y5gLbCXe.d.ts} +1 -1
- package/dist/{ports-CE7umTp-.d.cts → ports-y1QNfM80.d.cts} +1 -1
- package/dist/react/index.cjs +89 -27
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +6 -1
- package/dist/react/index.d.ts +6 -1
- package/dist/react/index.js +89 -27
- package/dist/react/index.js.map +1 -1
- package/dist/realtime/index.d.cts +2 -2
- package/dist/realtime/index.d.ts +2 -2
- package/dist/{record-CvqV8wyO.d.cts → record-1yDCn169.d.cts} +6 -1
- package/dist/{record-CvqV8wyO.d.ts → record-1yDCn169.d.ts} +6 -1
- package/dist/{subscription-CC0kgkwa.d.cts → subscription-B_WaT-kr.d.cts} +1 -1
- package/dist/{subscription-DjkuDMcX.d.ts → subscription-CUok1vAm.d.ts} +1 -1
- package/dist/{table-kind-FMYq3nCr.d.ts → table-kind-COmkYYkc.d.ts} +3 -3
- package/dist/{table-kind-DHpMEOHd.d.cts → table-kind-LodkBhCZ.d.cts} +3 -3
- package/dist/templates/index.cjs +3 -2
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.d.cts +9 -9
- package/dist/templates/index.d.ts +9 -9
- package/dist/templates/index.js +3 -2
- package/dist/templates/index.js.map +1 -1
- package/dist/{types-DuceX7js.d.cts → types-BJGTxu3Y.d.cts} +2 -2
- package/dist/{types-BbCZJh1C.d.ts → types-C5-AaPa6.d.ts} +2 -2
- package/dist/{types-B4LF3sFx.d.ts → types-CU_Tn2Np.d.ts} +2 -2
- package/dist/{types-Flsf_KU5.d.cts → types-yBZLtxrZ.d.cts} +2 -2
- package/dist/use-cases/index.cjs.map +1 -1
- package/dist/use-cases/index.d.cts +5 -5
- package/dist/use-cases/index.d.ts +5 -5
- package/dist/use-cases/index.js.map +1 -1
- package/dist/{validate-EvZGkD96.d.cts → validate-CE6qpJIb.d.cts} +1 -1
- package/dist/{validate-DyVwSD74.d.ts → validate-Rz9djP6H.d.ts} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
+
## 0.80.8
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records/v0.80.4..npm/records/v0.80.8 -- apps/shared/records`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.80.7
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/records/v0.80.4..npm/records/v0.80.7 -- apps/shared/records`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
15
|
+
## 0.80.6
|
|
16
|
+
### PAGE-BUNDLE-2: a record page opens in one call
|
|
17
|
+
|
|
18
|
+
RECORD PAGE BUNDLE: the records client answers a record page's own doors (`read_record`, `record_row_controls`, `my_levels` for the record, `record_history` head, `comment_thread`, `computed_provenance`, `record_headers`) from ONE `custom.record_page_bundle(p_organization_id, p_record_id)` call (live; SECURITY INVOKER; each part equals its door's own answer, verified part by part as admin@admin.com). Same contract as the table bundle: exact door + arguments, used once, 10 s; a refusing part is asked by its own door; a write that lands on the record drops what is still held. `primeRecordPageBundle({ organizationId, recordId, answer })` hands it an answer the server render asked as the same person.
|
|
19
|
+
|
|
20
|
+
**Consumer action:** none (additive). A host that seeds its record route calls `primeRecordPageBundle`.
|
|
21
|
+
|
|
22
|
+
## 0.80.5
|
|
23
|
+
|
|
24
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
25
|
+
`git diff npm/records/v0.80.4..npm/records/v0.80.5 -- apps/shared/records`).
|
|
26
|
+
No source changes intended and no consumer action required.
|
|
3
27
|
|
|
4
28
|
## 0.80.4
|
|
5
29
|
|
package/README.md
CHANGED
|
@@ -278,6 +278,25 @@ const { write, update, remove, conflict } = useRecordMutation();
|
|
|
278
278
|
`live` is never quietly false: when realtime is not bound, `liveOffReason` says
|
|
279
279
|
why in a sentence a screen can show.
|
|
280
280
|
|
|
281
|
+
## Drill-down — declared definitions
|
|
282
|
+
|
|
283
|
+
A server drill (`platform.drill_describe` / `platform.drill_ask`) answers a standard table from
|
|
284
|
+
the registry, or a **declared definition**: a `*.drill.ts` file (`declareDrillDefinition({...})`,
|
|
285
|
+
shape in `scripts/drill-definitions/ai_usage.drill.ts`) compiled to one function per definition,
|
|
286
|
+
`platform.drill_def__<key>()`. A Dimension may carry `level` (breakouts, show, attributes,
|
|
287
|
+
records); the UI side is `useDrill` in `@ai-matrx/records-ui` and the table in
|
|
288
|
+
`@ai-matrx/design-system` (its README § Drill-down).
|
|
289
|
+
|
|
290
|
+
| Command (in this package) | Does |
|
|
291
|
+
|---|---|
|
|
292
|
+
| `pnpm drill:sync --write --lane <LANE>` | writes a campaign file (+ inverse) for every declaration whose live body differs |
|
|
293
|
+
| `pnpm drill:sync --write --lane <LANE> --only <key,key>` | the same, for ONLY your definitions — never a peer's half-done one |
|
|
294
|
+
| `pnpm drill:sync --check` | the census: every declaration sound and equal to its live body (exit 1 otherwise) |
|
|
295
|
+
| `pnpm drill:sync --check --only <key,key>` | the census of your definitions only |
|
|
296
|
+
| `... --target clone` | reads the nightly copy instead of production |
|
|
297
|
+
|
|
298
|
+
`--only` naming a key no file declares fails, so a typo never passes as "nothing to do".
|
|
299
|
+
|
|
281
300
|
## The generated half
|
|
282
301
|
|
|
283
302
|
`src/store.generated.ts` is written by `pnpm records:generate` from the live
|
package/dist/app-table/index.cjs
CHANGED
|
@@ -434,6 +434,32 @@ function takePrimedTablePageBundle(organizationId, tableId, viewId) {
|
|
|
434
434
|
return Date.now() - held.at < PRIMED_TTL_MS ? held.answer : null;
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
// src/core/recordChanges.ts
|
|
438
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
439
|
+
function announceRecordChanged(recordId) {
|
|
440
|
+
for (const listener of [...listeners]) {
|
|
441
|
+
try {
|
|
442
|
+
listener(recordId);
|
|
443
|
+
} catch (thrown) {
|
|
444
|
+
console.error("[@ai-matrx/records] a record-change listener threw", thrown);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function onRecordChanged(listener) {
|
|
449
|
+
listeners.add(listener);
|
|
450
|
+
return () => listeners.delete(listener);
|
|
451
|
+
}
|
|
452
|
+
var tableListeners = /* @__PURE__ */ new Set();
|
|
453
|
+
function announceTableStructureChanged(tableId) {
|
|
454
|
+
for (const listener of [...tableListeners]) {
|
|
455
|
+
try {
|
|
456
|
+
listener(tableId);
|
|
457
|
+
} catch (thrown) {
|
|
458
|
+
console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
437
463
|
// src/archive.ts
|
|
438
464
|
var DEFAULT_ARCHIVE_LANE = "org";
|
|
439
465
|
|
|
@@ -1565,6 +1591,7 @@ var STORE_DOORS = [
|
|
|
1565
1591
|
{ name: "record_filter_sql", args: "p_organization_id uuid, p_table_id uuid, p_filter jsonb", returns: "text", security: "invoker" },
|
|
1566
1592
|
{ name: "record_headers", args: "p_organization_id uuid, p_ids uuid[]", returns: "TABLE(id uuid, table_id uuid, created_at timestamp with time zone, updated_at timestamp with time zone, version integer, deleted_at timestamp with time zone, mine boolean, created_by uuid)", security: "definer" },
|
|
1567
1593
|
{ name: "record_history", args: "p_organization_id uuid, p_record_id uuid, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(version integer, occurred_at timestamp with time zone, operation text, operation_label text, actor jsonb, changes jsonb, migration_id uuid, undoable boolean)", security: "definer" },
|
|
1594
|
+
{ name: "record_page_bundle", args: "p_organization_id uuid, p_record_id uuid", returns: "jsonb", security: "invoker" },
|
|
1568
1595
|
{ name: "record_platform_keys", args: "", returns: "text[]", security: "invoker" },
|
|
1569
1596
|
{ name: "record_relation_edges", args: "p_organization_id uuid, p_id uuid, p_table_id uuid, p_data_class text, p_data jsonb, p_deleted_at timestamp with time zone", returns: "TABLE(target_id uuid, edge_role text, field_id uuid, ord integer)", security: "invoker" },
|
|
1570
1597
|
{ name: "record_reparent", args: "p_organization_id uuid, p_record_id uuid, p_parent_id uuid", returns: "void", security: "definer" },
|
|
@@ -2662,28 +2689,6 @@ var DRILL_DOORS = {
|
|
|
2662
2689
|
rows: "drill_rows"
|
|
2663
2690
|
};
|
|
2664
2691
|
|
|
2665
|
-
// src/core/recordChanges.ts
|
|
2666
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
2667
|
-
function announceRecordChanged(recordId) {
|
|
2668
|
-
for (const listener of [...listeners]) {
|
|
2669
|
-
try {
|
|
2670
|
-
listener(recordId);
|
|
2671
|
-
} catch (thrown) {
|
|
2672
|
-
console.error("[@ai-matrx/records] a record-change listener threw", thrown);
|
|
2673
|
-
}
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
var tableListeners = /* @__PURE__ */ new Set();
|
|
2677
|
-
function announceTableStructureChanged(tableId) {
|
|
2678
|
-
for (const listener of [...tableListeners]) {
|
|
2679
|
-
try {
|
|
2680
|
-
listener(tableId);
|
|
2681
|
-
} catch (thrown) {
|
|
2682
|
-
console.error("[@ai-matrx/records] a table-structure listener threw", thrown);
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
2692
|
// src/core/query.ts
|
|
2688
2693
|
var DEFAULT_PAGE_SIZE = 50;
|
|
2689
2694
|
function planQuery(query) {
|
|
@@ -2803,8 +2808,68 @@ function createRecordsClient(given) {
|
|
|
2803
2808
|
} catch {
|
|
2804
2809
|
}
|
|
2805
2810
|
}
|
|
2811
|
+
const RECORD_OPENERS = /* @__PURE__ */ new Set(["read_record", "record_row_controls", "record_history", "comment_thread", "computed_provenance"]);
|
|
2812
|
+
const recordFlights = /* @__PURE__ */ new Map();
|
|
2813
|
+
const recordAsked = /* @__PURE__ */ new Map();
|
|
2814
|
+
let recordChangesHeard = false;
|
|
2815
|
+
function bundleRecordOf(door, args) {
|
|
2816
|
+
if (RECORD_OPENERS.has(door)) return typeof args["p_record_id"] === "string" ? args["p_record_id"] : null;
|
|
2817
|
+
const ids = args["p_ids"];
|
|
2818
|
+
const one = Array.isArray(ids) && ids.length === 1 && typeof ids[0] === "string" ? ids[0] : null;
|
|
2819
|
+
if (door === "record_headers") return one;
|
|
2820
|
+
if (door === "my_levels" && args["p_type"] === "record") return one;
|
|
2821
|
+
return null;
|
|
2822
|
+
}
|
|
2823
|
+
async function fillRecordBundle(recordId) {
|
|
2824
|
+
if (!recordChangesHeard) {
|
|
2825
|
+
recordChangesHeard = true;
|
|
2826
|
+
onRecordChanged((changed) => {
|
|
2827
|
+
recordAsked.delete(changed);
|
|
2828
|
+
for (const key of [...bundleParts.keys()]) if (key.includes(changed)) bundleParts.delete(key);
|
|
2829
|
+
});
|
|
2830
|
+
}
|
|
2831
|
+
try {
|
|
2832
|
+
const usable = (r) => r !== null && !r.error && r.data !== null && typeof r.data === "object" && Array.isArray(r.data.parts);
|
|
2833
|
+
const primedAnswer = takePrimedTablePageBundle(org, `record:${recordId}`, null);
|
|
2834
|
+
let response = primedAnswer ? await primedAnswer : null;
|
|
2835
|
+
if (!usable(response)) {
|
|
2836
|
+
response = await config.dataSource.rpc("record_page_bundle", { p_organization_id: org, p_record_id: recordId }, { schema });
|
|
2837
|
+
}
|
|
2838
|
+
if (!usable(response)) return;
|
|
2839
|
+
const now = Date.now();
|
|
2840
|
+
for (const part of response.data.parts) {
|
|
2841
|
+
if (part.error !== void 0 || part.data === void 0) continue;
|
|
2842
|
+
bundleParts.set(bundleKey(part.door, part.args), { data: part.data, at: now });
|
|
2843
|
+
}
|
|
2844
|
+
} catch {
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
async function fromRecordBundle(door, args) {
|
|
2848
|
+
if (!doorReady(config, "record_page_bundle")) return void 0;
|
|
2849
|
+
const recordId = bundleRecordOf(door, args);
|
|
2850
|
+
if (!recordId) return void 0;
|
|
2851
|
+
const opener = RECORD_OPENERS.has(door);
|
|
2852
|
+
if (!opener && !recordFlights.has(recordId) && !recordAsked.has(recordId)) return void 0;
|
|
2853
|
+
const asked = recordAsked.get(recordId);
|
|
2854
|
+
const fresh = asked !== void 0 && Date.now() - asked < BUNDLE_TTL_MS;
|
|
2855
|
+
if (!fresh && opener) {
|
|
2856
|
+
recordAsked.set(recordId, Date.now());
|
|
2857
|
+
const flight2 = fillRecordBundle(recordId).finally(() => recordFlights.delete(recordId));
|
|
2858
|
+
recordFlights.set(recordId, flight2);
|
|
2859
|
+
}
|
|
2860
|
+
const flight = recordFlights.get(recordId);
|
|
2861
|
+
if (flight) await flight;
|
|
2862
|
+
const key = bundleKey(door, args);
|
|
2863
|
+
const held = bundleParts.get(key);
|
|
2864
|
+
if (!held) return opener ? null : void 0;
|
|
2865
|
+
bundleParts.delete(key);
|
|
2866
|
+
return Date.now() - held.at < BUNDLE_TTL_MS ? { data: held.data } : null;
|
|
2867
|
+
}
|
|
2806
2868
|
async function fromBundle(door, args) {
|
|
2807
|
-
if (!config.dataSource.opensInOneCall
|
|
2869
|
+
if (!config.dataSource.opensInOneCall) return null;
|
|
2870
|
+
const fromRecord = await fromRecordBundle(door, args);
|
|
2871
|
+
if (fromRecord !== void 0) return fromRecord;
|
|
2872
|
+
if (!doorReady(config, "table_page_bundle")) return null;
|
|
2808
2873
|
const tableId = bundleTableOf(door, args);
|
|
2809
2874
|
if (tableId) {
|
|
2810
2875
|
const asked = bundleAsked.get(tableId);
|