@ai-matrx/records 0.80.8 → 0.81.0
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 -0
- package/dist/app-table/index.cjs.map +1 -1
- package/dist/app-table/index.js.map +1 -1
- package/dist/core/index.cjs +74 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +35 -1
- package/dist/core/index.d.ts +35 -1
- package/dist/core/index.js +74 -0
- package/dist/core/index.js.map +1 -1
- package/dist/data/index.cjs.map +1 -1
- package/dist/data/index.js.map +1 -1
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.js.map +1 -1
- package/dist/react/index.cjs +236 -95
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +60 -1
- package/dist/react/index.d.ts +60 -1
- package/dist/react/index.js +174 -33
- package/dist/react/index.js.map +1 -1
- package/dist/templates/index.cjs +1 -1
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.js +1 -1
- package/dist/templates/index.js.map +1 -1
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -86,6 +86,8 @@ __export(react_exports, {
|
|
|
86
86
|
RULE_USES: () => RULE_USES,
|
|
87
87
|
RecordsHoldScope: () => RecordsHoldScope,
|
|
88
88
|
RecordsProvider: () => RecordsProvider,
|
|
89
|
+
RecordsSeedProvider: () => RecordsSeedProvider,
|
|
90
|
+
SEED_FRESH_MS: () => SEED_FRESH_MS,
|
|
89
91
|
SHOWN_TO_LABEL: () => SHOWN_TO_LABEL,
|
|
90
92
|
SHOWN_TO_VALUES: () => SHOWN_TO_VALUES,
|
|
91
93
|
SHOWN_TO_WHO_MAY_CHANGE: () => SHOWN_TO_WHO_MAY_CHANGE,
|
|
@@ -277,6 +279,7 @@ __export(react_exports, {
|
|
|
277
279
|
useReverseColumns: () => useReverseColumns,
|
|
278
280
|
useReverseLinks: () => useReverseLinks,
|
|
279
281
|
useRowActions: () => useRowActions,
|
|
282
|
+
useSeededAnswer: () => useSeededAnswer,
|
|
280
283
|
useStoreTable: () => useStoreTable,
|
|
281
284
|
useTable: () => useTable,
|
|
282
285
|
useTableArchive: () => useTableArchive,
|
|
@@ -300,6 +303,10 @@ function registry() {
|
|
|
300
303
|
return g[REGISTRY] ??= /* @__PURE__ */ new Map();
|
|
301
304
|
}
|
|
302
305
|
var primedKey = (organizationId, tableId, viewId) => `${organizationId}|${tableId}|${viewId ?? ""}`;
|
|
306
|
+
function primeTablePageBundle(input) {
|
|
307
|
+
const answer = Promise.resolve(input.answer).catch((thrown) => ({ data: null, error: thrown }));
|
|
308
|
+
registry().set(primedKey(input.organizationId, input.tableId, input.viewId), { answer, at: Date.now() });
|
|
309
|
+
}
|
|
303
310
|
function takePrimedTablePageBundle(organizationId, tableId, viewId) {
|
|
304
311
|
if (!organizationId) return null;
|
|
305
312
|
const key = primedKey(organizationId, tableId, viewId);
|
|
@@ -309,6 +316,9 @@ function takePrimedTablePageBundle(organizationId, tableId, viewId) {
|
|
|
309
316
|
primed.delete(key);
|
|
310
317
|
return Date.now() - held.at < PRIMED_TTL_MS ? held.answer : null;
|
|
311
318
|
}
|
|
319
|
+
function primeRecordPageBundle(input) {
|
|
320
|
+
primeTablePageBundle({ organizationId: input.organizationId, tableId: `record:${input.recordId}`, answer: input.answer });
|
|
321
|
+
}
|
|
312
322
|
|
|
313
323
|
// src/core/recordChanges.ts
|
|
314
324
|
var listeners = /* @__PURE__ */ new Set();
|
|
@@ -426,8 +436,8 @@ function liftWithheld(rows) {
|
|
|
426
436
|
}
|
|
427
437
|
|
|
428
438
|
// src/subscription.ts
|
|
429
|
-
function hasQuietHours(
|
|
430
|
-
return Boolean(
|
|
439
|
+
function hasQuietHours(quiet2) {
|
|
440
|
+
return Boolean(quiet2?.start && quiet2?.end);
|
|
431
441
|
}
|
|
432
442
|
function callersTimeZone() {
|
|
433
443
|
try {
|
|
@@ -7851,7 +7861,7 @@ function useRecordsActor() {
|
|
|
7851
7861
|
}
|
|
7852
7862
|
|
|
7853
7863
|
// src/react/hooks.ts
|
|
7854
|
-
var
|
|
7864
|
+
var import_react4 = require("react");
|
|
7855
7865
|
|
|
7856
7866
|
// src/react/dataCache.ts
|
|
7857
7867
|
var RECORDS_CACHE_GRACE_MS = 3e4;
|
|
@@ -8004,6 +8014,12 @@ function releaseEntry(handle) {
|
|
|
8004
8014
|
entry.refs = Math.max(0, entry.refs - 1);
|
|
8005
8015
|
if (entry.refs === 0) scheduleClose(entry);
|
|
8006
8016
|
}
|
|
8017
|
+
function seedEntry(handle, data, stale) {
|
|
8018
|
+
const entry = handle;
|
|
8019
|
+
if (entry.started || entry.snapshot.data !== null) return;
|
|
8020
|
+
entry.snapshot = { data, loading: false, error: null };
|
|
8021
|
+
entry.started = !stale;
|
|
8022
|
+
}
|
|
8007
8023
|
function openHold(holdKey) {
|
|
8008
8024
|
const holds = root().holds;
|
|
8009
8025
|
let hold = holds.get(holdKey);
|
|
@@ -8034,65 +8050,190 @@ function recordsCacheCounters() {
|
|
|
8034
8050
|
return { ...root().counters };
|
|
8035
8051
|
}
|
|
8036
8052
|
|
|
8037
|
-
// src/react/
|
|
8053
|
+
// src/react/seed.tsx
|
|
8038
8054
|
var import_react2 = require("react");
|
|
8039
|
-
|
|
8055
|
+
|
|
8056
|
+
// src/core/seed.ts
|
|
8057
|
+
var BUNDLE_DOORS = /* @__PURE__ */ new Set(["table_page_bundle", "record_page_bundle"]);
|
|
8058
|
+
function seedKey(door, args) {
|
|
8059
|
+
return `${door}|${canonicalArgs(args)}`;
|
|
8060
|
+
}
|
|
8061
|
+
function answersOf(door, args, data) {
|
|
8062
|
+
const out = [{ door, args, data }];
|
|
8063
|
+
if (!BUNDLE_DOORS.has(door) || !data || typeof data !== "object") return out;
|
|
8064
|
+
const parts = data.parts;
|
|
8065
|
+
if (!Array.isArray(parts)) return out;
|
|
8066
|
+
for (const part of parts) {
|
|
8067
|
+
if (part.error !== void 0 || part.data === void 0) continue;
|
|
8068
|
+
if (typeof part.door !== "string" || !part.args || typeof part.args !== "object") continue;
|
|
8069
|
+
out.push({ door: part.door, args: part.args, data: part.data });
|
|
8070
|
+
}
|
|
8071
|
+
return out;
|
|
8072
|
+
}
|
|
8073
|
+
function seedIndex(seed) {
|
|
8074
|
+
const index = /* @__PURE__ */ new Map();
|
|
8075
|
+
for (const a of seed.answers) {
|
|
8076
|
+
for (const spread of answersOf(a.door, a.args, a.data)) index.set(seedKey(spread.door, spread.args), spread.data);
|
|
8077
|
+
}
|
|
8078
|
+
return index;
|
|
8079
|
+
}
|
|
8080
|
+
var MISS = { code: "SEED_MISS", message: "Not in the page's seed.", details: null, hint: null };
|
|
8081
|
+
function missingQuery(onMiss) {
|
|
8082
|
+
const answer = () => {
|
|
8083
|
+
onMiss();
|
|
8084
|
+
return Promise.resolve({ data: null, error: MISS, count: null });
|
|
8085
|
+
};
|
|
8086
|
+
const chain = new Proxy(function() {
|
|
8087
|
+
}, {
|
|
8088
|
+
get(_target, prop) {
|
|
8089
|
+
if (prop === "then") return (ok2, bad) => answer().then(ok2, bad);
|
|
8090
|
+
return () => chain;
|
|
8091
|
+
},
|
|
8092
|
+
apply: () => chain
|
|
8093
|
+
});
|
|
8094
|
+
return { select: () => chain };
|
|
8095
|
+
}
|
|
8096
|
+
function seededDataSource(index) {
|
|
8097
|
+
let missed = false;
|
|
8098
|
+
const source = {
|
|
8099
|
+
rpc(fn, args) {
|
|
8100
|
+
const key = seedKey(fn, args);
|
|
8101
|
+
if (index.has(key)) return Promise.resolve({ data: index.get(key), error: null });
|
|
8102
|
+
missed = true;
|
|
8103
|
+
return Promise.resolve({ data: null, error: MISS });
|
|
8104
|
+
},
|
|
8105
|
+
schema: () => ({ from: () => missingQuery(() => missed = true) })
|
|
8106
|
+
};
|
|
8107
|
+
return { source, missed: () => missed };
|
|
8108
|
+
}
|
|
8109
|
+
|
|
8110
|
+
// src/react/seed.tsx
|
|
8111
|
+
var SEED_FRESH_MS = 3e4;
|
|
8112
|
+
var stores = /* @__PURE__ */ new WeakMap();
|
|
8113
|
+
var quiet = () => {
|
|
8114
|
+
};
|
|
8115
|
+
function storeFor(seed) {
|
|
8116
|
+
const held = stores.get(seed);
|
|
8117
|
+
if (held) return held;
|
|
8118
|
+
const index = seedIndex(seed);
|
|
8119
|
+
const runs = /* @__PURE__ */ new Map();
|
|
8120
|
+
const store = {
|
|
8121
|
+
live: true,
|
|
8122
|
+
run(slot, run, config) {
|
|
8123
|
+
const asked = runs.get(slot);
|
|
8124
|
+
if (asked) return asked;
|
|
8125
|
+
const { source, missed } = seededDataSource(index);
|
|
8126
|
+
const { realtime: _live, ...quietConfig } = config;
|
|
8127
|
+
const client = createRecordsClient({ ...quietConfig, dataSource: source, onError: quiet });
|
|
8128
|
+
const stale = typeof seed.at !== "number" || Date.now() - seed.at > SEED_FRESH_MS;
|
|
8129
|
+
const outcome = Promise.resolve().then(() => run(client)).then(
|
|
8130
|
+
(answer) => answer.ok && !missed() ? { seeded: true, data: answer.data, stale } : { seeded: false },
|
|
8131
|
+
() => ({ seeded: false })
|
|
8132
|
+
);
|
|
8133
|
+
runs.set(slot, outcome);
|
|
8134
|
+
return outcome;
|
|
8135
|
+
}
|
|
8136
|
+
};
|
|
8137
|
+
stores.set(seed, store);
|
|
8138
|
+
if (typeof window !== "undefined") {
|
|
8139
|
+
for (const a of seed.answers) {
|
|
8140
|
+
const org = a.args["p_organization_id"];
|
|
8141
|
+
if (typeof org !== "string") continue;
|
|
8142
|
+
if (a.door === "table_page_bundle" && typeof a.args["p_table_id"] === "string") {
|
|
8143
|
+
const view = a.args["p_view_id"];
|
|
8144
|
+
primeTablePageBundle({ organizationId: org, tableId: a.args["p_table_id"], viewId: typeof view === "string" ? view : null, answer: { data: a.data, error: null } });
|
|
8145
|
+
} else if (a.door === "record_page_bundle" && typeof a.args["p_record_id"] === "string") {
|
|
8146
|
+
primeRecordPageBundle({ organizationId: org, recordId: a.args["p_record_id"], answer: { data: a.data, error: null } });
|
|
8147
|
+
}
|
|
8148
|
+
}
|
|
8149
|
+
}
|
|
8150
|
+
return store;
|
|
8151
|
+
}
|
|
8152
|
+
var SeedContext = (0, import_react2.createContext)(null);
|
|
8153
|
+
function RecordsSeedProvider({ seed, children }) {
|
|
8154
|
+
const store = seed && Array.isArray(seed.answers) ? storeFor(seed) : null;
|
|
8155
|
+
(0, import_react2.useEffect)(() => {
|
|
8156
|
+
if (store) store.live = false;
|
|
8157
|
+
}, [store]);
|
|
8158
|
+
return (0, import_react2.createElement)(SeedContext.Provider, { value: store }, children);
|
|
8159
|
+
}
|
|
8160
|
+
function useSeedStore() {
|
|
8161
|
+
const store = (0, import_react2.useContext)(SeedContext);
|
|
8162
|
+
return store && store.live ? store : null;
|
|
8163
|
+
}
|
|
8164
|
+
|
|
8165
|
+
// src/react/hold.tsx
|
|
8166
|
+
var import_react3 = require("react");
|
|
8167
|
+
var HoldContext = (0, import_react3.createContext)(null);
|
|
8040
8168
|
function RecordsHoldScope({ holdKey, children }) {
|
|
8041
|
-
return (0,
|
|
8169
|
+
return (0, import_react3.createElement)(HoldContext.Provider, { value: holdKey }, children);
|
|
8042
8170
|
}
|
|
8043
8171
|
function useRecordsHold(holdKey) {
|
|
8044
|
-
(0,
|
|
8172
|
+
(0, import_react3.useEffect)(() => holdKey ? openHold(holdKey) : void 0, [holdKey]);
|
|
8045
8173
|
}
|
|
8046
8174
|
function useHoldKey() {
|
|
8047
|
-
return (0,
|
|
8175
|
+
return (0, import_react3.useContext)(HoldContext);
|
|
8048
8176
|
}
|
|
8049
8177
|
|
|
8050
8178
|
// src/react/hooks.ts
|
|
8051
8179
|
function useAsync(run, key, live) {
|
|
8052
8180
|
const client = useRecordsClient();
|
|
8053
8181
|
const holdKey = useHoldKey();
|
|
8054
|
-
const slot = (0,
|
|
8055
|
-
const entry = (0,
|
|
8182
|
+
const slot = (0, import_react4.useId)();
|
|
8183
|
+
const entry = (0, import_react4.useMemo)(
|
|
8056
8184
|
() => typeof window === "undefined" ? serverEntry(run, client) : entryFor(client, key, run, live ?? null),
|
|
8057
8185
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8058
8186
|
[client, key]
|
|
8059
8187
|
);
|
|
8060
8188
|
entry.run = run;
|
|
8061
8189
|
entry.client = client;
|
|
8062
|
-
const
|
|
8063
|
-
(
|
|
8190
|
+
const seed = useSeedStore();
|
|
8191
|
+
if (seed && entry.snapshot.data === null && !entry.snapshot.error && !entry.started) {
|
|
8192
|
+
const outcome = (0, import_react4.use)(seed.run(`${identityOf(client)}|${key}`, run, client.config));
|
|
8193
|
+
if (outcome.seeded) seedEntry(entry, outcome.data, outcome.stale);
|
|
8194
|
+
}
|
|
8195
|
+
const snapshot = (0, import_react4.useSyncExternalStore)(entry.subscribe, entry.getSnapshot, entry.getSnapshot);
|
|
8196
|
+
(0, import_react4.useEffect)(() => {
|
|
8064
8197
|
acquireEntry(entry);
|
|
8065
8198
|
return () => releaseEntry(entry);
|
|
8066
8199
|
}, [entry]);
|
|
8067
|
-
(0,
|
|
8200
|
+
(0, import_react4.useEffect)(() => {
|
|
8068
8201
|
if (holdKey) pinToHold(holdKey, slot, entry);
|
|
8069
8202
|
}, [holdKey, slot, entry]);
|
|
8070
|
-
const lastData = (0,
|
|
8203
|
+
const lastData = (0, import_react4.useRef)(null);
|
|
8071
8204
|
if (snapshot.data !== null) lastData.current = snapshot.data;
|
|
8072
8205
|
const shown = snapshot.data === null && snapshot.loading && !snapshot.error && lastData.current !== null ? { ...snapshot, data: lastData.current } : snapshot;
|
|
8073
|
-
const reload = (0,
|
|
8074
|
-
const setData = (0,
|
|
8206
|
+
const reload = (0, import_react4.useCallback)(() => entry.refetch(), [entry]);
|
|
8207
|
+
const setData = (0, import_react4.useCallback)((update) => entry.setData(update), [entry]);
|
|
8075
8208
|
return { ...shown, reload, setData };
|
|
8076
8209
|
}
|
|
8210
|
+
function useSeededAnswer(key, run) {
|
|
8211
|
+
const client = useRecordsClient();
|
|
8212
|
+
const seed = useSeedStore();
|
|
8213
|
+
if (!seed || key === null) return void 0;
|
|
8214
|
+
const outcome = (0, import_react4.use)(seed.run(`${identityOf(client)}|own:${key}`, run, client.config));
|
|
8215
|
+
return outcome.seeded ? outcome.data : void 0;
|
|
8216
|
+
}
|
|
8077
8217
|
function serverEntry(run, client) {
|
|
8078
|
-
const
|
|
8079
|
-
return {
|
|
8218
|
+
const entry = {
|
|
8080
8219
|
key: "server",
|
|
8081
|
-
snapshot,
|
|
8220
|
+
snapshot: { data: null, loading: true, error: null },
|
|
8082
8221
|
run,
|
|
8083
8222
|
client,
|
|
8084
8223
|
subscribe: () => () => {
|
|
8085
8224
|
},
|
|
8086
|
-
|
|
8225
|
+
// Read through the entry: a page seed may answer it during this render (`seedEntry`).
|
|
8226
|
+
getSnapshot: () => entry.snapshot,
|
|
8087
8227
|
refetch: () => {
|
|
8088
8228
|
},
|
|
8089
8229
|
setData: () => {
|
|
8090
8230
|
}
|
|
8091
8231
|
};
|
|
8232
|
+
return entry;
|
|
8092
8233
|
}
|
|
8093
8234
|
function useTable(tableId) {
|
|
8094
8235
|
const revision = useShapeRevision(tableId);
|
|
8095
|
-
(0,
|
|
8236
|
+
(0, import_react4.useEffect)(() => {
|
|
8096
8237
|
if (tableId) registerShapeInterest(tableId);
|
|
8097
8238
|
}, [tableId]);
|
|
8098
8239
|
return useAsync(
|
|
@@ -8149,12 +8290,12 @@ function subscribeToShape(listener) {
|
|
|
8149
8290
|
};
|
|
8150
8291
|
}
|
|
8151
8292
|
function useShapeRevision(tableId) {
|
|
8152
|
-
const read = (0,
|
|
8153
|
-
return (0,
|
|
8293
|
+
const read = (0, import_react4.useCallback)(() => tableId ? shapeRevisions.get(tableId) ?? 0 : 0, [tableId]);
|
|
8294
|
+
return (0, import_react4.useSyncExternalStore)(subscribeToShape, read, () => 0);
|
|
8154
8295
|
}
|
|
8155
8296
|
function useFields(tableId, recordType) {
|
|
8156
8297
|
const revision = useShapeRevision(tableId);
|
|
8157
|
-
(0,
|
|
8298
|
+
(0, import_react4.useEffect)(() => {
|
|
8158
8299
|
if (tableId) registerShapeInterest(tableId);
|
|
8159
8300
|
}, [tableId]);
|
|
8160
8301
|
return useAsync(
|
|
@@ -8179,7 +8320,7 @@ async function answerOrRefusal(ask, where) {
|
|
|
8179
8320
|
}
|
|
8180
8321
|
}
|
|
8181
8322
|
function useReverseColumns(tableId) {
|
|
8182
|
-
const revision = (0,
|
|
8323
|
+
const revision = (0, import_react4.useSyncExternalStore)(subscribeToShape, () => anyShapeRevision, () => 0);
|
|
8183
8324
|
return useAsync(
|
|
8184
8325
|
async (client) => {
|
|
8185
8326
|
if (!tableId || !doorReady(client.config, DOORS.reverseColumns)) return { ok: true, data: [] };
|
|
@@ -8189,8 +8330,8 @@ function useReverseColumns(tableId) {
|
|
|
8189
8330
|
);
|
|
8190
8331
|
}
|
|
8191
8332
|
function useReverseLinks(tableId, columns, recordIds, limit = 3, offset = 0) {
|
|
8192
|
-
const [writes, setWrites] = (0,
|
|
8193
|
-
(0,
|
|
8333
|
+
const [writes, setWrites] = (0, import_react4.useState)(0);
|
|
8334
|
+
(0, import_react4.useEffect)(() => onRecordChanged(() => setWrites((n) => n + 1)), []);
|
|
8194
8335
|
const idsKey = recordIds.join(",");
|
|
8195
8336
|
const columnsKey = columns.map((c) => c.source_field_id).join(",");
|
|
8196
8337
|
return useAsync(
|
|
@@ -8285,7 +8426,7 @@ function liveStatus(client, tableId) {
|
|
|
8285
8426
|
return { live, liveReason };
|
|
8286
8427
|
}
|
|
8287
8428
|
function useKeptPage(tableId, base) {
|
|
8288
|
-
const lastGood = (0,
|
|
8429
|
+
const lastGood = (0, import_react4.useRef)(null);
|
|
8289
8430
|
if (base.data !== null && !base.error) lastGood.current = { tableId, data: base.data };
|
|
8290
8431
|
if (base.error && base.data === null && lastGood.current && lastGood.current.tableId === tableId) {
|
|
8291
8432
|
return { ...base, data: lastGood.current.data };
|
|
@@ -8302,7 +8443,7 @@ function sameRowAnswer(a, b) {
|
|
|
8302
8443
|
}
|
|
8303
8444
|
}
|
|
8304
8445
|
function useSharedRows(state) {
|
|
8305
|
-
const held = (0,
|
|
8446
|
+
const held = (0, import_react4.useRef)({
|
|
8306
8447
|
source: null,
|
|
8307
8448
|
shared: null,
|
|
8308
8449
|
byId: /* @__PURE__ */ new Map()
|
|
@@ -8377,8 +8518,8 @@ function useRecordPage(tableId, options = {}) {
|
|
|
8377
8518
|
return { ...useSharedRows(useKeptPage(tableId, base)), live, liveReason };
|
|
8378
8519
|
}
|
|
8379
8520
|
function useRecordChangeRevision(recordId) {
|
|
8380
|
-
const [revision, setRevision] = (0,
|
|
8381
|
-
(0,
|
|
8521
|
+
const [revision, setRevision] = (0, import_react4.useState)(0);
|
|
8522
|
+
(0, import_react4.useEffect)(() => {
|
|
8382
8523
|
if (!recordId) return;
|
|
8383
8524
|
return onRecordChanged((changed) => {
|
|
8384
8525
|
if (changed === recordId) setRevision((n) => n + 1);
|
|
@@ -8429,10 +8570,10 @@ function liveRecordFor(recordId, tableId) {
|
|
|
8429
8570
|
}
|
|
8430
8571
|
function useRecordMutation() {
|
|
8431
8572
|
const client = useRecordsClient();
|
|
8432
|
-
const [saving, setSaving] = (0,
|
|
8433
|
-
const [error, setError] = (0,
|
|
8434
|
-
const [conflict, setConflict] = (0,
|
|
8435
|
-
const run = (0,
|
|
8573
|
+
const [saving, setSaving] = (0, import_react4.useState)(false);
|
|
8574
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
8575
|
+
const [conflict, setConflict] = (0, import_react4.useState)(null);
|
|
8576
|
+
const run = (0, import_react4.useCallback)(
|
|
8436
8577
|
async (recordId, call) => {
|
|
8437
8578
|
setSaving(true);
|
|
8438
8579
|
setError(null);
|
|
@@ -8451,7 +8592,7 @@ function useRecordMutation() {
|
|
|
8451
8592
|
},
|
|
8452
8593
|
[]
|
|
8453
8594
|
);
|
|
8454
|
-
return (0,
|
|
8595
|
+
return (0, import_react4.useMemo)(
|
|
8455
8596
|
() => ({
|
|
8456
8597
|
write: (args) => run(null, () => client.recordWrite({ table_id: args.table_id, data: args.data })),
|
|
8457
8598
|
update: (args) => run(
|
|
@@ -8480,15 +8621,15 @@ function useTableArchive(tableId, options) {
|
|
|
8480
8621
|
const client = useRecordsClient();
|
|
8481
8622
|
const chunk = options?.chunk ?? TABLE_ARCHIVE_PASS;
|
|
8482
8623
|
const includeTable = options?.includeTable ?? true;
|
|
8483
|
-
const [progress, setProgress] = (0,
|
|
8484
|
-
const [running, setRunning] = (0,
|
|
8485
|
-
const [passes, setPasses] = (0,
|
|
8486
|
-
const [error, setError] = (0,
|
|
8487
|
-
const [interrupted, setInterrupted] = (0,
|
|
8488
|
-
const [chunkInUse, setChunkInUse] = (0,
|
|
8489
|
-
const [slowedDown, setSlowedDown] = (0,
|
|
8490
|
-
const cut = (0,
|
|
8491
|
-
const preview = (0,
|
|
8624
|
+
const [progress, setProgress] = (0, import_react4.useState)(null);
|
|
8625
|
+
const [running, setRunning] = (0, import_react4.useState)(false);
|
|
8626
|
+
const [passes, setPasses] = (0, import_react4.useState)(0);
|
|
8627
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
8628
|
+
const [interrupted, setInterrupted] = (0, import_react4.useState)(false);
|
|
8629
|
+
const [chunkInUse, setChunkInUse] = (0, import_react4.useState)(chunk);
|
|
8630
|
+
const [slowedDown, setSlowedDown] = (0, import_react4.useState)(false);
|
|
8631
|
+
const cut = (0, import_react4.useRef)(false);
|
|
8632
|
+
const preview = (0, import_react4.useCallback)(async () => {
|
|
8492
8633
|
setError(null);
|
|
8493
8634
|
const answered = await client.tableArchive({ table_id: tableId, chunk: 0, includeTable });
|
|
8494
8635
|
if (!answered.ok) {
|
|
@@ -8499,7 +8640,7 @@ function useTableArchive(tableId, options) {
|
|
|
8499
8640
|
if (answered.data.in_progress) setInterrupted(true);
|
|
8500
8641
|
return answered.data;
|
|
8501
8642
|
}, [client, tableId, includeTable]);
|
|
8502
|
-
const loop = (0,
|
|
8643
|
+
const loop = (0, import_react4.useCallback)(async () => {
|
|
8503
8644
|
cut.current = false;
|
|
8504
8645
|
setRunning(true);
|
|
8505
8646
|
setError(null);
|
|
@@ -8536,7 +8677,7 @@ function useTableArchive(tableId, options) {
|
|
|
8536
8677
|
setRunning(false);
|
|
8537
8678
|
}
|
|
8538
8679
|
}, [client, tableId, chunk, includeTable]);
|
|
8539
|
-
return (0,
|
|
8680
|
+
return (0, import_react4.useMemo)(
|
|
8540
8681
|
() => ({
|
|
8541
8682
|
progress,
|
|
8542
8683
|
running,
|
|
@@ -8581,11 +8722,11 @@ function useEntityBackLinks(token, recordId, options) {
|
|
|
8581
8722
|
}) : Promise.resolve({ ok: true, data: null }),
|
|
8582
8723
|
`entity-back-links:${scope}`
|
|
8583
8724
|
);
|
|
8584
|
-
const [more, setMore] = (0,
|
|
8725
|
+
const [more, setMore] = (0, import_react4.useState)({ scope, items: [], cursor: void 0, busy: false, error: null });
|
|
8585
8726
|
const current = more.scope === scope ? more : { scope, items: [], cursor: void 0, busy: false, error: null };
|
|
8586
8727
|
const firstAnswer = first.data;
|
|
8587
8728
|
const cursor = current.cursor === void 0 ? firstAnswer?.next_cursor ?? null : current.cursor;
|
|
8588
|
-
const loadMore = (0,
|
|
8729
|
+
const loadMore = (0, import_react4.useCallback)(async () => {
|
|
8589
8730
|
if (!asking || !cursor) return;
|
|
8590
8731
|
setMore({ ...current, busy: true, error: null });
|
|
8591
8732
|
const answered = await client.entityBackLinks({
|
|
@@ -8607,7 +8748,7 @@ function useEntityBackLinks(token, recordId, options) {
|
|
|
8607
8748
|
error: null
|
|
8608
8749
|
});
|
|
8609
8750
|
}, [client, asking?.token, asking?.recordId, asking?.organizationId, limit, cursor, current, scope]);
|
|
8610
|
-
const reload = (0,
|
|
8751
|
+
const reload = (0, import_react4.useCallback)(() => {
|
|
8611
8752
|
setMore({ scope, items: [], cursor: void 0, busy: false, error: null });
|
|
8612
8753
|
first.reload();
|
|
8613
8754
|
}, [first, scope]);
|
|
@@ -8643,9 +8784,9 @@ function useEntityFieldRights(token) {
|
|
|
8643
8784
|
}
|
|
8644
8785
|
function useEntityFieldMutation() {
|
|
8645
8786
|
const client = useRecordsClient();
|
|
8646
|
-
const [saving, setSaving] = (0,
|
|
8647
|
-
const [error, setError] = (0,
|
|
8648
|
-
const run = (0,
|
|
8787
|
+
const [saving, setSaving] = (0, import_react4.useState)(false);
|
|
8788
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
8789
|
+
const run = (0, import_react4.useCallback)(
|
|
8649
8790
|
async (call, whenRefused) => {
|
|
8650
8791
|
setSaving(true);
|
|
8651
8792
|
setError(null);
|
|
@@ -8660,7 +8801,7 @@ function useEntityFieldMutation() {
|
|
|
8660
8801
|
},
|
|
8661
8802
|
[]
|
|
8662
8803
|
);
|
|
8663
|
-
return (0,
|
|
8804
|
+
return (0, import_react4.useMemo)(
|
|
8664
8805
|
() => ({
|
|
8665
8806
|
declare: (args) => run(() => client.entityFieldDeclare({ token: args.token, spec: args.spec }), null),
|
|
8666
8807
|
update: (args) => run(
|
|
@@ -8686,9 +8827,9 @@ function useEntityFieldMutation() {
|
|
|
8686
8827
|
}
|
|
8687
8828
|
function useFieldMutation() {
|
|
8688
8829
|
const client = useRecordsClient();
|
|
8689
|
-
const [saving, setSaving] = (0,
|
|
8690
|
-
const [error, setError] = (0,
|
|
8691
|
-
const run = (0,
|
|
8830
|
+
const [saving, setSaving] = (0, import_react4.useState)(false);
|
|
8831
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
8832
|
+
const run = (0, import_react4.useCallback)(
|
|
8692
8833
|
async (call, whenRefused) => {
|
|
8693
8834
|
setSaving(true);
|
|
8694
8835
|
setError(null);
|
|
@@ -8703,14 +8844,14 @@ function useFieldMutation() {
|
|
|
8703
8844
|
},
|
|
8704
8845
|
[]
|
|
8705
8846
|
);
|
|
8706
|
-
const announce = (0,
|
|
8847
|
+
const announce = (0, import_react4.useCallback)((tableId) => {
|
|
8707
8848
|
if (tableId) {
|
|
8708
8849
|
tableShapeChanged(tableId);
|
|
8709
8850
|
return;
|
|
8710
8851
|
}
|
|
8711
8852
|
for (const id of [...shapeRevisions.keys()]) tableShapeChanged(id);
|
|
8712
8853
|
}, []);
|
|
8713
|
-
return (0,
|
|
8854
|
+
return (0, import_react4.useMemo)(
|
|
8714
8855
|
() => ({
|
|
8715
8856
|
declare: async (args) => {
|
|
8716
8857
|
const made = await run(
|
|
@@ -8747,9 +8888,9 @@ function useFieldMutation() {
|
|
|
8747
8888
|
}
|
|
8748
8889
|
function useMergeField(key, state) {
|
|
8749
8890
|
const client = useRecordsClient();
|
|
8750
|
-
const [resolution, setResolution] = (0,
|
|
8891
|
+
const [resolution, setResolution] = (0, import_react4.useState)(null);
|
|
8751
8892
|
const resolver = client.config.resolver;
|
|
8752
|
-
(0,
|
|
8893
|
+
(0, import_react4.useEffect)(() => {
|
|
8753
8894
|
if (!key) {
|
|
8754
8895
|
setResolution(null);
|
|
8755
8896
|
return;
|
|
@@ -8784,11 +8925,11 @@ function useMergeField(key, state) {
|
|
|
8784
8925
|
}
|
|
8785
8926
|
|
|
8786
8927
|
// src/react/entity-reference.ts
|
|
8787
|
-
var
|
|
8928
|
+
var import_react5 = require("react");
|
|
8788
8929
|
function useEntityReferenceKinds() {
|
|
8789
8930
|
const client = useRecordsClient();
|
|
8790
|
-
const [state, setState] = (0,
|
|
8791
|
-
(0,
|
|
8931
|
+
const [state, setState] = (0, import_react5.useState)({ data: null, loading: true, error: null });
|
|
8932
|
+
(0, import_react5.useEffect)(() => {
|
|
8792
8933
|
let live = true;
|
|
8793
8934
|
void entityReferenceKinds(client.config.dataSource).then((res) => {
|
|
8794
8935
|
if (!live) return;
|
|
@@ -8803,8 +8944,8 @@ function useEntityReferenceKinds() {
|
|
|
8803
8944
|
function useEntityReferenceWords(refs) {
|
|
8804
8945
|
const client = useRecordsClient();
|
|
8805
8946
|
const key = refs.map((r) => `${r.token}:${r.id}`).join(",");
|
|
8806
|
-
const [state, setState] = (0,
|
|
8807
|
-
(0,
|
|
8947
|
+
const [state, setState] = (0, import_react5.useState)({ data: null, loading: refs.length > 0, error: null });
|
|
8948
|
+
(0, import_react5.useEffect)(() => {
|
|
8808
8949
|
let live = true;
|
|
8809
8950
|
void entityReferenceWords(client.config.dataSource, client.config.organizationId, refs).then((res) => {
|
|
8810
8951
|
if (!live) return;
|
|
@@ -8819,8 +8960,8 @@ function useEntityReferenceWords(refs) {
|
|
|
8819
8960
|
function useEntityReferenceSearch(tokens, search, enabled = true) {
|
|
8820
8961
|
const client = useRecordsClient();
|
|
8821
8962
|
const key = `${tokens.join(",")}|${search.trim()}|${enabled ? 1 : 0}`;
|
|
8822
|
-
const [state, setState] = (0,
|
|
8823
|
-
(0,
|
|
8963
|
+
const [state, setState] = (0, import_react5.useState)({ data: null, loading: enabled && tokens.length > 0, error: null });
|
|
8964
|
+
(0, import_react5.useEffect)(() => {
|
|
8824
8965
|
if (!enabled || tokens.length === 0) {
|
|
8825
8966
|
setState({ data: [], loading: false, error: null });
|
|
8826
8967
|
return;
|
|
@@ -8842,7 +8983,7 @@ function useEntityReferenceSearch(tokens, search, enabled = true) {
|
|
|
8842
8983
|
}
|
|
8843
8984
|
|
|
8844
8985
|
// src/react/useAppTable.ts
|
|
8845
|
-
var
|
|
8986
|
+
var import_react6 = require("react");
|
|
8846
8987
|
|
|
8847
8988
|
// src/core/declareTable.ts
|
|
8848
8989
|
function tokenFor(name) {
|
|
@@ -9137,16 +9278,16 @@ function useAppTable(def, options = {}) {
|
|
|
9137
9278
|
const client = useRecordsClient();
|
|
9138
9279
|
const narrowed = options.organizationId ?? null;
|
|
9139
9280
|
const writeOrg = narrowed ?? client.config.organizationId;
|
|
9140
|
-
const [rows, setRows] = (0,
|
|
9141
|
-
const [total, setTotal] = (0,
|
|
9142
|
-
const [truncated, setTruncated] = (0,
|
|
9143
|
-
const [loading, setLoading] = (0,
|
|
9144
|
-
const [error, setError] = (0,
|
|
9145
|
-
const [status, setStatus] = (0,
|
|
9146
|
-
const [revision, setRevision] = (0,
|
|
9147
|
-
const rowsRef = (0,
|
|
9281
|
+
const [rows, setRows] = (0, import_react6.useState)([]);
|
|
9282
|
+
const [total, setTotal] = (0, import_react6.useState)(null);
|
|
9283
|
+
const [truncated, setTruncated] = (0, import_react6.useState)(false);
|
|
9284
|
+
const [loading, setLoading] = (0, import_react6.useState)(true);
|
|
9285
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
9286
|
+
const [status, setStatus] = (0, import_react6.useState)(null);
|
|
9287
|
+
const [revision, setRevision] = (0, import_react6.useState)(0);
|
|
9288
|
+
const rowsRef = (0, import_react6.useRef)([]);
|
|
9148
9289
|
rowsRef.current = rows;
|
|
9149
|
-
(0,
|
|
9290
|
+
(0, import_react6.useEffect)(() => {
|
|
9150
9291
|
let live = true;
|
|
9151
9292
|
setLoading(true);
|
|
9152
9293
|
(async () => {
|
|
@@ -9178,8 +9319,8 @@ function useAppTable(def, options = {}) {
|
|
|
9178
9319
|
live = false;
|
|
9179
9320
|
};
|
|
9180
9321
|
}, [client, def.slug, def.kept_for, def.specHash, writeOrg, narrowed, revision]);
|
|
9181
|
-
const reload = (0,
|
|
9182
|
-
const upsert = (0,
|
|
9322
|
+
const reload = (0, import_react6.useCallback)(() => setRevision((n) => n + 1), []);
|
|
9323
|
+
const upsert = (0, import_react6.useCallback)(
|
|
9183
9324
|
async (data, upsertOptions = {}) => {
|
|
9184
9325
|
if (!writeOrg) {
|
|
9185
9326
|
return { ok: false, error: { code: "invalid_argument", message: `${def.name}: no organization to write to.` } };
|
|
@@ -9190,7 +9331,7 @@ function useAppTable(def, options = {}) {
|
|
|
9190
9331
|
},
|
|
9191
9332
|
[client, def, writeOrg, reload]
|
|
9192
9333
|
);
|
|
9193
|
-
const remove = (0,
|
|
9334
|
+
const remove = (0, import_react6.useCallback)(
|
|
9194
9335
|
async (rowId) => {
|
|
9195
9336
|
const org = rowsRef.current.find((r) => r._id === rowId)?._organizationId ?? writeOrg;
|
|
9196
9337
|
const answer = await removeAppRow(client, def, rowId, { organizationId: org });
|
|
@@ -9207,7 +9348,7 @@ function archivedTableOf(error) {
|
|
|
9207
9348
|
}
|
|
9208
9349
|
|
|
9209
9350
|
// src/react/useStoreTable.ts
|
|
9210
|
-
var
|
|
9351
|
+
var import_react8 = require("react");
|
|
9211
9352
|
|
|
9212
9353
|
// src/app-table/store-table.ts
|
|
9213
9354
|
function storeTable(def) {
|
|
@@ -10442,7 +10583,7 @@ function createTableDataPort({ client, aliases }) {
|
|
|
10442
10583
|
}
|
|
10443
10584
|
|
|
10444
10585
|
// src/data/react.tsx
|
|
10445
|
-
var
|
|
10586
|
+
var import_react7 = require("react");
|
|
10446
10587
|
var import_react_query = require("@tanstack/react-query");
|
|
10447
10588
|
var RECORDS_QUERY_ROOT = "@ai-matrx/records";
|
|
10448
10589
|
var DATA_LIVE_GRACE_MS = 3e4;
|
|
@@ -10489,13 +10630,13 @@ function retryable(failureCount, thrown) {
|
|
|
10489
10630
|
const code = thrown instanceof DataRefusal ? thrown.error.code : "unreachable";
|
|
10490
10631
|
return (code === "unreachable" || code === "timed_out") && failureCount < 2;
|
|
10491
10632
|
}
|
|
10492
|
-
var DataPortContext = (0,
|
|
10633
|
+
var DataPortContext = (0, import_react7.createContext)(null);
|
|
10493
10634
|
function hostEvents(port) {
|
|
10494
10635
|
return { on: (event, listener) => port.subscribe(event, listener) };
|
|
10495
10636
|
}
|
|
10496
10637
|
var warnedNotLive = false;
|
|
10497
10638
|
function useDataPort(scope) {
|
|
10498
|
-
const held = (0,
|
|
10639
|
+
const held = (0, import_react7.useContext)(DataPortContext);
|
|
10499
10640
|
if (scope) return scope;
|
|
10500
10641
|
if (!held) {
|
|
10501
10642
|
throw new Error(
|
|
@@ -10781,7 +10922,7 @@ function acquireLive(qc, port, events, portKey, alias) {
|
|
|
10781
10922
|
}
|
|
10782
10923
|
var FALLBACK_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/records/data-query-client");
|
|
10783
10924
|
function useRecordsQueryClient() {
|
|
10784
|
-
const provided = (0,
|
|
10925
|
+
const provided = (0, import_react7.useContext)(import_react_query.QueryClientContext);
|
|
10785
10926
|
if (provided) return provided;
|
|
10786
10927
|
const g = globalThis;
|
|
10787
10928
|
let held = g[FALLBACK_KEY];
|
|
@@ -10794,7 +10935,7 @@ function useRecordsQueryClient() {
|
|
|
10794
10935
|
function useLive(alias, scope) {
|
|
10795
10936
|
const qc = useRecordsQueryClient();
|
|
10796
10937
|
const { port, portKey, events } = useDataPort(scope);
|
|
10797
|
-
(0,
|
|
10938
|
+
(0, import_react7.useEffect)(() => {
|
|
10798
10939
|
if (!alias) return;
|
|
10799
10940
|
return acquireLive(qc, port, events, portKey, alias);
|
|
10800
10941
|
}, [qc, port, events, portKey, alias]);
|
|
@@ -10814,7 +10955,7 @@ function useDataRows(alias, query = {}, scope) {
|
|
|
10814
10955
|
},
|
|
10815
10956
|
qc
|
|
10816
10957
|
);
|
|
10817
|
-
const rows = (0,
|
|
10958
|
+
const rows = (0, import_react7.useMemo)(() => {
|
|
10818
10959
|
const seen = /* @__PURE__ */ new Set();
|
|
10819
10960
|
const out = [];
|
|
10820
10961
|
for (const page2 of q.data?.pages ?? []) {
|
|
@@ -10826,11 +10967,11 @@ function useDataRows(alias, query = {}, scope) {
|
|
|
10826
10967
|
}
|
|
10827
10968
|
return out;
|
|
10828
10969
|
}, [q.data]);
|
|
10829
|
-
const want = (0,
|
|
10970
|
+
const want = (0, import_react7.useRef)({ key: "", pages: 0 });
|
|
10830
10971
|
const keyHash = (0, import_react_query.hashKey)(rowsKey);
|
|
10831
10972
|
const loaded = q.data?.pages.length ?? 0;
|
|
10832
10973
|
const { isFetching, hasNextPage, isFetchNextPageError, fetchNextPage } = q;
|
|
10833
|
-
(0,
|
|
10974
|
+
(0, import_react7.useEffect)(() => {
|
|
10834
10975
|
const w = want.current;
|
|
10835
10976
|
if (w.key !== keyHash || isFetching || loaded >= w.pages) return;
|
|
10836
10977
|
if (!hasNextPage || isFetchNextPageError) {
|
|
@@ -10870,7 +11011,7 @@ function drawPatch(before, patch) {
|
|
|
10870
11011
|
function useDataMutations(alias, scope) {
|
|
10871
11012
|
const qc = useRecordsQueryClient();
|
|
10872
11013
|
const { port, portKey } = useDataPort(scope);
|
|
10873
|
-
return (0,
|
|
11014
|
+
return (0, import_react7.useMemo)(() => {
|
|
10874
11015
|
const snapshotRows = () => qc.getQueriesData({ queryKey: dataKeys.rowsPrefix(portKey, alias) });
|
|
10875
11016
|
const putBack = (snap) => {
|
|
10876
11017
|
for (const [key, data] of snap) qc.setQueryData(key, data);
|
|
@@ -10972,7 +11113,7 @@ function toNamed(table, row) {
|
|
|
10972
11113
|
function useStoreTable(table, options = {}) {
|
|
10973
11114
|
const client = useRecordsClient();
|
|
10974
11115
|
const alias = table.id;
|
|
10975
|
-
const scope = (0,
|
|
11116
|
+
const scope = (0, import_react8.useMemo)(
|
|
10976
11117
|
() => {
|
|
10977
11118
|
const port = createTableDataPort({ client, aliases: { [alias]: { kind: "table", tableId: table.id, organizationId: table.organizationId, label: table.name } } });
|
|
10978
11119
|
return { port, events: hostEvents(port), portKey: `store-table|${client.config.organizationId ?? "-"}|${client.config.actor.user_id ?? "-"}` };
|
|
@@ -10980,7 +11121,7 @@ function useStoreTable(table, options = {}) {
|
|
|
10980
11121
|
[client, alias, table.id, table.organizationId, table.name]
|
|
10981
11122
|
);
|
|
10982
11123
|
const asked = JSON.stringify(options);
|
|
10983
|
-
const built = (0,
|
|
11124
|
+
const built = (0, import_react8.useMemo)(() => {
|
|
10984
11125
|
const where = [];
|
|
10985
11126
|
for (const [name, value] of Object.entries(options.where ?? {})) {
|
|
10986
11127
|
const column = table.columns[name];
|
|
@@ -11007,10 +11148,10 @@ function useStoreTable(table, options = {}) {
|
|
|
11007
11148
|
const limit = Math.min(options.limit ?? STORE_ROWS_CEILING, STORE_ROWS_CEILING);
|
|
11008
11149
|
const read = useDataRows(alias, built.ok ? built.data : { pageSize: 1 }, scope);
|
|
11009
11150
|
const write = useDataMutations(alias, scope);
|
|
11010
|
-
(0,
|
|
11151
|
+
(0, import_react8.useEffect)(() => {
|
|
11011
11152
|
if (built.ok && read.hasMore && !read.loadingMore && !read.loading && !read.error && read.rows.length < limit) read.loadMore();
|
|
11012
11153
|
}, [built.ok, read.hasMore, read.loadingMore, read.loading, read.error, read.rows.length, limit, read]);
|
|
11013
|
-
const rows = (0,
|
|
11154
|
+
const rows = (0, import_react8.useMemo)(() => read.rows.slice(0, limit).filter((r) => r["_pending"] !== true).map((r) => toNamed(table, r)), [read.rows, limit, table]);
|
|
11014
11155
|
const total = built.ok ? read.total : null;
|
|
11015
11156
|
return {
|
|
11016
11157
|
rows: built.ok ? rows : [],
|