@toclocoinc/lattice-grid 1.67.0 → 1.68.1
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/README.md +1 -1
- package/angular/package.json +1 -1
- package/docs/API.html +5334 -3788
- package/docs/api-detail.html +40 -5
- package/lattice-grid.d.ts +3368 -2
- package/lattice-grid.esm.min.js +32 -10
- package/lattice-grid.min.cjs +32 -10
- package/lattice-grid.min.js +32 -10
- package/modules/ai.d.ts +64 -1
- package/modules/ai.esm.min.js +3 -3
- package/modules/ai.min.cjs +3 -3
- package/modules/ai.min.js +3 -3
- package/modules/angular.d.ts +1 -1
- package/modules/angular.esm.min.js +3 -3
- package/modules/angular.min.cjs +3 -3
- package/modules/angular.min.js +3 -3
- package/modules/chart-alluvial.d.ts +1 -1
- package/modules/chart-alluvial.esm.min.js +1 -1
- package/modules/chart-alluvial.min.cjs +1 -1
- package/modules/chart-alluvial.min.js +1 -1
- package/modules/chart-arc.d.ts +1 -1
- package/modules/chart-arc.esm.min.js +1 -1
- package/modules/chart-arc.min.cjs +1 -1
- package/modules/chart-arc.min.js +1 -1
- package/modules/chart-bubblemap.d.ts +1 -1
- package/modules/chart-bubblemap.esm.min.js +1 -1
- package/modules/chart-bubblemap.min.cjs +1 -1
- package/modules/chart-bubblemap.min.js +1 -1
- package/modules/chart-bump.d.ts +1 -1
- package/modules/chart-bump.esm.min.js +1 -1
- package/modules/chart-bump.min.cjs +1 -1
- package/modules/chart-bump.min.js +1 -1
- package/modules/chart-calendar.d.ts +1 -1
- package/modules/chart-calendar.esm.min.js +1 -1
- package/modules/chart-calendar.min.cjs +1 -1
- package/modules/chart-calendar.min.js +1 -1
- package/modules/chart-decomposition.d.ts +1 -1
- package/modules/chart-decomposition.esm.min.js +1 -1
- package/modules/chart-decomposition.min.cjs +1 -1
- package/modules/chart-decomposition.min.js +1 -1
- package/modules/chart-diverging.d.ts +1 -1
- package/modules/chart-diverging.esm.min.js +1 -1
- package/modules/chart-diverging.min.cjs +1 -1
- package/modules/chart-diverging.min.js +1 -1
- package/modules/chart-dumbbell.d.ts +1 -1
- package/modules/chart-dumbbell.esm.min.js +1 -1
- package/modules/chart-dumbbell.min.cjs +1 -1
- package/modules/chart-dumbbell.min.js +1 -1
- package/modules/chart-fan.d.ts +1 -1
- package/modules/chart-fan.esm.min.js +1 -1
- package/modules/chart-fan.min.cjs +1 -1
- package/modules/chart-fan.min.js +1 -1
- package/modules/chart-hexbin.d.ts +1 -1
- package/modules/chart-hexbin.esm.min.js +1 -1
- package/modules/chart-hexbin.min.cjs +1 -1
- package/modules/chart-hexbin.min.js +1 -1
- package/modules/chart-hexmap.d.ts +1 -1
- package/modules/chart-hexmap.esm.min.js +1 -1
- package/modules/chart-hexmap.min.cjs +1 -1
- package/modules/chart-hexmap.min.js +1 -1
- package/modules/chart-icicle.d.ts +1 -1
- package/modules/chart-icicle.esm.min.js +1 -1
- package/modules/chart-icicle.min.cjs +1 -1
- package/modules/chart-icicle.min.js +1 -1
- package/modules/chart-markermap.d.ts +1 -1
- package/modules/chart-markermap.esm.min.js +1 -1
- package/modules/chart-markermap.min.cjs +1 -1
- package/modules/chart-markermap.min.js +1 -1
- package/modules/chart-parallel.d.ts +1 -1
- package/modules/chart-parallel.esm.min.js +1 -1
- package/modules/chart-parallel.min.cjs +1 -1
- package/modules/chart-parallel.min.js +1 -1
- package/modules/chart-ridgeline.d.ts +1 -1
- package/modules/chart-ridgeline.esm.min.js +1 -1
- package/modules/chart-ridgeline.min.cjs +1 -1
- package/modules/chart-ridgeline.min.js +1 -1
- package/modules/chart-roc.d.ts +1 -1
- package/modules/chart-roc.esm.min.js +1 -1
- package/modules/chart-roc.min.cjs +1 -1
- package/modules/chart-roc.min.js +1 -1
- package/modules/chart-slope.d.ts +1 -1
- package/modules/chart-slope.esm.min.js +1 -1
- package/modules/chart-slope.min.cjs +1 -1
- package/modules/chart-slope.min.js +1 -1
- package/modules/chart-splom.d.ts +1 -1
- package/modules/chart-splom.esm.min.js +1 -1
- package/modules/chart-splom.min.cjs +1 -1
- package/modules/chart-splom.min.js +1 -1
- package/modules/chart-waffle.d.ts +1 -1
- package/modules/chart-waffle.esm.min.js +1 -1
- package/modules/chart-waffle.min.cjs +1 -1
- package/modules/chart-waffle.min.js +1 -1
- package/modules/charts.d.ts +16 -1
- package/modules/charts.esm.min.js +1391 -1257
- package/modules/charts.min.cjs +1391 -1257
- package/modules/charts.min.js +1391 -1257
- package/modules/data-router.d.ts +227 -1
- package/modules/data-router.esm.min.js +204 -8
- package/modules/data-router.min.cjs +204 -8
- package/modules/data-router.min.js +204 -8
- package/modules/devtools.d.ts +1 -1
- package/modules/devtools.esm.min.js +1 -1
- package/modules/devtools.min.cjs +1 -1
- package/modules/devtools.min.js +1 -1
- package/modules/dhtmlx-compat.d.ts +1 -1
- package/modules/dhtmlx-compat.esm.min.js +3 -3
- package/modules/dhtmlx-compat.min.cjs +3 -3
- package/modules/dhtmlx-compat.min.js +3 -3
- package/modules/gantt.d.ts +302 -1
- package/modules/gantt.esm.min.js +32 -7
- package/modules/gantt.min.cjs +32 -7
- package/modules/gantt.min.js +32 -7
- package/modules/geo-europe-nuts.d.ts +1 -1
- package/modules/geo-europe-nuts.esm.min.js +1 -1
- package/modules/geo-uk.d.ts +1 -1
- package/modules/geo-uk.esm.min.js +1 -1
- package/modules/geo-us-states.d.ts +1 -1
- package/modules/geo-us-states.esm.min.js +1 -1
- package/modules/geo-world-110m.d.ts +1 -1
- package/modules/geo-world-110m.esm.min.js +1 -1
- package/modules/geo-world-50m.d.ts +1 -1
- package/modules/geo-world-50m.esm.min.js +1 -1
- package/modules/htmx.d.ts +1 -1
- package/modules/htmx.esm.min.js +32 -10
- package/modules/htmx.min.cjs +32 -10
- package/modules/htmx.min.js +32 -10
- package/modules/kanban.d.ts +233 -1
- package/modules/kanban.esm.min.js +3 -3
- package/modules/kanban.min.cjs +3 -3
- package/modules/kanban.min.js +3 -3
- package/modules/kpi.d.ts +196 -8
- package/modules/kpi.esm.min.js +32 -7
- package/modules/kpi.min.cjs +32 -7
- package/modules/kpi.min.js +32 -7
- package/modules/layout.d.ts +117 -1
- package/modules/layout.esm.min.js +3 -3
- package/modules/layout.min.cjs +3 -3
- package/modules/layout.min.js +3 -3
- package/modules/mock-socket.d.ts +6 -1
- package/modules/mock-socket.esm.min.js +1 -1
- package/modules/mock-socket.min.cjs +1 -1
- package/modules/mock-socket.min.js +1 -1
- package/modules/react.d.ts +14 -1
- package/modules/react.esm.min.js +3 -3
- package/modules/react.min.cjs +3 -3
- package/modules/react.min.js +3 -3
- package/modules/svelte.d.ts +1 -1
- package/modules/svelte.esm.min.js +3 -3
- package/modules/svelte.min.cjs +3 -3
- package/modules/svelte.min.js +3 -3
- package/modules/tabs.d.ts +30 -1
- package/modules/tabs.esm.min.js +13 -14
- package/modules/tabs.min.cjs +13 -14
- package/modules/tabs.min.js +13 -14
- package/modules/vue.d.ts +8 -1
- package/modules/vue.esm.min.js +3 -3
- package/modules/vue.min.cjs +3 -3
- package/modules/vue.min.js +3 -3
- package/modules/webcomponent.d.ts +113 -1
- package/modules/webcomponent.esm.min.js +32 -10
- package/modules/webcomponent.min.cjs +32 -10
- package/modules/webcomponent.min.js +32 -10
- package/package.json +1 -1
package/modules/data-router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.68.1, data-router module type declarations
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -53,7 +53,16 @@ type RouteWhere = Record<string, unknown>;
|
|
|
53
53
|
* shorthand (`sum`, `avg`, `min`, `max`, `count`).
|
|
54
54
|
*/
|
|
55
55
|
interface RouteRollup {
|
|
56
|
+
/**
|
|
57
|
+
* What identifies a group: a property name, a `fn(row)`, or a list of either for a
|
|
58
|
+
* composite. Named properties are carried onto the summary row.
|
|
59
|
+
*/
|
|
56
60
|
groupBy: RouterKey | RouterKey[];
|
|
61
|
+
/**
|
|
62
|
+
* The summary fields, each a reducer over the group's rows: a function handed the rows,
|
|
63
|
+
* or `{ op, field }` for `count`, `sum`, `avg`, `min` or `max` over the numeric values
|
|
64
|
+
* of `field`. `avg` over no numeric values is 0; `min` and `max` are undefined.
|
|
65
|
+
*/
|
|
57
66
|
aggregate?: Record<string, ((rows: RouterRecord[]) => unknown) | { op: string; field?: string }>;
|
|
58
67
|
}
|
|
59
68
|
|
|
@@ -81,16 +90,68 @@ type RouterWrite = Record<string, unknown>;
|
|
|
81
90
|
* refresh under load (v13).
|
|
82
91
|
*/
|
|
83
92
|
interface RouteOptions {
|
|
93
|
+
/**
|
|
94
|
+
* What identifies a row on this route — a field name or a `fn(row)` — overriding the
|
|
95
|
+
* router's own `rowKey`.
|
|
96
|
+
*/
|
|
84
97
|
rowKey?: RouterKey;
|
|
98
|
+
/**
|
|
99
|
+
* Reshapes each row before the viewer sees it. The row's identity is still taken from
|
|
100
|
+
* the original, so the keyed diff is unaffected; a transform route is derived and its
|
|
101
|
+
* edits are always reverted.
|
|
102
|
+
*/
|
|
85
103
|
transform?: (row: RouterRecord) => RouterRecord;
|
|
104
|
+
/**
|
|
105
|
+
* Admits a subset of the route's partition to the viewer. It runs on the original row,
|
|
106
|
+
* before any transform and before a rollup groups them.
|
|
107
|
+
*/
|
|
86
108
|
filter?: (row: RouterRecord) => boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Orders the rows the viewer receives — a comparator, or `{ key, dir }`. A viewer with
|
|
111
|
+
* a sort model of its own still governs the final display; for a rollup route this
|
|
112
|
+
* sorts the summary rows.
|
|
113
|
+
*/
|
|
87
114
|
sort?: RouteSort;
|
|
115
|
+
/**
|
|
116
|
+
* Feeds the viewer one summary row per group instead of the raw rows. A rollup route is
|
|
117
|
+
* derived and its edits are always reverted.
|
|
118
|
+
*/
|
|
88
119
|
rollup?: RouteRollup;
|
|
120
|
+
/**
|
|
121
|
+
* A filter-wire condition for this route's slice, read only by `query()`: the pushable
|
|
122
|
+
* part goes to the engine and the rest is finished in the browser. It has no effect on
|
|
123
|
+
* rows arriving through `load`, `apply` or `push`.
|
|
124
|
+
*/
|
|
89
125
|
where?: RouteWhere;
|
|
126
|
+
/**
|
|
127
|
+
* Captures the viewer's committed edits and routes them to `onWrite` instead of leaving
|
|
128
|
+
* them local. Defaults to false; on a derived (rollup or transform) route the edit is
|
|
129
|
+
* reverted with a warning whatever this says.
|
|
130
|
+
*/
|
|
90
131
|
writable?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Receives each captured edit as `{ key, colId, value, before, row }`. Return `false`
|
|
134
|
+
* or `{ ok: false }` (or reject, or throw) to revert the cell, `{ conflict, row }` to
|
|
135
|
+
* fire `onConflict` and take the winning row, anything else to accept; a promise is
|
|
136
|
+
* awaited with the optimistic value standing. Overrides the router-wide handler. The
|
|
137
|
+
* context's `route` is the viewer; `source` is always null.
|
|
138
|
+
*/
|
|
91
139
|
onWrite?: (change: RouterWrite, ctx: { route: unknown; source: unknown }) => unknown;
|
|
140
|
+
/**
|
|
141
|
+
* Called when `onWrite` returns a `conflict`, with the server's row, so the host can
|
|
142
|
+
* tell the user. The router itself is last-write-wins: the returned row (or the
|
|
143
|
+
* optimistic one) re-enters regardless. Overrides the router-wide handler.
|
|
144
|
+
*/
|
|
92
145
|
onConflict?: (change: RouterWrite, ctx: { serverRow: RouterRecord }) => void;
|
|
146
|
+
/**
|
|
147
|
+
* Names this route in `metrics()` and the devtools panel. Defaults to null — the
|
|
148
|
+
* default route reports `default`.
|
|
149
|
+
*/
|
|
93
150
|
label?: string;
|
|
151
|
+
/**
|
|
152
|
+
* Throttles how often this route's viewer is refreshed under load. Omitted, every
|
|
153
|
+
* change repaints the viewer at once.
|
|
154
|
+
*/
|
|
94
155
|
backpressure?: RouteBackpressure;
|
|
95
156
|
}
|
|
96
157
|
|
|
@@ -120,9 +181,26 @@ interface RouterEdge { from: unknown; to: unknown; on?: SelectionRelation; relat
|
|
|
120
181
|
* spec. Desugars to those calls and composes with them.
|
|
121
182
|
*/
|
|
122
183
|
interface RouterConfig {
|
|
184
|
+
/**
|
|
185
|
+
* The routes to open, each `{ grid, when, ...routeOptions }`, or `{ default: grid }`,
|
|
186
|
+
* or `{ subscribe: handler, when }`, or `{ alert: handler, when, condition }`. `when`
|
|
187
|
+
* is the partition value or predicate `attach` takes.
|
|
188
|
+
*/
|
|
123
189
|
routes?: Record<string, unknown>[];
|
|
190
|
+
/**
|
|
191
|
+
* Selection links to make, each naming the `from` and `to` grids and the relation as
|
|
192
|
+
* `on` (or `relation`) — the arguments of `link()`.
|
|
193
|
+
*/
|
|
124
194
|
links?: { from: unknown; to: unknown; on?: SelectionRelation; relation?: SelectionRelation }[];
|
|
195
|
+
/**
|
|
196
|
+
* Relationship-graph edges to register, as `relate()` takes them; an edge may be
|
|
197
|
+
* `mutual` to work in both directions.
|
|
198
|
+
*/
|
|
125
199
|
relate?: RouterEdge[];
|
|
200
|
+
/**
|
|
201
|
+
* Turns on the time-travel buffer, bounded by `window` (ms of feed time) and/or `max`
|
|
202
|
+
* deltas. An empty object applies a default cap of 10,000 deltas and warns.
|
|
203
|
+
*/
|
|
126
204
|
buffer?: { window?: number; max?: number };
|
|
127
205
|
}
|
|
128
206
|
|
|
@@ -136,13 +214,37 @@ interface RouterConfig {
|
|
|
136
214
|
* `passthrough` it unjoined, or fill the fields with `null`.
|
|
137
215
|
*/
|
|
138
216
|
interface RouterJoin {
|
|
217
|
+
/** The id of the registered source holding the lookup rows. */
|
|
139
218
|
from: string;
|
|
219
|
+
/**
|
|
220
|
+
* Reads the joining value off this source's row — a field name or a `fn(row)`.
|
|
221
|
+
* Required: without it (or `on`) the join is ignored with a warning.
|
|
222
|
+
*/
|
|
140
223
|
localKey?: RouterKey;
|
|
224
|
+
/** An alias for `localKey`, read when `localKey` is absent. */
|
|
141
225
|
on?: RouterKey;
|
|
226
|
+
/**
|
|
227
|
+
* Reads the joining value off the lookup row — a field name or a `fn(row)`. Defaults to
|
|
228
|
+
* a string `localKey`; with a function `localKey` and no `foreignKey`, the join is
|
|
229
|
+
* ignored with a warning.
|
|
230
|
+
*/
|
|
142
231
|
foreignKey?: RouterKey;
|
|
232
|
+
/** An alias for `foreignKey`, read when `foreignKey` is absent. */
|
|
143
233
|
fromKey?: RouterKey;
|
|
234
|
+
/**
|
|
235
|
+
* Which lookup fields to carry onto the row: a list of names, a `{ from: to }` rename
|
|
236
|
+
* map, or a `fn(lookupRow, leftRow)` returning the fields to merge. With none, rows
|
|
237
|
+
* pass through unenriched and the router warns.
|
|
238
|
+
*/
|
|
144
239
|
fields?: string[] | Record<string, string> | ((lookupRow: RouterRecord | null, leftRow: RouterRecord) => RouterRecord);
|
|
240
|
+
/** An alias for `fields`, read when `fields` is absent. */
|
|
145
241
|
select?: string[] | Record<string, string> | ((lookupRow: RouterRecord | null, leftRow: RouterRecord) => RouterRecord);
|
|
242
|
+
/**
|
|
243
|
+
* What happens while the lookup row has not arrived: `hold` keeps the row from viewers
|
|
244
|
+
* until it does, `passthrough` sends it unenriched, `null` fills the declared fields
|
|
245
|
+
* with null. Defaults to `passthrough`, which an unrecognised value also falls back to,
|
|
246
|
+
* with a warning.
|
|
247
|
+
*/
|
|
146
248
|
missing?: 'hold' | 'passthrough' | 'null';
|
|
147
249
|
}
|
|
148
250
|
|
|
@@ -178,9 +280,19 @@ interface RouterSourceHandle {
|
|
|
178
280
|
|
|
179
281
|
/** One route's figures in a `metrics()` snapshot (v10). */
|
|
180
282
|
interface RouterRouteMetrics {
|
|
283
|
+
/** The route's `label`, or `default` for the default route, or null when it has neither. */
|
|
181
284
|
label: string | null;
|
|
285
|
+
/** How many rows the route's partition holds, before its filter, links and rollup. */
|
|
182
286
|
rows: number;
|
|
287
|
+
/**
|
|
288
|
+
* How many rows the viewer currently holds — the partition after the route's filter,
|
|
289
|
+
* any cross-grid links, and a rollup's grouping.
|
|
290
|
+
*/
|
|
183
291
|
shown: number;
|
|
292
|
+
/**
|
|
293
|
+
* Rows routed to this route per second since the previous metrics read. The first read
|
|
294
|
+
* of a route reports 0, having no interval to measure.
|
|
295
|
+
*/
|
|
184
296
|
throughput: number;
|
|
185
297
|
[key: string]: unknown;
|
|
186
298
|
}
|
|
@@ -194,12 +306,31 @@ interface RouterSourceMetrics { id: string; rows: number; throughput: number; [k
|
|
|
194
306
|
* dropped (duplicate), buffered and lag figures.
|
|
195
307
|
*/
|
|
196
308
|
interface RouterMetrics {
|
|
309
|
+
/** One entry per route, in attach order, the default route last. */
|
|
197
310
|
routes: RouterRouteMetrics[];
|
|
311
|
+
/** One entry per registered fan-in source. */
|
|
198
312
|
sources: RouterSourceMetrics[];
|
|
313
|
+
/**
|
|
314
|
+
* How many arriving records matched no route (and went to the default sink, if there is
|
|
315
|
+
* one). Counted since the last `load()` or `query()`, each of which resets it.
|
|
316
|
+
*/
|
|
199
317
|
unrouted: number;
|
|
318
|
+
/**
|
|
319
|
+
* How many deltas the dedupe gate discarded as stale or already seen, cumulative for
|
|
320
|
+
* the router's life.
|
|
321
|
+
*/
|
|
200
322
|
dropped: number;
|
|
323
|
+
/** How many deltas the time-travel ring currently holds. Zero when not buffering. */
|
|
201
324
|
buffered: number;
|
|
325
|
+
/**
|
|
326
|
+
* How many buffered deltas the viewers are behind the live head, in deltas. Nonzero
|
|
327
|
+
* only while scrubbed into the past.
|
|
328
|
+
*/
|
|
202
329
|
lag: number;
|
|
330
|
+
/**
|
|
331
|
+
* Rows routed across every route per second since the previous metrics read; 0 on the
|
|
332
|
+
* first read.
|
|
333
|
+
*/
|
|
203
334
|
throughput: number;
|
|
204
335
|
}
|
|
205
336
|
|
|
@@ -220,7 +351,17 @@ interface RouterDevtoolsPanel { refresh(): void; destroy(): void }
|
|
|
220
351
|
* `capabilities` the planner consults to decide what it may push down.
|
|
221
352
|
*/
|
|
222
353
|
interface RouterQueryAdapter {
|
|
354
|
+
/**
|
|
355
|
+
* What the engine can evaluate, as the pushdown capability model reads it; the planner
|
|
356
|
+
* consults it to decide how much of a filter to push down. Omitted, the conservative
|
|
357
|
+
* defaults apply.
|
|
358
|
+
*/
|
|
223
359
|
capabilities?: Record<string, unknown>;
|
|
360
|
+
/**
|
|
361
|
+
* Runs one planned query and resolves to its rows (`total` optional and unused by the
|
|
362
|
+
* router). Called once per `where` route, plus once for the base query shared by the
|
|
363
|
+
* routes without one.
|
|
364
|
+
*/
|
|
224
365
|
execute: (query: Record<string, unknown>, request?: Record<string, unknown>) => Promise<{ rows: RouterRecord[]; total?: number }>;
|
|
225
366
|
}
|
|
226
367
|
|
|
@@ -230,11 +371,24 @@ interface RouterQueryAdapter {
|
|
|
230
371
|
* `indexedDB` / `dbName` / `storeName` select the browser store.
|
|
231
372
|
*/
|
|
232
373
|
interface RouterPersistOptions {
|
|
374
|
+
/** The record the snapshot is written under. Defaults to `lattice-router`. */
|
|
233
375
|
key?: string;
|
|
376
|
+
/**
|
|
377
|
+
* How long to wait after a change before writing, in ms, so a burst costs one write.
|
|
378
|
+
* Defaults to 250; zero or less writes on every change.
|
|
379
|
+
*/
|
|
234
380
|
debounce?: number;
|
|
381
|
+
/** An async key/value backend of your own. Given one, IndexedDB is never opened. */
|
|
235
382
|
storage?: { get: (key: string) => Promise<unknown>; set: (key: string, value: unknown) => Promise<void> };
|
|
383
|
+
/**
|
|
384
|
+
* The `IDBFactory` to open the database with. Defaults to the global `indexedDB`; where
|
|
385
|
+
* none is reachable the router warns once and keeps running in memory with no durable
|
|
386
|
+
* resume.
|
|
387
|
+
*/
|
|
236
388
|
indexedDB?: unknown;
|
|
389
|
+
/** The IndexedDB database to open. Defaults to `lattice-router`. */
|
|
237
390
|
dbName?: string;
|
|
391
|
+
/** The object store inside the database. Defaults to `snapshots`. */
|
|
238
392
|
storeName?: string;
|
|
239
393
|
}
|
|
240
394
|
|
|
@@ -356,20 +510,92 @@ interface DataRouter {
|
|
|
356
510
|
* disables the timer) (v10).
|
|
357
511
|
*/
|
|
358
512
|
interface DataRouterOptions {
|
|
513
|
+
/**
|
|
514
|
+
* How a record says which partition it belongs to: a property name, or a
|
|
515
|
+
* function of the record. This is the one thing the router needs to route.
|
|
516
|
+
*/
|
|
359
517
|
key?: RouterKey;
|
|
518
|
+
/**
|
|
519
|
+
* A record's identity within a route — a property name or a function. It
|
|
520
|
+
* is what makes an update an update rather than a second row, and what
|
|
521
|
+
* lets a record whose partition changed *move* between routes instead of
|
|
522
|
+
* being duplicated. Defaults to the record's `rowKey` property.
|
|
523
|
+
*/
|
|
360
524
|
rowKey?: RouterKey;
|
|
525
|
+
/**
|
|
526
|
+
* Send a record to every route whose predicate it matches, rather than to
|
|
527
|
+
* the first one only. Off by default.
|
|
528
|
+
*/
|
|
361
529
|
overlap?: boolean;
|
|
530
|
+
/**
|
|
531
|
+
* Called with each record that matched no route. They are never silently
|
|
532
|
+
* dropped: they are counted as well, and go to the default route when one
|
|
533
|
+
* is attached.
|
|
534
|
+
*/
|
|
362
535
|
onUnrouted?: (item: RouterRecord | RouterDelta) => void;
|
|
536
|
+
/**
|
|
537
|
+
* How long, in milliseconds, to wait before re-filtering linked grids
|
|
538
|
+
* after a selection changes. 16 by default; `0` re-filters synchronously.
|
|
539
|
+
*/
|
|
363
540
|
selectionDebounce?: number;
|
|
541
|
+
/**
|
|
542
|
+
* Where a record carries its version or sequence number — a property name
|
|
543
|
+
* or a function. Supplying it lets the router apply a feed in order and,
|
|
544
|
+
* unless `dedupe` says otherwise, drop a delta it has already seen.
|
|
545
|
+
*/
|
|
364
546
|
seq?: RouterKey;
|
|
547
|
+
/**
|
|
548
|
+
* Whether to drop a record whose sequence number is not newer than the
|
|
549
|
+
* last one applied for that identity. On whenever `seq` is given;
|
|
550
|
+
* meaningless without it.
|
|
551
|
+
*/
|
|
365
552
|
dedupe?: boolean;
|
|
553
|
+
/**
|
|
554
|
+
* Buffer incoming records and apply them on an interval rather than one at
|
|
555
|
+
* a time: a number of milliseconds, or `{ intervalMs }`. Batching also
|
|
556
|
+
* turns coalescing on.
|
|
557
|
+
*/
|
|
366
558
|
batch?: number | { intervalMs: number };
|
|
559
|
+
/**
|
|
560
|
+
* Settle repeated updates to the same identity inside one batch into a
|
|
561
|
+
* single apply, so a fast feed costs one update per row rather than one
|
|
562
|
+
* per message.
|
|
563
|
+
*/
|
|
367
564
|
coalesce?: boolean;
|
|
565
|
+
/**
|
|
566
|
+
* Where a record carries its timestamp — a property name or a function. It
|
|
567
|
+
* is the axis `scrubTo` and `replay` move along when time-travel is
|
|
568
|
+
* buffering.
|
|
569
|
+
*/
|
|
368
570
|
time?: RouterKey;
|
|
571
|
+
/**
|
|
572
|
+
* The clock the router stamps and expires by. `Date.now` unless you supply
|
|
573
|
+
* one, which is how a test drives time without faking the global.
|
|
574
|
+
*/
|
|
369
575
|
now?: () => number;
|
|
576
|
+
/**
|
|
577
|
+
* A whole router described as data — routes, links, buffering — applied
|
|
578
|
+
* through `configure()` as soon as the router is built.
|
|
579
|
+
*/
|
|
370
580
|
config?: RouterConfig;
|
|
581
|
+
/**
|
|
582
|
+
* Persist an edit committed in any route attached `{ writable: true }`
|
|
583
|
+
* that names no handler of its own. Return, or resolve, falsely to revert
|
|
584
|
+
* the edit; a route with neither this nor its own handler leaves the edit
|
|
585
|
+
* in place unpersisted and warns.
|
|
586
|
+
*/
|
|
371
587
|
onWrite?: (change: RouterWrite, ctx: { route: unknown; source: unknown }) => unknown;
|
|
588
|
+
/**
|
|
589
|
+
* Called when a write comes back reporting a conflict, with the server's
|
|
590
|
+
* version of the row. The router itself is last-write-wins; this is where
|
|
591
|
+
* a host resolves it differently.
|
|
592
|
+
*/
|
|
372
593
|
onConflict?: (change: RouterWrite, ctx: { serverRow: RouterRecord }) => void;
|
|
594
|
+
/**
|
|
595
|
+
* How often, in milliseconds, to emit the `metrics` event. 1000 by
|
|
596
|
+
* default; `0` stops the timer and leaves `metrics()` to be read on
|
|
597
|
+
* demand.
|
|
598
|
+
*/
|
|
373
599
|
metricsInterval?: number;
|
|
374
600
|
}
|
|
375
601
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.68.1, data-router module
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -52,12 +52,12 @@ Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){r
|
|
|
52
52
|
Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
|
|
53
53
|
Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
|
|
54
54
|
Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
|
|
55
|
-
const STAMPED_VERSION="1.
|
|
55
|
+
const STAMPED_VERSION="1.68.1";
|
|
56
56
|
async function resolveVersion(){
|
|
57
57
|
if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
|
|
58
58
|
return STAMPED_VERSION;
|
|
59
59
|
}
|
|
60
|
-
const VERSION="1.
|
|
60
|
+
const VERSION="1.68.1";
|
|
61
61
|
const warned=new Set();
|
|
62
62
|
const WARNED_LIMIT=2000;
|
|
63
63
|
function rememberWarned(key){
|
|
@@ -1544,6 +1544,180 @@ grandTotals:()=>lastGrand,
|
|
|
1544
1544
|
};
|
|
1545
1545
|
}
|
|
1546
1546
|
});
|
|
1547
|
+
__def("packages/core/src/model/rowkey.js",function(__exports,__req){
|
|
1548
|
+
'use strict';
|
|
1549
|
+
Object.defineProperty(__exports,"KEY_DEPENDENT_FEATURES",{enumerable:true,get:function(){return KEY_DEPENDENT_FEATURES;}});
|
|
1550
|
+
Object.defineProperty(__exports,"compositeKey",{enumerable:true,get:function(){return compositeKey;}});
|
|
1551
|
+
Object.defineProperty(__exports,"createRowKey",{enumerable:true,get:function(){return createRowKey;}});
|
|
1552
|
+
Object.defineProperty(__exports,"warnMissingKeys",{enumerable:true,get:function(){return warnMissingKeys;}});
|
|
1553
|
+
Object.defineProperty(__exports,"groupPathKey",{enumerable:true,get:function(){return groupPathKey;}});
|
|
1554
|
+
Object.defineProperty(__exports,"splitPathKey",{enumerable:true,get:function(){return splitPathKey;}});
|
|
1555
|
+
const __m0=__req("packages/core/src/internal/util.js");
|
|
1556
|
+
const warnOnce=__m0["warnOnce"];
|
|
1557
|
+
const pathGetter=__m0["pathGetter"];
|
|
1558
|
+
const isFunction=__m0["isFunction"];
|
|
1559
|
+
const isBlank=__m0["isBlank"];
|
|
1560
|
+
const KEY_DEPENDENT_FEATURES=[
|
|
1561
|
+
'changes (rows.apply / rows.queue)',
|
|
1562
|
+
'streaming dedupe',
|
|
1563
|
+
'selection persistence',
|
|
1564
|
+
'remote reload',
|
|
1565
|
+
'cell comments',
|
|
1566
|
+
];
|
|
1567
|
+
const SEP='\u001f';
|
|
1568
|
+
function part(value){
|
|
1569
|
+
if(value===null)return'\u0000n';
|
|
1570
|
+
if(value===undefined)return'\u0000u';
|
|
1571
|
+
const t=typeof value;
|
|
1572
|
+
if(t==='string')return value;
|
|
1573
|
+
if(t==='number'||t==='bigint'||t==='boolean')return String(value);
|
|
1574
|
+
if(value instanceof Date)return`\u0000d${value.getTime()}`;
|
|
1575
|
+
try{
|
|
1576
|
+
return`\u0000o${JSON.stringify(value)}`;
|
|
1577
|
+
}catch{
|
|
1578
|
+
return'\u0000o?';
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
function compositeKey(parts){
|
|
1582
|
+
if(parts.length===1)return part(parts[0]);
|
|
1583
|
+
let out='';
|
|
1584
|
+
for(let i=0;i<parts.length;i++){
|
|
1585
|
+
if(i)out+=SEP;
|
|
1586
|
+
out+=part(parts[i]);
|
|
1587
|
+
}
|
|
1588
|
+
return out;
|
|
1589
|
+
}
|
|
1590
|
+
function createRowKey(spec,opts={}){
|
|
1591
|
+
const warn=opts.warn!==false;
|
|
1592
|
+
if(isFunction(spec)){
|
|
1593
|
+
const fn=(spec);
|
|
1594
|
+
return{
|
|
1595
|
+
stable:true,
|
|
1596
|
+
fields:[],
|
|
1597
|
+
disabled:[],
|
|
1598
|
+
key(data,index){
|
|
1599
|
+
try{
|
|
1600
|
+
const value=fn(data);
|
|
1601
|
+
return Array.isArray(value)?compositeKey(value):part(value);
|
|
1602
|
+
}catch(err){
|
|
1603
|
+
warnOnce('rowKey.throw','rowKey function threw; falling back to index identity for the affected rows.',err);
|
|
1604
|
+
return`#${index??-1}`;
|
|
1605
|
+
}
|
|
1606
|
+
},
|
|
1607
|
+
keyEmpty(data){
|
|
1608
|
+
try{
|
|
1609
|
+
const value=fn(data);
|
|
1610
|
+
return Array.isArray(value)?value.length===0||value.some(isBlank):isBlank(value);
|
|
1611
|
+
}catch{
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
missingFields(){return[];},
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
if(Array.isArray(spec)&&spec.length>0){
|
|
1619
|
+
const fields=spec.filter((f)=>typeof f==='string');
|
|
1620
|
+
const getters=fields.map((f)=>pathGetter(f));
|
|
1621
|
+
const n=getters.length;
|
|
1622
|
+
return{
|
|
1623
|
+
stable:true,
|
|
1624
|
+
fields,
|
|
1625
|
+
disabled:[],
|
|
1626
|
+
key(data){
|
|
1627
|
+
const parts=new Array(n);
|
|
1628
|
+
for(let i=0;i<n;i++)parts[i]=getters[i](data);
|
|
1629
|
+
return compositeKey(parts);
|
|
1630
|
+
},
|
|
1631
|
+
keyEmpty(data){
|
|
1632
|
+
for(let i=0;i<n;i++)if(isBlank(getters[i](data)))return true;
|
|
1633
|
+
return false;
|
|
1634
|
+
},
|
|
1635
|
+
missingFields(data){
|
|
1636
|
+
const out=[];
|
|
1637
|
+
for(let i=0;i<n;i++)if(isBlank(getters[i](data)))out.push(fields[i]);
|
|
1638
|
+
return out;
|
|
1639
|
+
},
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
if(typeof spec==='string'&&spec.length>0){
|
|
1643
|
+
const get=pathGetter(spec);
|
|
1644
|
+
return{
|
|
1645
|
+
stable:true,
|
|
1646
|
+
fields:[spec],
|
|
1647
|
+
disabled:[],
|
|
1648
|
+
key(data){
|
|
1649
|
+
return part(get(data));
|
|
1650
|
+
},
|
|
1651
|
+
keyEmpty(data){
|
|
1652
|
+
return isBlank(get(data));
|
|
1653
|
+
},
|
|
1654
|
+
missingFields(data){
|
|
1655
|
+
return isBlank(get(data))?[spec]:[];
|
|
1656
|
+
},
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
if(warn){
|
|
1660
|
+
warnOnce(
|
|
1661
|
+
'rowKey.missing',
|
|
1662
|
+
`no rowKey configured, so rows are identified by object identity. This disables: ${KEY_DEPENDENT_FEATURES.join(', ')}. Set rowKey to a field name, an array of field names, or a function.`,
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
return{
|
|
1666
|
+
stable:false,
|
|
1667
|
+
fields:[],
|
|
1668
|
+
disabled:KEY_DEPENDENT_FEATURES.slice(),
|
|
1669
|
+
key(data,index){
|
|
1670
|
+
if(data===null||typeof data!=='object'){
|
|
1671
|
+
return`#${index??0}:${String(data)}`;
|
|
1672
|
+
}
|
|
1673
|
+
let assigned=autoKeys.get(data);
|
|
1674
|
+
if(assigned===undefined){
|
|
1675
|
+
assigned=`#${autoKeySeq++}`;
|
|
1676
|
+
autoKeys.set(data,assigned);
|
|
1677
|
+
}
|
|
1678
|
+
return assigned;
|
|
1679
|
+
},
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
const autoKeys=new WeakMap();
|
|
1683
|
+
let autoKeySeq=0;
|
|
1684
|
+
function warnMissingKeys(resolver,rows){
|
|
1685
|
+
if(!resolver||resolver.stable===false||!isFunction(resolver.keyEmpty))return;
|
|
1686
|
+
if(!Array.isArray(rows)||rows.length===0)return;
|
|
1687
|
+
let missing=0;
|
|
1688
|
+
let sampleFields=null;
|
|
1689
|
+
let sampleData;
|
|
1690
|
+
for(let i=0;i<rows.length;i++){
|
|
1691
|
+
const data=rows[i];
|
|
1692
|
+
if(!resolver.keyEmpty(data))continue;
|
|
1693
|
+
missing++;
|
|
1694
|
+
if(sampleFields===null){
|
|
1695
|
+
sampleFields=isFunction(resolver.missingFields)?resolver.missingFields(data):[];
|
|
1696
|
+
sampleData=data;
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
if(missing===0)return;
|
|
1700
|
+
const dedupFields=resolver.fields.length?resolver.fields.join(','):'(function)';
|
|
1701
|
+
const named=sampleFields&&sampleFields.length
|
|
1702
|
+
?sampleFields.join(', ')
|
|
1703
|
+
:(resolver.fields.length?resolver.fields.join(', '):'the rowKey function');
|
|
1704
|
+
const present=sampleData!==null&&typeof sampleData==='object'
|
|
1705
|
+
?(Object.keys((sampleData)).join(', ')||'(no fields)')
|
|
1706
|
+
:String(sampleData);
|
|
1707
|
+
warnOnce(
|
|
1708
|
+
`rowKey.emptyValue:${dedupFields}`,
|
|
1709
|
+
`rowKey ${named} is missing on ${missing} of ${rows.length} rows; the first such row has: ${present}. `
|
|
1710
|
+
+'Rows without a key value collapse onto one key, so selection, edits and rows.apply updates land on '
|
|
1711
|
+
+'whichever row now shares it. Set rowKey to a field present on every row, or fix the source data.',
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
function groupPathKey(path){
|
|
1715
|
+
return compositeKey(path);
|
|
1716
|
+
}
|
|
1717
|
+
function splitPathKey(key){
|
|
1718
|
+
return key.split(SEP);
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1547
1721
|
__def("packages/modules/data-router/devtools.js",function(__exports,__req){
|
|
1548
1722
|
'use strict';
|
|
1549
1723
|
Object.defineProperty(__exports,"mountRouterDevtools",{enumerable:true,get:function(){return mountRouterDevtools;}});
|
|
@@ -1629,8 +1803,10 @@ const warnOnce=__m0["warnOnce"];
|
|
|
1629
1803
|
const __m1=__req("packages/core/src/source/pushdown.js");
|
|
1630
1804
|
const planQuery=__m1["planQuery"];
|
|
1631
1805
|
const capabilitiesOf=__m1["capabilitiesOf"];
|
|
1632
|
-
const __m2=__req("packages/
|
|
1633
|
-
const
|
|
1806
|
+
const __m2=__req("packages/core/src/model/rowkey.js");
|
|
1807
|
+
const compositeKey=__m2["compositeKey"];
|
|
1808
|
+
const __m3=__req("packages/modules/data-router/devtools.js");
|
|
1809
|
+
const mountRouterDevtools=__m3["mountRouterDevtools"];
|
|
1634
1810
|
function resolver(spec,fallback){
|
|
1635
1811
|
if(typeof spec==='function')return spec;
|
|
1636
1812
|
if(typeof spec==='string')return(row)=>row[spec];
|
|
@@ -1683,6 +1859,8 @@ const maxLag=(Number.isFinite(spec.maxLag)&&spec.maxLag>=0)?Math.floor(Number(sp
|
|
|
1683
1859
|
if(minInterval===0&&sample===1&&maxLag===null)return null;
|
|
1684
1860
|
return{minInterval,sample,maxLag};
|
|
1685
1861
|
}
|
|
1862
|
+
let routeSeq=0;
|
|
1863
|
+
function nextRouteId(){routeSeq+=1;return`r${routeSeq}`;}
|
|
1686
1864
|
function grouper(groupBy){
|
|
1687
1865
|
const specs=Array.isArray(groupBy)?groupBy:[groupBy];
|
|
1688
1866
|
const parts=specs.map((s)=>({name:typeof s==='string'?s:null,get:resolver(s,()=>undefined)}));
|
|
@@ -1694,7 +1872,7 @@ const v=part.get(row);
|
|
|
1694
1872
|
vals.push(v);
|
|
1695
1873
|
if(part.name)fields[part.name]=v;
|
|
1696
1874
|
}
|
|
1697
|
-
return{key:vals
|
|
1875
|
+
return{key:compositeKey(vals),fields};
|
|
1698
1876
|
};
|
|
1699
1877
|
}
|
|
1700
1878
|
function aggregateOne(spec,rows){
|
|
@@ -1863,10 +2041,25 @@ return fallbackRoute?[fallbackRoute]:[];
|
|
|
1863
2041
|
};
|
|
1864
2042
|
const applyChange=(route,change)=>{
|
|
1865
2043
|
if(change.add.length||change.update.length||change.remove.length){
|
|
1866
|
-
route.sink(change);
|
|
2044
|
+
const result=route.sink(change);
|
|
2045
|
+
warnRejectedRemovals(route,result);
|
|
1867
2046
|
}
|
|
1868
2047
|
return{added:change.add.length,updated:change.update.length,removed:change.remove.length};
|
|
1869
2048
|
};
|
|
2049
|
+
const warnRejectedRemovals=(route,result)=>{
|
|
2050
|
+
const rejected=(result)?.rejected;
|
|
2051
|
+
if(!Array.isArray(rejected)||!rejected.length)return;
|
|
2052
|
+
const removals=rejected.filter((r)=>r&&r.operation==='remove');
|
|
2053
|
+
if(!removals.length)return;
|
|
2054
|
+
const name=route.label||`route ${route.routeId}`;
|
|
2055
|
+
warnOnce(
|
|
2056
|
+
`data-router:remove-rejected:${route.routeId}`,
|
|
2057
|
+
`route "${name}" asked its target to remove ${removals.length} row(s) the target does not have`
|
|
2058
|
+
+` (for example ${JSON.stringify(String(removals[0].id))}). The rows are still on screen.`
|
|
2059
|
+
+' This is a key mismatch: the key the route derives for a row is not the key the grid derives'
|
|
2060
|
+
+' for it. Check that the route\'s `rowKey` names the same value as the grid\'s.',
|
|
2061
|
+
);
|
|
2062
|
+
};
|
|
1870
2063
|
const passes=(route,row)=>{
|
|
1871
2064
|
for(const link of links){
|
|
1872
2065
|
if(link.to!==route.grid)continue;
|
|
@@ -1904,7 +2097,9 @@ shown=new Map(summaries.map((s)=>[s.gkey,s.row]));
|
|
|
1904
2097
|
let rows=kept;
|
|
1905
2098
|
if(route.sort)rows=rows.slice().sort(route.sort);
|
|
1906
2099
|
shown=new Map();
|
|
1907
|
-
for(const row of rows)
|
|
2100
|
+
for(const row of rows){
|
|
2101
|
+
shown.set(compositeKey([route.keyOf(row)]),route.transform?route.transform(row):row);
|
|
2102
|
+
}
|
|
1908
2103
|
}
|
|
1909
2104
|
const add=[];
|
|
1910
2105
|
const update=[];
|
|
@@ -2053,6 +2248,7 @@ return()=>{};
|
|
|
2053
2248
|
};
|
|
2054
2249
|
const makeRoute=(grid,match,o)=>({
|
|
2055
2250
|
grid,
|
|
2251
|
+
routeId:nextRouteId(),
|
|
2056
2252
|
sink:targetSink(grid),
|
|
2057
2253
|
match,
|
|
2058
2254
|
keyOf:resolver(assertRowKeySpec(o.rowKey,'routes'),defaultKeyOf),
|