@prometheus-ags/entity-graph-core 3.2.0 → 4.0.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 +62 -0
- package/dist/{chunk-BE3BMRKF.mjs → chunk-H7NBREZV.mjs} +17 -5
- package/dist/chunk-H7NBREZV.mjs.map +1 -0
- package/dist/devtools.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +7 -19
- package/dist/chunk-BE3BMRKF.mjs.map +0 -1
- package/dist/devtools.cjs +0 -2571
- package/dist/devtools.cjs.map +0 -1
- package/dist/devtools.d.cts +0 -531
- package/dist/graph-ClW3HD8B.d.cts +0 -990
- package/dist/index.cjs +0 -4199
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2383
package/dist/index.d.cts
DELETED
|
@@ -1,2383 +0,0 @@
|
|
|
1
|
-
import { S as SortSpec, F as FilterSpec, E as EntityType, G as GraphStore$1, a as EntityId, b as SyncOrigin, Q as QueryKey, u as useGraphStore, c as EntitySnapshot, d as EntitySyncMetadata, g as graphStore } from './graph-ClW3HD8B.cjs';
|
|
2
|
-
export { C as CompletenessMode, e as EMPTY_ENTITY_STATE, f as EMPTY_IDS, h as EMPTY_LIST_STATE, i as EMPTY_SYNC_METADATA, j as EntityError, k as EntityErrorOptions, l as EntityState, m as FetchedEntityBatch, n as FetchedListProjection, o as FetchedListTarget, p as FilterClause, q as FilterGroup, r as FilterOperator, s as GraphState, I as IngestFetchedListOptions, L as ListResultMeta, t as ListState, v as SortClause, w as SortDirection, T as TerminalError, x as TransientError, V as ViewDescriptor, y as createGraphStore, z as flattenClauses, A as hasCustomPredicates, B as toEntityError, D as toGraphQLVariables, H as toRestParams, J as toSQLClauses } from './graph-ClW3HD8B.cjs';
|
|
3
|
-
import * as zustand_vanilla from 'zustand/vanilla';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Compiles a {@link FilterSpec} into a Prisma `where` object (plain JSON-serializable shape).
|
|
7
|
-
*
|
|
8
|
-
* Operator mapping matches common Prisma filter APIs: `eq` → `equals`, string ops use `mode: "insensitive"`,
|
|
9
|
-
* `nin` → `notIn`, `arrayContains` → `has`, `isNull` uses `null` / `{ not: null }` per `value`, and `isNotNull` → `{ not: null }`.
|
|
10
|
-
* Unsupported ops (`between`, `arrayOverlaps`, `matches`, `custom`) are omitted from the result.
|
|
11
|
-
*
|
|
12
|
-
* Top-level clause arrays are combined with `AND`. {@link FilterGroup} uses `AND` / `OR` to match `group.logic`.
|
|
13
|
-
*/
|
|
14
|
-
declare function toPrismaWhere(filter: FilterSpec): Record<string, unknown>;
|
|
15
|
-
/**
|
|
16
|
-
* Compiles a {@link SortSpec} into Prisma `orderBy` form: `[{ fieldName: "asc" | "desc" }, …]`.
|
|
17
|
-
* `nulls` and `comparator` on {@link SortClause} are ignored (local-only); extend callers if your Prisma version supports null ordering.
|
|
18
|
-
*/
|
|
19
|
-
declare function toPrismaOrderBy(sort: SortSpec): Record<string, string>[];
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 2.0 transport contract.
|
|
23
|
-
*
|
|
24
|
-
* Why this exists: in 1.x each call site of `useEntityList` /
|
|
25
|
-
* `useEntityView` passed its own `fetch` closure + `normalize`
|
|
26
|
-
* callback. That leaked the transport contract to every consumer and
|
|
27
|
-
* was the structural cause of the Quick Stats trap — each widget could
|
|
28
|
-
* (and did) reinvent the same retry-loop bug.
|
|
29
|
-
*
|
|
30
|
-
* In 2.0 the transport is registered ONCE per entity type at app boot
|
|
31
|
-
* via `registerEntityTransport(type, transport)`. Hooks
|
|
32
|
-
* (`useEntities`, `useEntityQuery`) look up the registered transport
|
|
33
|
-
* by entity type — consumers never pass a fetcher.
|
|
34
|
-
*
|
|
35
|
-
* Transports are pluggable: a built-in `makeRestTransport` covers
|
|
36
|
-
* PostgREST / Supabase; future helpers can cover GraphQL, PGlite-direct,
|
|
37
|
-
* mock-in-memory, etc. The contract is intentionally tiny.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Transport-agnostic list query passed by `useEntities` / `useEntityQuery`
|
|
42
|
-
* down to the registered transport.
|
|
43
|
-
*
|
|
44
|
-
* The transport is responsible for compiling this into the
|
|
45
|
-
* transport-specific wire format (HTTP query string, GraphQL variables,
|
|
46
|
-
* SQL WHERE, in-memory predicate, etc.).
|
|
47
|
-
*/
|
|
48
|
-
interface ListQuery {
|
|
49
|
-
/** Optional filter; transport-agnostic, see `FilterSpec`. */
|
|
50
|
-
filter?: FilterSpec | null;
|
|
51
|
-
/** Optional sort spec; transport-agnostic. */
|
|
52
|
-
sort?: SortSpec | null;
|
|
53
|
-
/** Free-text search string; transport decides which fields to match. */
|
|
54
|
-
search?: string;
|
|
55
|
-
/** Page size hint. Transport may cap or ignore. */
|
|
56
|
-
limit?: number;
|
|
57
|
-
/** Opaque cursor for pagination (cursor or numeric offset). */
|
|
58
|
-
cursor?: string | number | null;
|
|
59
|
-
/** Aborts the request when fired. Transports MUST honour this. */
|
|
60
|
-
signal?: AbortSignal;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Page of results returned by `EntityTransport.list`.
|
|
64
|
-
*
|
|
65
|
-
* `total` is `null` when the backend doesn't report it cheaply
|
|
66
|
-
* (consumers should treat as "unknown" rather than "zero").
|
|
67
|
-
*
|
|
68
|
-
* `nextCursor` is `null`/`undefined` when there are no more pages.
|
|
69
|
-
*/
|
|
70
|
-
interface ListResult<T> {
|
|
71
|
-
rows: T[];
|
|
72
|
-
total: number | null;
|
|
73
|
-
nextCursor?: string | number | null;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Operation flavour for a realtime change event.
|
|
77
|
-
*/
|
|
78
|
-
type ChangeOp = "insert" | "update" | "delete";
|
|
79
|
-
/**
|
|
80
|
-
* Realtime change event emitted by a transport's `subscribe`.
|
|
81
|
-
*
|
|
82
|
-
* For `delete` only `id` is meaningful; `row` MAY be omitted.
|
|
83
|
-
*/
|
|
84
|
-
interface ChangeEvent<T> {
|
|
85
|
-
op: ChangeOp;
|
|
86
|
-
id: string;
|
|
87
|
-
row?: T;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* The full per-entity transport contract.
|
|
91
|
-
*
|
|
92
|
-
* One transport per entity type, registered at app boot. The hooks
|
|
93
|
-
* (`useEntities`, `useEntityQuery`) look it up via `getEntityTransport(type)`.
|
|
94
|
-
*
|
|
95
|
-
* Required: `identify`, `authoritative`, `list`.
|
|
96
|
-
* Optional: `get` (for single-row fetches), `subscribe` (for realtime),
|
|
97
|
-
* `staleTime` (hint for SWR).
|
|
98
|
-
*/
|
|
99
|
-
interface EntityTransport<T extends object> {
|
|
100
|
-
/**
|
|
101
|
-
* Derive the stable string id of a row. Used by the engine to write
|
|
102
|
-
* into the entity graph under the right id key.
|
|
103
|
-
*/
|
|
104
|
-
identify: (row: T) => string;
|
|
105
|
-
/**
|
|
106
|
-
* `true` when the local copy is considered authoritative (e.g. PGlite
|
|
107
|
-
* + Electric Tier-A sync) — consumers can render from cache without
|
|
108
|
-
* a remote round-trip on every mount.
|
|
109
|
-
*
|
|
110
|
-
* `false` when the remote is authoritative (Tier-B REST hybrid) — the
|
|
111
|
-
* cache is a hint, not the truth.
|
|
112
|
-
*/
|
|
113
|
-
authoritative: boolean;
|
|
114
|
-
/**
|
|
115
|
-
* Stale-time hint in ms. The engine SWR logic refetches when
|
|
116
|
-
* `Date.now() - lastFetched > staleTime`. Omit to inherit the engine
|
|
117
|
-
* default (30s).
|
|
118
|
-
*/
|
|
119
|
-
staleTime?: number;
|
|
120
|
-
/** Fetch a list. The signal in `q.signal` MUST be honoured. */
|
|
121
|
-
list: (q: ListQuery) => Promise<ListResult<T>>;
|
|
122
|
-
/** Fetch a single row by id. Optional. */
|
|
123
|
-
get?: (id: string, signal?: AbortSignal) => Promise<T | null>;
|
|
124
|
-
/**
|
|
125
|
-
* Subscribe to realtime change events for this entity type. Optional.
|
|
126
|
-
*
|
|
127
|
-
* Called by `useEntities` / `useEntityQuery` exactly once per
|
|
128
|
-
* subscriber-bearing key. The returned function MUST tear down all
|
|
129
|
-
* underlying resources (sockets, channels, intervals).
|
|
130
|
-
*/
|
|
131
|
-
subscribe?: (onChange: (ev: ChangeEvent<T>) => void) => () => void;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Process-global registry of `EntityTransport` instances by entity type.
|
|
136
|
-
*
|
|
137
|
-
* Why global state: every consumer of `useEntities("Client")` must
|
|
138
|
-
* resolve the SAME transport. Threading a registry through React
|
|
139
|
-
* context would require every test, every isolated story, every
|
|
140
|
-
* non-React caller (engine internals) to plumb the context — a tax
|
|
141
|
-
* that buys nothing. The 1.x library already used module-global state
|
|
142
|
-
* for the `useGraphStore` Zustand store; this follows the same shape.
|
|
143
|
-
*
|
|
144
|
-
* The registry is mutable: re-registering a type silently replaces the
|
|
145
|
-
* prior transport (tests rely on this; production code should only
|
|
146
|
-
* register once at app boot).
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Register the transport for an entity type. Called once per type at
|
|
151
|
-
* app boot, typically from `src/shared/db/entity-transports.ts` in the
|
|
152
|
-
* consuming application.
|
|
153
|
-
*
|
|
154
|
-
* Re-registering REPLACES the prior transport — useful for tests, a
|
|
155
|
-
* footgun for production code. If you find yourself re-registering at
|
|
156
|
-
* runtime, you almost certainly want a different design.
|
|
157
|
-
*/
|
|
158
|
-
declare function registerEntityTransport<T extends object>(type: EntityType, transport: EntityTransport<T>): void;
|
|
159
|
-
/**
|
|
160
|
-
* Look up the transport for an entity type. Throws if none is
|
|
161
|
-
* registered — there is no "default" transport, by design.
|
|
162
|
-
*
|
|
163
|
-
* The cast to `EntityTransport<T>` is the API ergonomic
|
|
164
|
-
* compromise that lets call sites stay generic; the registry stores
|
|
165
|
-
* `EntityTransport<object>` because TypeScript can't otherwise unify
|
|
166
|
-
* heterogeneous rows in one map.
|
|
167
|
-
*/
|
|
168
|
-
declare function getEntityTransport<T extends object>(type: EntityType): EntityTransport<T>;
|
|
169
|
-
/**
|
|
170
|
-
* Test-only: clear ALL registered transports. Production code should
|
|
171
|
-
* never need this; tests use it to reset between specs.
|
|
172
|
-
*/
|
|
173
|
-
declare function __resetEntityTransports(): void;
|
|
174
|
-
/**
|
|
175
|
-
* Introspection: how many transports are currently registered.
|
|
176
|
-
* Useful for asserting in tests that boot wiring ran exactly once.
|
|
177
|
-
*/
|
|
178
|
-
declare function getRegisteredEntityTypes(): EntityType[];
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Active-graph resolution for imperative (non-hook) access.
|
|
182
|
-
*
|
|
183
|
-
* `GraphStoreProvider` scopes the React *hook* surface, but imperative callers —
|
|
184
|
-
* Zustand store actions, module-level helpers, mutation callbacks — have no
|
|
185
|
-
* React context to read. Before this module they had no way to reach a scoped
|
|
186
|
-
* graph at all, so a mounted provider silently failed to isolate them.
|
|
187
|
-
*
|
|
188
|
-
* Two independent mechanisms, both opt-in, both falling back to the package
|
|
189
|
-
* singleton so existing consumers are unaffected:
|
|
190
|
-
*
|
|
191
|
-
* 1. `setActiveGraphStore(store)` — a module-level active store. Correct in the
|
|
192
|
-
* browser, where there is exactly one application tree. `GraphStoreProvider`
|
|
193
|
-
* sets it on mount and restores the previous value on unmount.
|
|
194
|
-
*
|
|
195
|
-
* 2. `runWithGraphStore(store, fn)` — an `AsyncLocalStorage` scope. Required on
|
|
196
|
-
* the server, where concurrent requests interleave and a module-level value
|
|
197
|
-
* would leak across them.
|
|
198
|
-
*
|
|
199
|
-
* ALS takes precedence: if a request scope is active it always wins over the
|
|
200
|
-
* module-level value, because a server render must never observe another
|
|
201
|
-
* request's graph.
|
|
202
|
-
*
|
|
203
|
-
* ## Why `node:async_hooks` is loaded lazily
|
|
204
|
-
*
|
|
205
|
-
* This package is bundled for the browser as well as Node. A static
|
|
206
|
-
* `import "node:async_hooks"` would break browser builds and pull a polyfill
|
|
207
|
-
* into client bundles. The import is therefore attempted once, at first use of
|
|
208
|
-
* `runWithGraphStore`, and failure degrades to the module-level mechanism
|
|
209
|
-
* rather than throwing.
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Initialise request scoping on runtimes without a synchronous `require`.
|
|
214
|
-
*
|
|
215
|
-
* Under **pure ESM** there is no `require`, so the synchronous path above cannot
|
|
216
|
-
* load `node:async_hooks` and `runWithGraphStore` would silently degrade to the
|
|
217
|
-
* module-level store — which does NOT isolate concurrent requests. An ESM server
|
|
218
|
-
* must therefore `await prepareGraphStoreScope()` once during startup, before
|
|
219
|
-
* serving traffic.
|
|
220
|
-
*
|
|
221
|
-
* Safe to call anywhere: it resolves to `false` in the browser and is idempotent.
|
|
222
|
-
*/
|
|
223
|
-
declare function prepareGraphStoreScope(): Promise<boolean>;
|
|
224
|
-
/**
|
|
225
|
-
* Set the process/tab-wide active graph.
|
|
226
|
-
*
|
|
227
|
-
* Returns a restore function; callers MUST invoke it on teardown so a nested or
|
|
228
|
-
* remounted provider does not strand a stale store. Passing `null` clears it.
|
|
229
|
-
*/
|
|
230
|
-
declare function setActiveGraphStore(store: GraphStore$1 | null): () => void;
|
|
231
|
-
/**
|
|
232
|
-
* Run `fn` with `store` as the active graph for this async context.
|
|
233
|
-
*
|
|
234
|
-
* This is the server-side entry point: an SSR host wraps each request so that
|
|
235
|
-
* concurrent renders never share entity state. When the runtime has no
|
|
236
|
-
* `AsyncLocalStorage`, `fn` still runs — under the module-level store — rather
|
|
237
|
-
* than failing, so isomorphic code does not need a branch.
|
|
238
|
-
*/
|
|
239
|
-
declare function runWithGraphStore<R>(store: GraphStore$1, fn: () => R): R;
|
|
240
|
-
/**
|
|
241
|
-
* The graph imperative access should target right now.
|
|
242
|
-
*
|
|
243
|
-
* Precedence: request scope (ALS) → module-level active store → `fallback`.
|
|
244
|
-
* `fallback` is the package singleton, supplied by the caller to avoid a
|
|
245
|
-
* circular import with `graph.ts`.
|
|
246
|
-
*/
|
|
247
|
-
declare function resolveActiveGraphStore(fallback: GraphStore$1): GraphStore$1;
|
|
248
|
-
/** Test seam: drop all active-store state. */
|
|
249
|
-
declare function __resetActiveGraphStore(): void;
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* `makeRestTransport` — built-in helper for the most common case: a
|
|
253
|
-
* Supabase / PostgREST backend reached through a `SupabaseClient`-like
|
|
254
|
-
* object.
|
|
255
|
-
*
|
|
256
|
-
* Why a helper (not a class): consumers stay declarative —
|
|
257
|
-
* registerEntityTransport("Client",
|
|
258
|
-
* makeRestTransport<Client>({ supabase, table: "client" }));
|
|
259
|
-
* — and the library never imports `@supabase/supabase-js` directly
|
|
260
|
-
* (peer-dep-free).
|
|
261
|
-
*
|
|
262
|
-
* The transport:
|
|
263
|
-
* - Compiles `ListQuery` (filter / sort / search / cursor / limit)
|
|
264
|
-
* into a PostgREST query via the supabase-js builder.
|
|
265
|
-
* - Maps HTTP status to `TerminalError` (4xx) or `TransientError`
|
|
266
|
-
* (5xx / network).
|
|
267
|
-
* - Honours `AbortSignal` via supabase-js `.abortSignal(signal)`.
|
|
268
|
-
* - Returns `total` from PostgREST `count: 'exact'` when requested.
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Minimal slice of the `@supabase/supabase-js` `SupabaseClient` we use.
|
|
273
|
-
* Declared structurally so the library does not need to import the
|
|
274
|
-
* package as a dependency (peer-dep-free).
|
|
275
|
-
*/
|
|
276
|
-
interface SupabaseLike {
|
|
277
|
-
from: (table: string) => SupabaseQueryBuilderLike;
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Subset of the supabase-js builder we exercise. Each call returns the
|
|
281
|
-
* same builder for chaining; `then`-able at the end resolves to
|
|
282
|
-
* `{ data, error, count, status }`.
|
|
283
|
-
*/
|
|
284
|
-
interface SupabaseQueryBuilderLike {
|
|
285
|
-
select: (columns: string, opts?: {
|
|
286
|
-
count?: "exact" | "planned" | "estimated";
|
|
287
|
-
head?: boolean;
|
|
288
|
-
}) => SupabaseQueryBuilderLike;
|
|
289
|
-
eq: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
290
|
-
neq: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
291
|
-
gt: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
292
|
-
gte: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
293
|
-
lt: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
294
|
-
lte: (col: string, val: unknown) => SupabaseQueryBuilderLike;
|
|
295
|
-
in: (col: string, vals: readonly unknown[]) => SupabaseQueryBuilderLike;
|
|
296
|
-
ilike: (col: string, pattern: string) => SupabaseQueryBuilderLike;
|
|
297
|
-
is: (col: string, val: null | boolean) => SupabaseQueryBuilderLike;
|
|
298
|
-
or: (filter: string) => SupabaseQueryBuilderLike;
|
|
299
|
-
order: (col: string, opts?: {
|
|
300
|
-
ascending?: boolean;
|
|
301
|
-
nullsFirst?: boolean;
|
|
302
|
-
}) => SupabaseQueryBuilderLike;
|
|
303
|
-
range: (from: number, to: number) => SupabaseQueryBuilderLike;
|
|
304
|
-
limit: (n: number) => SupabaseQueryBuilderLike;
|
|
305
|
-
abortSignal?: (signal: AbortSignal) => SupabaseQueryBuilderLike;
|
|
306
|
-
then: <TResult1 = unknown, TResult2 = never>(onfulfilled?: ((value: {
|
|
307
|
-
data: unknown;
|
|
308
|
-
error: unknown;
|
|
309
|
-
count?: number | null;
|
|
310
|
-
status?: number;
|
|
311
|
-
}) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null) => Promise<TResult1 | TResult2>;
|
|
312
|
-
}
|
|
313
|
-
/** Options for `makeRestTransport`. */
|
|
314
|
-
interface MakeRestTransportOptions<T extends object> {
|
|
315
|
-
/** A `@supabase/supabase-js` client (or any structurally-compatible thing). */
|
|
316
|
-
supabase: SupabaseLike;
|
|
317
|
-
/** PostgREST table name. */
|
|
318
|
-
table: string;
|
|
319
|
-
/** Columns to select (default `"*"`). */
|
|
320
|
-
select?: string;
|
|
321
|
-
/** Stable id derivation. Defaults to `(row) => String(row.id)`. */
|
|
322
|
-
identify?: (row: T) => string;
|
|
323
|
-
/** Whether the local cache is treated as authoritative. */
|
|
324
|
-
authoritative?: boolean;
|
|
325
|
-
/** Stale-time hint in ms. */
|
|
326
|
-
staleTime?: number;
|
|
327
|
-
/** Free-text search column list (compiled to `or=col.ilike.*query*,…`). */
|
|
328
|
-
searchColumns?: string[];
|
|
329
|
-
/** Default page size when `ListQuery.limit` is absent. */
|
|
330
|
-
defaultLimit?: number;
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Build an `EntityTransport<T>` from a Supabase client + a table name.
|
|
334
|
-
*
|
|
335
|
-
* The returned transport:
|
|
336
|
-
* - Maps `ListQuery.filter` clauses to PostgREST operators (`eq`, `gt`,
|
|
337
|
-
* `in`, `ilike`, `is null`, etc.).
|
|
338
|
-
* - Compiles `ListQuery.search` into an `or=` clause across
|
|
339
|
-
* `searchColumns`.
|
|
340
|
-
* - Uses `count: 'exact'` on first page to surface `total`.
|
|
341
|
-
* - Throws `TerminalError` on 4xx (no retry); `TransientError` on 5xx
|
|
342
|
-
* or network failure.
|
|
343
|
-
* - Honours `signal` via `.abortSignal(signal)` (supabase-js >= 2.39).
|
|
344
|
-
*/
|
|
345
|
-
declare function makeRestTransport<T extends object>(opts: MakeRestTransportOptions<T>): EntityTransport<T>;
|
|
346
|
-
|
|
347
|
-
declare function getValueAtPath<T = unknown>(source: unknown, path: string): T | undefined;
|
|
348
|
-
declare function setValueAtPath<T extends object>(source: T, path: string, value: unknown): T;
|
|
349
|
-
declare function collectDirtyPaths(current: unknown, original: unknown, prefix?: string, acc?: Set<string>): Set<string>;
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* merge/types.ts — Pluggable conflict-resolution seam for the entity graph.
|
|
353
|
-
*
|
|
354
|
-
* Why a port (not a hard-wired engine):
|
|
355
|
-
* - The graph receives concurrent writes from multiple sources — realtime
|
|
356
|
-
* adapters (Flint, Supabase, Surreal), AG-UI agents, and optimistic local
|
|
357
|
-
* mutations. The default resolution is last-write-wins (LWW), matching the
|
|
358
|
-
* historical shallow-merge in `upsertEntity`.
|
|
359
|
-
* - Collaborative / agentic multi-writer scenarios need stronger guarantees
|
|
360
|
-
* (CRDT). But the *engine* (Loro vs Automerge vs Yjs) is a downstream
|
|
361
|
-
* decision — and the Flint fabric's own CRDT choice is still open. Encoding
|
|
362
|
-
* the decision as a swappable `MergeStrategy` keeps that open decision from
|
|
363
|
-
* blocking this layer.
|
|
364
|
-
*
|
|
365
|
-
* One strategy is registered per entity type (or a global default). The graph
|
|
366
|
-
* consults it at write time; absent a registration it falls back to LWW, so
|
|
367
|
-
* existing behavior is byte-for-byte preserved.
|
|
368
|
-
*/
|
|
369
|
-
|
|
370
|
-
/** Context handed to a {@link MergeStrategy} for one write. */
|
|
371
|
-
interface MergeContext {
|
|
372
|
-
/** Entity kind being written. */
|
|
373
|
-
type: EntityType;
|
|
374
|
-
/** Entity id being written. */
|
|
375
|
-
id: EntityId;
|
|
376
|
-
/** Provenance of the incoming write (server / client / optimistic). */
|
|
377
|
-
origin: SyncOrigin;
|
|
378
|
-
/** Wall-clock ms of the incoming write, when the caller knows it. */
|
|
379
|
-
updatedAt: number | null;
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Resolves the next canonical entity value from the previous value and an
|
|
383
|
-
* incoming partial/full write.
|
|
384
|
-
*
|
|
385
|
-
* Contract:
|
|
386
|
-
* - MUST be pure (no side effects, no graph access) — the graph applies the
|
|
387
|
-
* returned value inside its Immer producer.
|
|
388
|
-
* - MUST return a NEW object; never mutate `prev` or `next` (immutability rule).
|
|
389
|
-
* - `prev` is `undefined` on first write for an id.
|
|
390
|
-
*
|
|
391
|
-
* @param prev - Current canonical value, or undefined if none exists yet.
|
|
392
|
-
* @param next - Incoming write (partial for upsert, full for replace).
|
|
393
|
-
* @param ctx - Type/id/origin/timestamp metadata for this write.
|
|
394
|
-
* @returns The merged canonical value to store.
|
|
395
|
-
*/
|
|
396
|
-
type MergeStrategy = (prev: Record<string, unknown> | undefined, next: Record<string, unknown>, ctx: MergeContext) => Record<string, unknown>;
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* merge/lww.ts — Last-write-wins default strategy.
|
|
400
|
-
*
|
|
401
|
-
* Semantics match the historical `upsertEntity` behavior exactly: shallow-merge
|
|
402
|
-
* the incoming write over the previous value. This is the fallback when no
|
|
403
|
-
* other strategy is registered, so registering nothing is a no-op change.
|
|
404
|
-
*/
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Shallow-merge `next` over `prev` (incoming keys win). Returns a new object.
|
|
408
|
-
* On first write (`prev` undefined) returns a shallow copy of `next`.
|
|
409
|
-
*/
|
|
410
|
-
declare const lwwStrategy: MergeStrategy;
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* merge/registry.ts — One MergeStrategy per entity type (+ optional global default).
|
|
414
|
-
*
|
|
415
|
-
* Lookup order at write time:
|
|
416
|
-
* 1. strategy registered for the exact `type`
|
|
417
|
-
* 2. global default strategy (if one was set)
|
|
418
|
-
* 3. built-in LWW (`lwwStrategy`)
|
|
419
|
-
*
|
|
420
|
-
* Step 3 guarantees that with zero registrations the graph behaves exactly as
|
|
421
|
-
* it did before this seam existed.
|
|
422
|
-
*/
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Register a {@link MergeStrategy} for one entity type. Overwrites any prior
|
|
426
|
-
* registration for that type.
|
|
427
|
-
*/
|
|
428
|
-
declare function registerMergeStrategy(type: string, strategy: MergeStrategy): void;
|
|
429
|
-
/**
|
|
430
|
-
* Set the fallback strategy used for any type without its own registration.
|
|
431
|
-
* Pass `null` to clear it (reverting the fallback to built-in LWW).
|
|
432
|
-
*/
|
|
433
|
-
declare function setDefaultMergeStrategy(strategy: MergeStrategy | null): void;
|
|
434
|
-
/**
|
|
435
|
-
* Resolve the effective strategy for a type: per-type → global default → LWW.
|
|
436
|
-
* Always returns a usable strategy (never null).
|
|
437
|
-
*/
|
|
438
|
-
declare function getMergeStrategy(type: string): MergeStrategy;
|
|
439
|
-
/** True if `type` (or a global default) has a non-LWW strategy registered. */
|
|
440
|
-
declare function hasMergeStrategy(type: string): boolean;
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* merge/loro.ts — Loro-backed CRDT MergeStrategy (reference implementation).
|
|
444
|
-
*
|
|
445
|
-
* Maps each entity (`type:id`) onto a Loro document whose root is an LWW-Map —
|
|
446
|
-
* a near-1:1 fit for the graph's `type:id:field` model. Concurrent field writes
|
|
447
|
-
* resolve via Loro's CRDT semantics rather than blind last-write-wins, so two
|
|
448
|
-
* writers updating *different* fields never clobber each other, and writers
|
|
449
|
-
* updating the *same* field resolve deterministically across replicas.
|
|
450
|
-
*
|
|
451
|
-
* `loro-crdt` is an OPTIONAL peer dependency. It is imported lazily so the core
|
|
452
|
-
* bundle stays `zustand + immer` only — nothing loads Loro unless an app
|
|
453
|
-
* actually registers `createLoroMergeStrategy()`.
|
|
454
|
-
*
|
|
455
|
-
* NOTE: `createLoroMergeStrategy` is async because it dynamically imports the
|
|
456
|
-
* engine. Await it once at boot, then register the resolved synchronous
|
|
457
|
-
* strategy. The returned strategy itself is pure+sync (the MergeStrategy
|
|
458
|
-
* contract), keeping per-write resolution off the async path.
|
|
459
|
-
*/
|
|
460
|
-
|
|
461
|
-
type LoroModuleLoader = () => Promise<{
|
|
462
|
-
LoroDoc: unknown;
|
|
463
|
-
}>;
|
|
464
|
-
/**
|
|
465
|
-
* Build a Loro-backed {@link MergeStrategy}. Resolves `loro-crdt` lazily; throws
|
|
466
|
-
* a clear error if the optional peer is not installed.
|
|
467
|
-
*
|
|
468
|
-
* @example
|
|
469
|
-
* ```ts
|
|
470
|
-
* const loro = await createLoroMergeStrategy();
|
|
471
|
-
* registerMergeStrategy("Document", loro);
|
|
472
|
-
* ```
|
|
473
|
-
*/
|
|
474
|
-
declare function createLoroMergeStrategy(loadLoro?: LoroModuleLoader): Promise<MergeStrategy>;
|
|
475
|
-
|
|
476
|
-
type GraphStore = ReturnType<typeof useGraphStore.getState>;
|
|
477
|
-
type GraphIncludeMap = Record<string, GraphIncludeRelation>;
|
|
478
|
-
type GraphIncludeRelation = {
|
|
479
|
-
type: EntityType;
|
|
480
|
-
via: {
|
|
481
|
-
kind: "field";
|
|
482
|
-
field: string;
|
|
483
|
-
};
|
|
484
|
-
include?: GraphIncludeMap;
|
|
485
|
-
} | {
|
|
486
|
-
type: EntityType;
|
|
487
|
-
via: {
|
|
488
|
-
kind: "array";
|
|
489
|
-
field: string;
|
|
490
|
-
};
|
|
491
|
-
include?: GraphIncludeMap;
|
|
492
|
-
} | {
|
|
493
|
-
type: EntityType;
|
|
494
|
-
via: {
|
|
495
|
-
kind: "list";
|
|
496
|
-
key: QueryKey | ((entity: Record<string, unknown>) => QueryKey | null | undefined);
|
|
497
|
-
};
|
|
498
|
-
include?: GraphIncludeMap;
|
|
499
|
-
} | {
|
|
500
|
-
type: EntityType;
|
|
501
|
-
via: {
|
|
502
|
-
kind: "resolver";
|
|
503
|
-
resolve: (entity: Record<string, unknown>, store: GraphStore) => EntityId | EntityId[] | null | undefined;
|
|
504
|
-
};
|
|
505
|
-
include?: GraphIncludeMap;
|
|
506
|
-
};
|
|
507
|
-
interface GraphQueryOptions<TEntity extends object> {
|
|
508
|
-
type: EntityType;
|
|
509
|
-
id?: EntityId;
|
|
510
|
-
ids?: EntityId[];
|
|
511
|
-
listKey?: QueryKey;
|
|
512
|
-
where?: (entity: EntitySnapshot<TEntity>) => boolean;
|
|
513
|
-
sort?: (a: EntitySnapshot<TEntity>, b: EntitySnapshot<TEntity>) => number;
|
|
514
|
-
include?: GraphIncludeMap;
|
|
515
|
-
select?: ((entity: Record<string, unknown>) => unknown) | string[];
|
|
516
|
-
}
|
|
517
|
-
type ProjectedRow = Record<string, unknown>;
|
|
518
|
-
declare function queryOnce<TEntity extends object>(opts: GraphQueryOptions<TEntity> & {
|
|
519
|
-
id: EntityId;
|
|
520
|
-
}): ProjectedRow | null;
|
|
521
|
-
declare function queryOnce<TEntity extends object>(opts: GraphQueryOptions<TEntity>): ProjectedRow[];
|
|
522
|
-
declare const selectGraph: typeof queryOnce;
|
|
523
|
-
|
|
524
|
-
interface GraphDataSnapshot {
|
|
525
|
-
entities: ReturnType<typeof graphStore.getState>["entities"];
|
|
526
|
-
patches: ReturnType<typeof graphStore.getState>["patches"];
|
|
527
|
-
entityStates: ReturnType<typeof graphStore.getState>["entityStates"];
|
|
528
|
-
syncMetadata: ReturnType<typeof graphStore.getState>["syncMetadata"];
|
|
529
|
-
lists: ReturnType<typeof graphStore.getState>["lists"];
|
|
530
|
-
}
|
|
531
|
-
interface GraphTransaction {
|
|
532
|
-
upsertEntity: (type: EntityType, id: EntityId, data: Record<string, unknown>) => GraphTransaction;
|
|
533
|
-
replaceEntity: (type: EntityType, id: EntityId, data: Record<string, unknown>) => GraphTransaction;
|
|
534
|
-
removeEntity: (type: EntityType, id: EntityId) => GraphTransaction;
|
|
535
|
-
patchEntity: (type: EntityType, id: EntityId, patch: Record<string, unknown>) => GraphTransaction;
|
|
536
|
-
clearPatch: (type: EntityType, id: EntityId) => GraphTransaction;
|
|
537
|
-
insertIdInList: (key: QueryKey, id: EntityId, position: "start" | "end" | number) => GraphTransaction;
|
|
538
|
-
removeIdFromAllLists: (type: EntityType, id: EntityId) => GraphTransaction;
|
|
539
|
-
setEntitySyncMetadata: (type: EntityType, id: EntityId, metadata: Partial<EntitySyncMetadata>) => GraphTransaction;
|
|
540
|
-
markEntityPending: (type: EntityType, id: EntityId, origin?: SyncOrigin) => GraphTransaction;
|
|
541
|
-
markEntitySynced: (type: EntityType, id: EntityId, origin?: SyncOrigin) => GraphTransaction;
|
|
542
|
-
commit: () => void;
|
|
543
|
-
rollback: () => void;
|
|
544
|
-
snapshot: () => GraphDataSnapshot;
|
|
545
|
-
}
|
|
546
|
-
interface GraphActionOptions<TInput, TResult> {
|
|
547
|
-
key?: string;
|
|
548
|
-
optimistic?: (tx: GraphTransaction, input: TInput) => void;
|
|
549
|
-
run: (tx: GraphTransaction, input: TInput) => Promise<TResult> | TResult;
|
|
550
|
-
onSuccess?: (result: TResult, input: TInput, tx: GraphTransaction) => void;
|
|
551
|
-
onError?: (error: Error, input: TInput) => void;
|
|
552
|
-
}
|
|
553
|
-
interface GraphActionRecord$1 {
|
|
554
|
-
id: string;
|
|
555
|
-
key: string;
|
|
556
|
-
input: unknown;
|
|
557
|
-
enqueuedAt: string;
|
|
558
|
-
}
|
|
559
|
-
type GraphActionEvent = {
|
|
560
|
-
type: "enqueued";
|
|
561
|
-
record: GraphActionRecord$1;
|
|
562
|
-
} | {
|
|
563
|
-
type: "settled";
|
|
564
|
-
record: GraphActionRecord$1;
|
|
565
|
-
};
|
|
566
|
-
declare function createGraphTransaction(storeApi?: GraphStore$1): GraphTransaction;
|
|
567
|
-
declare function createGraphAction<TInput, TResult>(opts: GraphActionOptions<TInput, TResult>): (input: TInput) => Promise<TResult>;
|
|
568
|
-
|
|
569
|
-
interface GraphEffectEvent<T> {
|
|
570
|
-
key: string;
|
|
571
|
-
value: T;
|
|
572
|
-
previousValue: T;
|
|
573
|
-
}
|
|
574
|
-
interface GraphEffectOptions<T> {
|
|
575
|
-
query: () => T[] | T | null;
|
|
576
|
-
getKey?: (value: T, index: number) => string;
|
|
577
|
-
skipInitial?: boolean;
|
|
578
|
-
isEqual?: (previousValue: T, nextValue: T) => boolean;
|
|
579
|
-
onEnter?: (event: {
|
|
580
|
-
key: string;
|
|
581
|
-
value: T;
|
|
582
|
-
}) => void;
|
|
583
|
-
onUpdate?: (event: GraphEffectEvent<T>) => void;
|
|
584
|
-
onExit?: (event: {
|
|
585
|
-
key: string;
|
|
586
|
-
previousValue: T;
|
|
587
|
-
}) => void;
|
|
588
|
-
}
|
|
589
|
-
interface GraphEffectHandle {
|
|
590
|
-
dispose: () => void;
|
|
591
|
-
}
|
|
592
|
-
declare function createGraphEffect<T>(opts: GraphEffectOptions<T>): GraphEffectHandle;
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* schema.ts (core) — framework-agnostic JSON-schema registry + snapshot/markdown
|
|
596
|
-
* helpers. The React field renderers/editors (MarkdownFieldRenderer,
|
|
597
|
-
* MarkdownFieldEditor, useSchemaEntityFields, buildEntityFieldsFromSchema which
|
|
598
|
-
* depends on the UI FieldDescriptor type) live in the react binding's schema.tsx,
|
|
599
|
-
* built on these primitives.
|
|
600
|
-
*/
|
|
601
|
-
interface JsonSchemaObject {
|
|
602
|
-
$id?: string;
|
|
603
|
-
title?: string;
|
|
604
|
-
description?: string;
|
|
605
|
-
type?: string | string[];
|
|
606
|
-
format?: string;
|
|
607
|
-
enum?: readonly unknown[];
|
|
608
|
-
default?: unknown;
|
|
609
|
-
properties?: Record<string, JsonSchemaObject>;
|
|
610
|
-
items?: JsonSchemaObject;
|
|
611
|
-
required?: string[];
|
|
612
|
-
additionalProperties?: boolean | JsonSchemaObject;
|
|
613
|
-
["x-a2ui-component"]?: string;
|
|
614
|
-
["x-display-order"]?: number;
|
|
615
|
-
["x-field-type"]?: string;
|
|
616
|
-
["x-hidden"]?: boolean;
|
|
617
|
-
}
|
|
618
|
-
interface EntityJsonSchemaConfig {
|
|
619
|
-
entityType: string;
|
|
620
|
-
schemaId?: string;
|
|
621
|
-
field?: string;
|
|
622
|
-
version?: string;
|
|
623
|
-
source?: "static" | "runtime" | "ai";
|
|
624
|
-
schema: JsonSchemaObject;
|
|
625
|
-
}
|
|
626
|
-
interface GetEntityJsonSchemaOptions {
|
|
627
|
-
entityType: string;
|
|
628
|
-
schemaId?: string;
|
|
629
|
-
field?: string;
|
|
630
|
-
}
|
|
631
|
-
interface GraphSnapshotWithSchemasOptions {
|
|
632
|
-
scope: string;
|
|
633
|
-
data: unknown;
|
|
634
|
-
schemas: Array<EntityJsonSchemaConfig | null | undefined>;
|
|
635
|
-
pretty?: boolean;
|
|
636
|
-
}
|
|
637
|
-
declare function registerEntityJsonSchema(config: EntityJsonSchemaConfig): void;
|
|
638
|
-
declare function registerRuntimeSchema(config: EntityJsonSchemaConfig): void;
|
|
639
|
-
declare function getEntityJsonSchema(opts: GetEntityJsonSchemaOptions): EntityJsonSchemaConfig | null;
|
|
640
|
-
declare function exportGraphSnapshotWithSchemas(opts: GraphSnapshotWithSchemasOptions): string;
|
|
641
|
-
declare function escapeHtml(input: string): string;
|
|
642
|
-
declare function renderMarkdownToHtml(value: string): string;
|
|
643
|
-
/** Infer a coarse field-type string from a JSON-schema node (UI-agnostic). */
|
|
644
|
-
declare function inferSchemaFieldType(schema: JsonSchemaObject): string;
|
|
645
|
-
declare function registryKey(entityType: string, field?: string, schemaId?: string): string;
|
|
646
|
-
declare function humanizeFieldName(value: string): string;
|
|
647
|
-
|
|
648
|
-
interface GraphSnapshotExportOptions {
|
|
649
|
-
scope: string;
|
|
650
|
-
data: unknown;
|
|
651
|
-
pretty?: boolean;
|
|
652
|
-
}
|
|
653
|
-
interface GraphToolContext {
|
|
654
|
-
store: ReturnType<typeof useGraphStore.getState>;
|
|
655
|
-
queryOnce: typeof queryOnce;
|
|
656
|
-
exportGraphSnapshot: typeof exportGraphSnapshot;
|
|
657
|
-
}
|
|
658
|
-
interface SchemaGraphToolContext extends GraphToolContext {
|
|
659
|
-
getEntityJsonSchema: typeof getEntityJsonSchema;
|
|
660
|
-
exportGraphSnapshotWithSchemas: typeof exportGraphSnapshotWithSchemas;
|
|
661
|
-
}
|
|
662
|
-
declare function exportGraphSnapshot(opts: GraphSnapshotExportOptions): string;
|
|
663
|
-
declare function createGraphTool<TInput, TResult>(handler: (input: TInput, ctx: GraphToolContext) => Promise<TResult> | TResult): (input: TInput) => TResult | Promise<TResult>;
|
|
664
|
-
declare function createSchemaGraphTool<TInput, TResult>(handler: (input: TInput, ctx: SchemaGraphToolContext) => Promise<TResult> | TResult): (input: TInput) => TResult | Promise<TResult>;
|
|
665
|
-
|
|
666
|
-
interface GraphPersistenceAdapter {
|
|
667
|
-
get: (key: string) => Promise<string | null> | string | null;
|
|
668
|
-
set: (key: string, value: string) => Promise<void> | void;
|
|
669
|
-
remove?: (key: string) => Promise<void> | void;
|
|
670
|
-
}
|
|
671
|
-
interface GraphActionRecord {
|
|
672
|
-
id: string;
|
|
673
|
-
key: string;
|
|
674
|
-
input: unknown;
|
|
675
|
-
enqueuedAt: string;
|
|
676
|
-
}
|
|
677
|
-
interface GraphSyncStatus {
|
|
678
|
-
phase: "idle" | "hydrating" | "syncing" | "ready" | "offline" | "error";
|
|
679
|
-
isOnline: boolean;
|
|
680
|
-
isSynced: boolean;
|
|
681
|
-
pendingActions: number;
|
|
682
|
-
lastHydratedAt: string | null;
|
|
683
|
-
lastPersistedAt: string | null;
|
|
684
|
-
storageKey: string | null;
|
|
685
|
-
error: string | null;
|
|
686
|
-
}
|
|
687
|
-
interface GraphSnapshotPayload {
|
|
688
|
-
version: 1;
|
|
689
|
-
snapshot: {
|
|
690
|
-
entities: ReturnType<typeof graphStore.getState>["entities"];
|
|
691
|
-
patches: ReturnType<typeof graphStore.getState>["patches"];
|
|
692
|
-
entityStates: ReturnType<typeof graphStore.getState>["entityStates"];
|
|
693
|
-
syncMetadata: ReturnType<typeof graphStore.getState>["syncMetadata"];
|
|
694
|
-
lists: ReturnType<typeof graphStore.getState>["lists"];
|
|
695
|
-
};
|
|
696
|
-
pendingActions: GraphActionRecord[];
|
|
697
|
-
}
|
|
698
|
-
interface PersistGraphToStorageOptions {
|
|
699
|
-
storage: GraphPersistenceAdapter;
|
|
700
|
-
key: string;
|
|
701
|
-
store?: GraphStore$1;
|
|
702
|
-
pendingActions?: GraphActionRecord[];
|
|
703
|
-
}
|
|
704
|
-
interface HydrateGraphFromStorageOptions {
|
|
705
|
-
storage: GraphPersistenceAdapter;
|
|
706
|
-
key: string;
|
|
707
|
-
store?: GraphStore$1;
|
|
708
|
-
}
|
|
709
|
-
/**
|
|
710
|
-
* Retry-with-backoff policy for replaying pending offline actions.
|
|
711
|
-
*
|
|
712
|
-
* The replay loop tracks per-action attempt counts. After `maxAttempts`
|
|
713
|
-
* failed attempts the action is considered "poisoned" — it is removed from
|
|
714
|
-
* the in-memory pending queue (so it won't block other actions) and the
|
|
715
|
-
* optional `poisonHandler` is invoked. Consumers typically log the action,
|
|
716
|
-
* surface a UI prompt, or persist it to a dead-letter store.
|
|
717
|
-
*
|
|
718
|
-
* Defaults: 5 attempts, starting at 500ms, doubling up to 30s, with
|
|
719
|
-
* "equal" jitter (random in `[delay/2, delay]`).
|
|
720
|
-
*/
|
|
721
|
-
interface ReplayRetryPolicy {
|
|
722
|
-
maxAttempts?: number;
|
|
723
|
-
initialDelayMs?: number;
|
|
724
|
-
maxDelayMs?: number;
|
|
725
|
-
backoffFactor?: number;
|
|
726
|
-
jitter?: "full" | "equal" | "none";
|
|
727
|
-
poisonHandler?: (action: GraphActionRecord, error: unknown) => void | Promise<void>;
|
|
728
|
-
}
|
|
729
|
-
interface StartLocalFirstGraphOptions {
|
|
730
|
-
storage: GraphPersistenceAdapter;
|
|
731
|
-
store?: GraphStore$1;
|
|
732
|
-
key?: string;
|
|
733
|
-
replayPendingActions?: boolean;
|
|
734
|
-
onlineSource?: {
|
|
735
|
-
getIsOnline: () => boolean;
|
|
736
|
-
subscribe: (listener: (online: boolean) => void) => () => void;
|
|
737
|
-
};
|
|
738
|
-
persistDebounceMs?: number;
|
|
739
|
-
/** Retry-with-backoff policy for offline action replay. */
|
|
740
|
-
retryPolicy?: ReplayRetryPolicy;
|
|
741
|
-
}
|
|
742
|
-
interface LocalFirstGraphRuntime {
|
|
743
|
-
ready: Promise<void>;
|
|
744
|
-
dispose: () => void;
|
|
745
|
-
persistNow: () => Promise<void>;
|
|
746
|
-
hydrate: () => Promise<Awaited<ReturnType<typeof hydrateGraphFromStorage>>>;
|
|
747
|
-
getStatus: () => GraphSyncStatus;
|
|
748
|
-
}
|
|
749
|
-
declare const graphSyncStatusStore: zustand_vanilla.StoreApi<{
|
|
750
|
-
status: GraphSyncStatus;
|
|
751
|
-
setStatus: (status: Partial<GraphSyncStatus>) => void;
|
|
752
|
-
}>;
|
|
753
|
-
declare function getGraphSyncStatus(): GraphSyncStatus;
|
|
754
|
-
declare function persistGraphToStorage(opts: PersistGraphToStorageOptions): Promise<{
|
|
755
|
-
ok: true;
|
|
756
|
-
key: string;
|
|
757
|
-
bytes: number;
|
|
758
|
-
persistedAt: string;
|
|
759
|
-
}>;
|
|
760
|
-
declare function hydrateGraphFromStorage(opts: HydrateGraphFromStorageOptions): Promise<{
|
|
761
|
-
ok: false;
|
|
762
|
-
key: string;
|
|
763
|
-
hydratedAt: null;
|
|
764
|
-
entityCounts: {};
|
|
765
|
-
error: string;
|
|
766
|
-
pendingActions?: undefined;
|
|
767
|
-
} | {
|
|
768
|
-
ok: true;
|
|
769
|
-
key: string;
|
|
770
|
-
hydratedAt: string;
|
|
771
|
-
entityCounts: {
|
|
772
|
-
[k: string]: number;
|
|
773
|
-
};
|
|
774
|
-
pendingActions: GraphActionRecord[];
|
|
775
|
-
error?: undefined;
|
|
776
|
-
}>;
|
|
777
|
-
declare function startLocalFirstGraph(opts: StartLocalFirstGraphOptions): LocalFirstGraphRuntime;
|
|
778
|
-
interface ResolvedRetryPolicy {
|
|
779
|
-
maxAttempts: number;
|
|
780
|
-
initialDelayMs: number;
|
|
781
|
-
maxDelayMs: number;
|
|
782
|
-
backoffFactor: number;
|
|
783
|
-
jitter: "full" | "equal" | "none";
|
|
784
|
-
poisonHandler?: (action: GraphActionRecord, error: unknown) => void | Promise<void>;
|
|
785
|
-
}
|
|
786
|
-
/**
|
|
787
|
-
* Attempt to replay an action up to `maxAttempts` times. On exhaustion the
|
|
788
|
-
* action goes to "poison" — the optional handler is invoked and the function
|
|
789
|
-
* resolves. Exposed for unit testing.
|
|
790
|
-
*/
|
|
791
|
-
declare function replayActionWithRetry(action: GraphActionRecord, policy: ResolvedRetryPolicy, storeApi?: GraphStore$1): Promise<{
|
|
792
|
-
ok: true;
|
|
793
|
-
} | {
|
|
794
|
-
ok: false;
|
|
795
|
-
poisoned: true;
|
|
796
|
-
error: unknown;
|
|
797
|
-
}>;
|
|
798
|
-
|
|
799
|
-
/** Deprecated in-process event shape retained by the package root. */
|
|
800
|
-
type LegacyDevtoolsEvent = {
|
|
801
|
-
kind: "upsert";
|
|
802
|
-
type: string;
|
|
803
|
-
id: string;
|
|
804
|
-
data: Record<string, unknown>;
|
|
805
|
-
at: string;
|
|
806
|
-
} | {
|
|
807
|
-
kind: "patch";
|
|
808
|
-
type: string;
|
|
809
|
-
id: string;
|
|
810
|
-
patch: Record<string, unknown>;
|
|
811
|
-
at: string;
|
|
812
|
-
} | {
|
|
813
|
-
kind: "unpatch";
|
|
814
|
-
type: string;
|
|
815
|
-
id: string;
|
|
816
|
-
keys: string[];
|
|
817
|
-
at: string;
|
|
818
|
-
} | {
|
|
819
|
-
kind: "clearPatch";
|
|
820
|
-
type: string;
|
|
821
|
-
id: string;
|
|
822
|
-
at: string;
|
|
823
|
-
} | {
|
|
824
|
-
kind: "list";
|
|
825
|
-
key: string;
|
|
826
|
-
idCount: number;
|
|
827
|
-
at: string;
|
|
828
|
-
};
|
|
829
|
-
|
|
830
|
-
/**
|
|
831
|
-
* Process-wide defaults for stale times, retries, and background revalidation.
|
|
832
|
-
* Keeps hook signatures small: `useEntity` / `useEntityList` merge these with per-query overrides.
|
|
833
|
-
*/
|
|
834
|
-
interface EngineOptions {
|
|
835
|
-
defaultStaleTime?: number;
|
|
836
|
-
/** Max age (`Date.now() - lastFetched`) for evicting entities with zero subscribers during GC. */
|
|
837
|
-
defaultGcTime?: number;
|
|
838
|
-
/** Interval between GC passes when the collector is active (default 60s). */
|
|
839
|
-
gcInterval?: number;
|
|
840
|
-
maxRetries?: number;
|
|
841
|
-
retryBaseDelay?: number;
|
|
842
|
-
revalidateOnFocus?: boolean;
|
|
843
|
-
revalidateOnReconnect?: boolean;
|
|
844
|
-
}
|
|
845
|
-
/**
|
|
846
|
-
* Declarative **instruction** for loading one entity: wire transport (`fetch`), normalization, and graph writes.
|
|
847
|
-
* Hooks pass this to `fetchEntity`; the graph remains source of truth after success.
|
|
848
|
-
*/
|
|
849
|
-
interface EntityQueryOptions<TRaw, TEntity extends object> {
|
|
850
|
-
type: EntityType;
|
|
851
|
-
id: EntityId | null | undefined;
|
|
852
|
-
fetch: (id: EntityId) => Promise<TRaw>;
|
|
853
|
-
normalize: (raw: TRaw) => TEntity;
|
|
854
|
-
idField?: string;
|
|
855
|
-
sideEffects?: (raw: TRaw, store: GraphStore$1) => void;
|
|
856
|
-
staleTime?: number;
|
|
857
|
-
enabled?: boolean;
|
|
858
|
-
onSuccess?: (entity: TEntity) => void;
|
|
859
|
-
onError?: (error: Error) => void;
|
|
860
|
-
}
|
|
861
|
-
/** Cursor/page knobs passed through to list `fetch` implementations (REST, GraphQL, etc.). */
|
|
862
|
-
interface ListFetchParams {
|
|
863
|
-
cursor?: string;
|
|
864
|
-
page?: number;
|
|
865
|
-
pageSize?: number;
|
|
866
|
-
params?: Record<string, unknown>;
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* Normalized list page shape from any backend. Items are mapped through `normalize` into `{ id, data }` upserts — the list stores ids only.
|
|
870
|
-
*/
|
|
871
|
-
interface ListResponse<T> {
|
|
872
|
-
items: T[];
|
|
873
|
-
total?: number | null;
|
|
874
|
-
nextCursor?: string | null;
|
|
875
|
-
prevCursor?: string;
|
|
876
|
-
hasNextPage?: boolean;
|
|
877
|
-
hasPrevPage?: boolean;
|
|
878
|
-
page?: number;
|
|
879
|
-
pageSize?: number;
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Declarative **instruction** for a collection query: stable `queryKey`, fetcher, and per-row normalization into the graph.
|
|
883
|
-
* `mode` controls whether a fetch replaces ids or appends (infinite scroll) when used with load-more.
|
|
884
|
-
*/
|
|
885
|
-
interface ListQueryOptions<TRaw, TEntity extends object> {
|
|
886
|
-
type: EntityType;
|
|
887
|
-
queryKey: unknown[];
|
|
888
|
-
/**
|
|
889
|
-
* Inline fetcher (deprecated 1.x REST form). Optional in 2.0: pure graph
|
|
890
|
-
* subscriptions for Tier-A PGlite/Electric entities pass no fetcher — the
|
|
891
|
-
* graph is hydrated out-of-band and the hook only joins ids → entities.
|
|
892
|
-
* When omitted, `fetchList` is a no-op and the hook is read-only.
|
|
893
|
-
*/
|
|
894
|
-
fetch?: (params: ListFetchParams) => Promise<ListResponse<TRaw>>;
|
|
895
|
-
/** Row normalizer. Optional alongside `fetch` (graph-only callers omit both). */
|
|
896
|
-
normalize?: (raw: TRaw) => {
|
|
897
|
-
id: EntityId;
|
|
898
|
-
data: TEntity;
|
|
899
|
-
};
|
|
900
|
-
sideEffects?: (items: TRaw[], store: GraphStore$1) => void;
|
|
901
|
-
mode?: "replace" | "append";
|
|
902
|
-
staleTime?: number;
|
|
903
|
-
enabled?: boolean;
|
|
904
|
-
onSuccess?: (result: ListResponse<TRaw>) => void;
|
|
905
|
-
onError?: (error: Error) => void;
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Deterministic string key for list queries so object order in nested keys does not create duplicate cache entries.
|
|
909
|
-
* @param key - Hook-provided query key array (serializable values)
|
|
910
|
-
*/
|
|
911
|
-
declare function serializeKey(key: unknown[]): string;
|
|
912
|
-
/**
|
|
913
|
-
* Collapse concurrent identical requests into one Promise (prevents stampedes when many components mount the same entity/list).
|
|
914
|
-
* @param key - Logical dedupe key (e.g. `type:id` or serialized list key)
|
|
915
|
-
* @param fn - Async work that performs the fetch + graph writes
|
|
916
|
-
*/
|
|
917
|
-
declare function dedupe<T>(key: string, fn: () => Promise<T>, store?: GraphStore$1): Promise<T>;
|
|
918
|
-
/**
|
|
919
|
-
* Ref-count graph interest for a subscriber key (`${type}:${id}`). Background revalidation skips keys with zero subscribers.
|
|
920
|
-
* @returns Opaque token required for `unregisterSubscriber`
|
|
921
|
-
*/
|
|
922
|
-
declare function registerSubscriber(key: string, store?: GraphStore$1): symbol;
|
|
923
|
-
/** Pair with `registerSubscriber` on unmount so idle entities stop refetching. */
|
|
924
|
-
declare function unregisterSubscriber(key: string, token: symbol, store?: GraphStore$1): void;
|
|
925
|
-
/**
|
|
926
|
-
* Subscribe to ref-count changes for `registerSubscriber` / `unregisterSubscriber`.
|
|
927
|
-
* Used by `useGraphDevTools` so subscriber totals update without graph mutations.
|
|
928
|
-
*/
|
|
929
|
-
declare function subscribeSubscriberStats(onChange: () => void, store?: GraphStore$1): () => boolean;
|
|
930
|
-
/** Total active entity subscriber tokens across all keys (sum of ref-counts). */
|
|
931
|
-
declare function getActiveSubscriberCount(store?: GraphStore$1): number;
|
|
932
|
-
/**
|
|
933
|
-
* Discriminated union of devtools events.
|
|
934
|
-
*
|
|
935
|
-
* New inspection surfaces should use the versioned `./devtools` subpath.
|
|
936
|
-
*/
|
|
937
|
-
type DevtoolsEvent = LegacyDevtoolsEvent;
|
|
938
|
-
type DevtoolsListener = (event: DevtoolsEvent) => void;
|
|
939
|
-
/**
|
|
940
|
-
* Subscribe to the devtools event stream.
|
|
941
|
-
*
|
|
942
|
-
* - Returns an `UnsubscribeFn` that removes this listener.
|
|
943
|
-
* - Idempotent: subscribing the same function reference twice tracks it once
|
|
944
|
-
* (Set semantics).
|
|
945
|
-
* - Throwing listeners do NOT block delivery to other listeners; the error is
|
|
946
|
-
* logged via `console.warn` and dispatch continues.
|
|
947
|
-
* - Re-entrancy safe: listeners that subscribe/unsubscribe during dispatch
|
|
948
|
-
* affect future events only, not the in-flight one.
|
|
949
|
-
*/
|
|
950
|
-
declare function subscribeDevtoolsEvent(cb: DevtoolsListener): () => void;
|
|
951
|
-
/**
|
|
952
|
-
* Stops the periodic garbage-collection timer for the selected graph.
|
|
953
|
-
*/
|
|
954
|
-
declare function stopGarbageCollector(storeApi?: GraphStore$1): void;
|
|
955
|
-
/**
|
|
956
|
-
* Starts periodic garbage collection using current `getEngineOptions().gcInterval`.
|
|
957
|
-
* Stops any previous interval first. No-ops during SSR (`window` is undefined) or without `setInterval`.
|
|
958
|
-
* @returns Disposer that stops this graph's collector.
|
|
959
|
-
*/
|
|
960
|
-
declare function startGarbageCollector(storeApi?: GraphStore$1): () => void;
|
|
961
|
-
/** Override global engine behavior (typically once at app bootstrap). Restarts GC with merged options. */
|
|
962
|
-
declare function configureEngine(opts: EngineOptions): void;
|
|
963
|
-
/** Read merged engine options; hooks use this for default `staleTime` and retry behavior. */
|
|
964
|
-
declare function getEngineOptions(): Required<EngineOptions>;
|
|
965
|
-
/**
|
|
966
|
-
* Run a single-entity fetch with dedupe, retries, normalization, and graph updates.
|
|
967
|
-
* Call from hooks/adapters — not from presentational components.
|
|
968
|
-
*/
|
|
969
|
-
declare function fetchEntity<TRaw, TEntity extends object>(opts: EntityQueryOptions<TRaw, TEntity>, engineOpts: Required<EngineOptions>, storeApi?: GraphStore$1): Promise<void>;
|
|
970
|
-
/**
|
|
971
|
-
* Fetch a list page: upserts all rows, writes ids to the list key, supports append mode for pagination.
|
|
972
|
-
* @param isLoadMore - When true, uses a separate dedupe key and `appendListResult` / `setListFetchingMore`.
|
|
973
|
-
*/
|
|
974
|
-
declare function fetchList<TRaw, TEntity extends object>(opts: ListQueryOptions<TRaw, TEntity>, params: ListFetchParams, engineOpts: Required<EngineOptions>, isLoadMore?: boolean, storeApi?: GraphStore$1): Promise<void>;
|
|
975
|
-
/**
|
|
976
|
-
* Opt-in window listeners that mark **subscribed** entities stale on focus/reconnect so hooks can SWR-refetch.
|
|
977
|
-
* Reference-counted per graph and safe for SSR (no-ops without `window`).
|
|
978
|
-
* @returns Disposer that releases this attachment and removes listeners plus GC when the last owner releases it.
|
|
979
|
-
*/
|
|
980
|
-
declare function attachGlobalListeners(storeApi?: GraphStore$1): () => void;
|
|
981
|
-
|
|
982
|
-
/**
|
|
983
|
-
* devtools-event-bus — W5 (seim-em-explorer-event-bus-registry)
|
|
984
|
-
*
|
|
985
|
-
* Ring-buffered, fan-out event bus on top of the W3 `subscribeDevtoolsEvent` tap.
|
|
986
|
-
* Adds: replay-on-subscribe, microtask-level burst coalescing, multi-store registry.
|
|
987
|
-
*/
|
|
988
|
-
|
|
989
|
-
interface DevtoolsEventBusOptions {
|
|
990
|
-
/** Maximum events retained in the ring buffer. Default: 500. */
|
|
991
|
-
bufferSize?: number;
|
|
992
|
-
/**
|
|
993
|
-
* Events 1..N (N = threshold) are dispatched individually as they arrive.
|
|
994
|
-
* Events N+1.. accumulate until the end of the microtask, then are coalesced
|
|
995
|
-
* into one synthetic `kind:"list"` summary event.
|
|
996
|
-
* Default: 10. Set to 0 to disable coalescing entirely.
|
|
997
|
-
*/
|
|
998
|
-
coalesceBurstThreshold?: number;
|
|
999
|
-
}
|
|
1000
|
-
interface DevtoolsEventBus {
|
|
1001
|
-
/** Subscribe to live events. Replays current buffer synchronously before returning. */
|
|
1002
|
-
subscribe(cb: (event: DevtoolsEvent) => void): () => void;
|
|
1003
|
-
/** Snapshot of buffered events in chronological order (oldest first). */
|
|
1004
|
-
getBuffer(): readonly DevtoolsEvent[];
|
|
1005
|
-
/** Force-dispatch any pending coalesced burst synchronously. */
|
|
1006
|
-
flush(): void;
|
|
1007
|
-
/** Release engine-tap, clear all subscribers, cascade inactive to registry. */
|
|
1008
|
-
destroy(): void;
|
|
1009
|
-
/**
|
|
1010
|
-
* Inject a synthetic `DevtoolsEvent` directly into the bus, bypassing the
|
|
1011
|
-
* engine tap. Used by the Chrome MV3 extension panel to feed events arriving
|
|
1012
|
-
* over the port-messaging bridge into the local bus instance.
|
|
1013
|
-
*/
|
|
1014
|
-
inject(event: DevtoolsEvent): void;
|
|
1015
|
-
}
|
|
1016
|
-
/** Matches the signature of `subscribeDevtoolsEvent` — used for external sources. */
|
|
1017
|
-
type DevtoolsSourceFn = (cb: (event: DevtoolsEvent) => void) => () => void;
|
|
1018
|
-
interface RegisteredStore {
|
|
1019
|
-
name: string;
|
|
1020
|
-
active: boolean;
|
|
1021
|
-
}
|
|
1022
|
-
/** Test-only helper: clears the devtools store registry between test runs. */
|
|
1023
|
-
declare function __resetStoreRegistry(): void;
|
|
1024
|
-
declare function createDevtoolsEventBus(opts?: DevtoolsEventBusOptions): DevtoolsEventBus;
|
|
1025
|
-
/**
|
|
1026
|
-
* Wire an additional event source into an existing `DevtoolsEventBus`.
|
|
1027
|
-
* Events from `source` flow through the bus's ring buffer, coalescing, and fan-out.
|
|
1028
|
-
* Throws if `name` is already registered and active.
|
|
1029
|
-
*/
|
|
1030
|
-
declare function registerStore(bus: DevtoolsEventBus, source: DevtoolsSourceFn, name: string): () => void;
|
|
1031
|
-
/** Returns registered stores for one bus, or every bus for legacy callers. */
|
|
1032
|
-
declare function getRegisteredStores(bus?: DevtoolsEventBus): ReadonlyArray<RegisteredStore>;
|
|
1033
|
-
|
|
1034
|
-
/**
|
|
1035
|
-
* Deprecated root time-travel compatibility facade.
|
|
1036
|
-
*
|
|
1037
|
-
* Snapshot data, cursors, retention, rewind state, and listeners are owned by
|
|
1038
|
-
* the optional per-store DevTools controller. This root module imports only a
|
|
1039
|
-
* lightweight delegate bridge, so normal package imports do not pull the
|
|
1040
|
-
* optional controller/protocol implementation into the root bundle.
|
|
1041
|
-
*/
|
|
1042
|
-
|
|
1043
|
-
type GraphSlice = Pick<ReturnType<typeof graphStore.getState>, "entities" | "patches" | "entityStates" | "syncMetadata" | "lists">;
|
|
1044
|
-
interface TimeTravelSnapshot {
|
|
1045
|
-
/** Monotonic controller cursor for the captured state. */
|
|
1046
|
-
seq: number;
|
|
1047
|
-
/** Capture timestamp (ms). */
|
|
1048
|
-
at: number;
|
|
1049
|
-
/** Optional compatibility label. */
|
|
1050
|
-
label?: string;
|
|
1051
|
-
/** Snapshot payloads are controller-private and no longer exposed at root. */
|
|
1052
|
-
data: GraphSlice;
|
|
1053
|
-
}
|
|
1054
|
-
interface TimeTravelState {
|
|
1055
|
-
snapshots: ReadonlyArray<Omit<TimeTravelSnapshot, "data">>;
|
|
1056
|
-
/** Compatibility ring index currently restored, or null when live. */
|
|
1057
|
-
cursor: number | null;
|
|
1058
|
-
capacity: number;
|
|
1059
|
-
}
|
|
1060
|
-
/** @deprecated Attach `@prometheus-ags/entity-graph-core/devtools` and configure its controller. */
|
|
1061
|
-
declare function configureTimeTravel(opts: {
|
|
1062
|
-
capacity?: number;
|
|
1063
|
-
}, storeApi?: GraphStore$1): void;
|
|
1064
|
-
/**
|
|
1065
|
-
* @deprecated Use the attached controller's automatic snapshot history.
|
|
1066
|
-
* Returns `-1` when the optional controller is not attached to `storeApi`.
|
|
1067
|
-
*/
|
|
1068
|
-
declare function recordGraphSnapshot(label?: string, storeApi?: GraphStore$1): number;
|
|
1069
|
-
/** @deprecated Use `controller.rewind(cursor)` from the explicit `./devtools` entry. */
|
|
1070
|
-
declare function restoreGraphSnapshot(index: number, storeApi?: GraphStore$1): boolean;
|
|
1071
|
-
/** @deprecated Use `controller.rewind(cursor)` from the explicit `./devtools` entry. */
|
|
1072
|
-
declare function restoreGraphSnapshotBySeq(seq: number, storeApi?: GraphStore$1): boolean;
|
|
1073
|
-
/** @deprecated Resolve retained cursors through the explicit per-store controller. */
|
|
1074
|
-
declare function stepTimeTravel(delta: number, storeApi?: GraphStore$1): boolean;
|
|
1075
|
-
/** @deprecated Use `controller.getSnapshotHistoryStatus()` and controller events. */
|
|
1076
|
-
declare function getTimeTravelState(storeApi?: GraphStore$1): TimeTravelState;
|
|
1077
|
-
/** @deprecated Subscribe to the explicit per-store controller. */
|
|
1078
|
-
declare function subscribeTimeTravel(cb: () => void, storeApi?: GraphStore$1): () => void;
|
|
1079
|
-
|
|
1080
|
-
/**
|
|
1081
|
-
* Evaluate `FilterSpec` against one in-memory entity — mirrors remote semantics as closely as plain JS allows.
|
|
1082
|
-
* Use for **local** and **hybrid** `useEntityView` paths so UI filtering matches what users expect from the declarative spec.
|
|
1083
|
-
*/
|
|
1084
|
-
declare function matchesFilter(entity: Record<string, unknown>, filter: FilterSpec): boolean;
|
|
1085
|
-
/**
|
|
1086
|
-
* Case-insensitive substring match across configured string fields; empty query is a no-op pass.
|
|
1087
|
-
* Keeps quick search consistent between client-only and debounced remote `q` params.
|
|
1088
|
-
*/
|
|
1089
|
-
declare function matchesSearch(entity: Record<string, unknown>, query: string, fields: string[]): boolean;
|
|
1090
|
-
/**
|
|
1091
|
-
* Multi-key comparator implementing `SortSpec` (null ordering, optional custom comparators, locale-aware string fallback).
|
|
1092
|
-
* Shared by local sorting and binary insertion for realtime updates.
|
|
1093
|
-
*/
|
|
1094
|
-
declare function compareEntities(a: Record<string, unknown>, b: Record<string, unknown>, sort: SortSpec): number;
|
|
1095
|
-
/**
|
|
1096
|
-
* Binary-search insertion index so realtime inserts land in sorted order without resorting the full id list (O(log n) per insert).
|
|
1097
|
-
* Skips missing `getEntity` rows by advancing low — callers should ensure entities exist or tolerate append-like behavior.
|
|
1098
|
-
*/
|
|
1099
|
-
declare function findInsertionIndex(entity: Record<string, unknown>, sortedIds: string[], getEntity: (id: string) => Record<string, unknown> | null, sort: SortSpec): number;
|
|
1100
|
-
/**
|
|
1101
|
-
* Pure list projection: map ids → entities, drop missing, filter/sort/search, return **ids** in display order.
|
|
1102
|
-
* Bridges stored id lists with on-the-fly view descriptors without duplicating entity payloads.
|
|
1103
|
-
*/
|
|
1104
|
-
declare function applyView(ids: string[], getEntity: (id: string) => Record<string, unknown> | null, filter?: FilterSpec | null, sort?: SortSpec | null, search?: {
|
|
1105
|
-
query: string;
|
|
1106
|
-
fields: string[];
|
|
1107
|
-
} | null): string[];
|
|
1108
|
-
/**
|
|
1109
|
-
* Heuristic for whether the graph likely holds **all** rows for a list key (enables local-only filtering/sorting in `useEntityView`).
|
|
1110
|
-
* `total` and `hasNextPage` come from list metadata written by fetchers.
|
|
1111
|
-
*/
|
|
1112
|
-
declare function checkCompleteness(loadedCount: number, total: number | null, hasNextPage: boolean): {
|
|
1113
|
-
isComplete: boolean;
|
|
1114
|
-
reason: string;
|
|
1115
|
-
};
|
|
1116
|
-
|
|
1117
|
-
/**
|
|
1118
|
-
* view/incremental.ts — G3 parity: incremental view maintenance.
|
|
1119
|
-
*
|
|
1120
|
-
* The baseline `applyView` re-filters + re-sorts the entire id list on every
|
|
1121
|
-
* change — O(n) per update. For large lists this is the gap vs TanStack DB's
|
|
1122
|
-
* differential-dataflow live queries.
|
|
1123
|
-
*
|
|
1124
|
-
* This maintains a derived, sorted result and updates it for a SINGLE entity
|
|
1125
|
-
* change in O(log n): binary-search the entity's current position, decide
|
|
1126
|
-
* membership via the filter, and insert / remove / reposition. No full
|
|
1127
|
-
* re-derivation. Result is byte-identical to `applyView` for the same inputs
|
|
1128
|
-
* (correctness parity is asserted in tests).
|
|
1129
|
-
*
|
|
1130
|
-
* Design choice: a hand-rolled dirty-tracking index rather than adopting d2ts
|
|
1131
|
-
* (0.1.x, pre-production) — same acceptance bar (sub-linear single-row update),
|
|
1132
|
-
* far lower dependency risk. The differential engine can replace the internals
|
|
1133
|
-
* later behind this same class without an API change.
|
|
1134
|
-
*/
|
|
1135
|
-
|
|
1136
|
-
interface IncrementalViewOptions {
|
|
1137
|
-
filter?: FilterSpec | null;
|
|
1138
|
-
sort?: SortSpec | null;
|
|
1139
|
-
search?: {
|
|
1140
|
-
query: string;
|
|
1141
|
-
fields: string[];
|
|
1142
|
-
} | null;
|
|
1143
|
-
/** Resolve an entity by id from the graph (or null if absent). */
|
|
1144
|
-
getEntity: (id: string) => Record<string, unknown> | null;
|
|
1145
|
-
}
|
|
1146
|
-
/**
|
|
1147
|
-
* A live, sorted view over a set of entity ids that updates incrementally.
|
|
1148
|
-
*
|
|
1149
|
-
* - `seed(ids)` builds the initial result (one O(n log n) pass).
|
|
1150
|
-
* - `applyChange(id)` updates the result for one changed/added/removed entity
|
|
1151
|
-
* in O(log n) comparisons (+ array splice).
|
|
1152
|
-
* - `result()` returns the current ordered id list (stable reference until a
|
|
1153
|
-
* change mutates it).
|
|
1154
|
-
*/
|
|
1155
|
-
declare class IncrementalView {
|
|
1156
|
-
private readonly opts;
|
|
1157
|
-
private ids;
|
|
1158
|
-
private readonly members;
|
|
1159
|
-
constructor(opts: IncrementalViewOptions);
|
|
1160
|
-
/** Whether an entity qualifies for this view (filter + search). */
|
|
1161
|
-
private qualifies;
|
|
1162
|
-
/** Comparator over ids using the configured sort (stable, id tiebreak). */
|
|
1163
|
-
private cmp;
|
|
1164
|
-
/** Binary-search the insertion index for `id` among current `ids`. */
|
|
1165
|
-
private insertionIndex;
|
|
1166
|
-
/** Build the initial sorted result from a full id set. */
|
|
1167
|
-
seed(ids: string[]): void;
|
|
1168
|
-
/**
|
|
1169
|
-
* Update the view for ONE entity that changed/was added/removed.
|
|
1170
|
-
* Returns true if the result order changed.
|
|
1171
|
-
*
|
|
1172
|
-
* O(log n) to locate; the array splice is O(n) memory-move but performs no
|
|
1173
|
-
* filter/sort over the whole set — the differentiator from full re-derivation.
|
|
1174
|
-
*/
|
|
1175
|
-
applyChange(id: string): boolean;
|
|
1176
|
-
/** Current ordered id list. */
|
|
1177
|
-
result(): string[];
|
|
1178
|
-
/** Current member count. */
|
|
1179
|
-
size(): number;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* FK edge: this entity points at one parent row. Used to invalidate parent aggregates and optional list keys when the FK changes.
|
|
1184
|
-
*/
|
|
1185
|
-
interface BelongsToRelation {
|
|
1186
|
-
cardinality: "belongsTo";
|
|
1187
|
-
foreignKey: string;
|
|
1188
|
-
targetType: EntityType;
|
|
1189
|
-
invalidateTargetLists?: string[];
|
|
1190
|
-
}
|
|
1191
|
-
/**
|
|
1192
|
-
* Inverse collection: children carry `foreignKey` pointing here; `listKeyPrefix` builds the child list query key for a given parent id.
|
|
1193
|
-
*/
|
|
1194
|
-
interface HasManyRelation {
|
|
1195
|
-
cardinality: "hasMany";
|
|
1196
|
-
targetType: EntityType;
|
|
1197
|
-
foreignKey: string;
|
|
1198
|
-
listKeyPrefix: (parentId: EntityId) => unknown[];
|
|
1199
|
-
}
|
|
1200
|
-
/**
|
|
1201
|
-
* Join-style relation stored as an id array on this entity; invalidates partner lists derived via `listKeyPrefix` for each touched id.
|
|
1202
|
-
*/
|
|
1203
|
-
interface ManyToManyRelation {
|
|
1204
|
-
cardinality: "manyToMany";
|
|
1205
|
-
targetType: EntityType;
|
|
1206
|
-
localArrayField?: string;
|
|
1207
|
-
listKeyPrefix: (thisId: EntityId) => unknown[];
|
|
1208
|
-
}
|
|
1209
|
-
type RelationDescriptor = BelongsToRelation | HasManyRelation | ManyToManyRelation;
|
|
1210
|
-
/**
|
|
1211
|
-
* Declarative relation metadata for one `EntityType`: optional named relations and list key prefixes to invalidate on any mutation.
|
|
1212
|
-
*/
|
|
1213
|
-
interface EntitySchema {
|
|
1214
|
-
type: EntityType;
|
|
1215
|
-
relations?: Record<string, RelationDescriptor>;
|
|
1216
|
-
globalListKeys?: string[];
|
|
1217
|
-
}
|
|
1218
|
-
/**
|
|
1219
|
-
* Snapshot diff passed to cascade rules after CRUD: compare `previous` vs `next` to find FK moves, array membership changes, etc.
|
|
1220
|
-
*/
|
|
1221
|
-
interface CascadeContext {
|
|
1222
|
-
type: EntityType;
|
|
1223
|
-
id: EntityId;
|
|
1224
|
-
previous: Record<string, unknown> | null;
|
|
1225
|
-
next: Record<string, unknown> | null;
|
|
1226
|
-
op: "create" | "update" | "delete";
|
|
1227
|
-
}
|
|
1228
|
-
/** Register or replace schema for `schema.type` (typically at app init). */
|
|
1229
|
-
declare function registerSchema(schema: EntitySchema): void;
|
|
1230
|
-
/** Lookup schema for cascade/join reads; returns null if unregistered. */
|
|
1231
|
-
declare function getSchema(type: EntityType): EntitySchema | null;
|
|
1232
|
-
/**
|
|
1233
|
-
* After a successful mutation, mark related entities/lists stale so hooks refetch without manually hunting query keys.
|
|
1234
|
-
* Traverses registered schemas (including reverse `hasMany`) so denormalized UIs stay eventually consistent with the graph.
|
|
1235
|
-
*/
|
|
1236
|
-
declare function cascadeInvalidation(ctx: CascadeContext, storeApi?: GraphStore$1): void;
|
|
1237
|
-
/**
|
|
1238
|
-
* Resolve relation **placeholders** for detail panels: joins graph reads for belongs-to targets, has-many id lists, or many-to-many id arrays.
|
|
1239
|
-
* Returns plain objects suitable for rendering; does not mutate the graph.
|
|
1240
|
-
*/
|
|
1241
|
-
declare function readRelations(type: EntityType, entity: Record<string, unknown>, storeApi?: GraphStore$1): Record<string, unknown>;
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
* agent/json-patch.ts — Minimal RFC-6902 JSON Patch applier.
|
|
1245
|
-
*
|
|
1246
|
-
* AG-UI `STATE_DELTA` events carry RFC-6902 operations. Rather than take a hard
|
|
1247
|
-
* dependency on `fast-json-patch` (last released 2022) or require consumers to
|
|
1248
|
-
* have `@ag-ui/client`'s applier, this implements the standard's six operations
|
|
1249
|
-
* directly. It is small, dependency-free, and fully unit-tested.
|
|
1250
|
-
*
|
|
1251
|
-
* Immutability: every op returns a NEW document; the input is never mutated.
|
|
1252
|
-
*
|
|
1253
|
-
* Supported ops: add, replace, remove, move, copy, test.
|
|
1254
|
-
* Pointers follow RFC-6901 (`/a/b/0`), including the `-` array-append token and
|
|
1255
|
-
* `~1`/`~0` escapes for `/` and `~`.
|
|
1256
|
-
*/
|
|
1257
|
-
interface JsonPatchOp {
|
|
1258
|
-
op: "add" | "remove" | "replace" | "move" | "copy" | "test";
|
|
1259
|
-
path: string;
|
|
1260
|
-
/** For add/replace/test. */
|
|
1261
|
-
value?: unknown;
|
|
1262
|
-
/** For move/copy. */
|
|
1263
|
-
from?: string;
|
|
1264
|
-
}
|
|
1265
|
-
/**
|
|
1266
|
-
* Apply a sequence of RFC-6902 operations to `doc`, returning a new document.
|
|
1267
|
-
* A failing `test` op throws (per spec); structural ops are applied in order.
|
|
1268
|
-
*/
|
|
1269
|
-
declare function applyJsonPatch<T = unknown>(doc: T, ops: readonly JsonPatchOp[]): T;
|
|
1270
|
-
|
|
1271
|
-
/**
|
|
1272
|
-
* agent/ag-ui-bridge.ts — Ingest AG-UI agent state into the entity graph.
|
|
1273
|
-
*
|
|
1274
|
-
* The headline agentic capability (change C2): an agent emits AG-UI state, it
|
|
1275
|
-
* lands in the entity graph, and every view reading those entities updates.
|
|
1276
|
-
*
|
|
1277
|
-
* AG-UI (https://docs.ag-ui.com) streams two state events:
|
|
1278
|
-
* - STATE_SNAPSHOT — the complete agent state object
|
|
1279
|
-
* - STATE_DELTA — a partial update as an RFC-6902 JSON Patch
|
|
1280
|
-
*
|
|
1281
|
-
* Our `patchEntity`/`upsertEntity` already align with this model: STATE_DELTA's
|
|
1282
|
-
* JSON Patch maps onto the graph, and writes route through the C1 MergeStrategy
|
|
1283
|
-
* so agent edits resolve against concurrent realtime/local writes.
|
|
1284
|
-
*
|
|
1285
|
-
* Mapping: the agent's state tree is projected onto entities via an
|
|
1286
|
-
* {@link AgUiStateMapping}. Each entry says "the object at this JSON-Pointer
|
|
1287
|
-
* prefix is an entity of `type`, keyed by `id` (a field of that object or a
|
|
1288
|
-
* constant)". This keeps the bridge transport-agnostic — it does not depend on
|
|
1289
|
-
* `@ag-ui/client` and takes plain event objects, so `@ag-ui/*` stays an OPTIONAL
|
|
1290
|
-
* peer (use it for typed events on the consumer side if desired).
|
|
1291
|
-
*/
|
|
1292
|
-
|
|
1293
|
-
/** AG-UI STATE_SNAPSHOT event (minimal shape — no @ag-ui dependency). */
|
|
1294
|
-
interface AgUiStateSnapshotEvent {
|
|
1295
|
-
type?: "STATE_SNAPSHOT" | string;
|
|
1296
|
-
snapshot: Record<string, unknown>;
|
|
1297
|
-
}
|
|
1298
|
-
/** AG-UI STATE_DELTA event (minimal shape — RFC-6902 patch). */
|
|
1299
|
-
interface AgUiStateDeltaEvent {
|
|
1300
|
-
type?: "STATE_DELTA" | string;
|
|
1301
|
-
delta: JsonPatchOp[];
|
|
1302
|
-
}
|
|
1303
|
-
/** Maps one slice of agent state onto an entity type. */
|
|
1304
|
-
interface AgUiStateMapping {
|
|
1305
|
-
/** Entity type the mapped object(s) belong to. */
|
|
1306
|
-
entityType: string;
|
|
1307
|
-
/**
|
|
1308
|
-
* JSON-Pointer prefix into the agent state where this entity (or collection)
|
|
1309
|
-
* lives. `"/order"` → a single entity; `"/orders"` → a collection keyed by id.
|
|
1310
|
-
*/
|
|
1311
|
-
pointer: string;
|
|
1312
|
-
/** Whether `pointer` addresses one object or a collection (array/record). */
|
|
1313
|
-
kind: "single" | "collection";
|
|
1314
|
-
/**
|
|
1315
|
-
* Field on each object that holds its entity id. For `single` you may instead
|
|
1316
|
-
* pass a constant id via `constantId`.
|
|
1317
|
-
*/
|
|
1318
|
-
idField?: string;
|
|
1319
|
-
/** Constant id for `single` mappings whose object has no id field. */
|
|
1320
|
-
constantId?: string;
|
|
1321
|
-
/**
|
|
1322
|
-
* How to write: `upsert` (merge via MergeStrategy — default) or `replace`
|
|
1323
|
-
* (full overwrite). Snapshots typically replace; deltas typically upsert.
|
|
1324
|
-
*/
|
|
1325
|
-
write?: "upsert" | "replace";
|
|
1326
|
-
}
|
|
1327
|
-
interface ApplyAgUiOptions {
|
|
1328
|
-
mappings: AgUiStateMapping[];
|
|
1329
|
-
}
|
|
1330
|
-
/**
|
|
1331
|
-
* Apply an AG-UI STATE_SNAPSHOT to the graph. Each mapped slice is written as an
|
|
1332
|
-
* entity. Snapshots default to `replace` semantics when the mapping does not
|
|
1333
|
-
* specify otherwise is left to the mapping's `write` field (default upsert).
|
|
1334
|
-
*
|
|
1335
|
-
* @example
|
|
1336
|
-
* ```ts
|
|
1337
|
-
* applyAgUiSnapshot(event, { mappings: [
|
|
1338
|
-
* { entityType: "Order", pointer: "/order", kind: "single", write: "replace" },
|
|
1339
|
-
* { entityType: "LineItem", pointer: "/order/items", kind: "collection" },
|
|
1340
|
-
* ]});
|
|
1341
|
-
* ```
|
|
1342
|
-
*/
|
|
1343
|
-
declare function applyAgUiSnapshot(event: AgUiStateSnapshotEvent, options: ApplyAgUiOptions): void;
|
|
1344
|
-
/**
|
|
1345
|
-
* Apply an AG-UI STATE_DELTA (RFC-6902 JSON Patch) to the graph.
|
|
1346
|
-
*
|
|
1347
|
-
* The delta is applied against a reconstructed agent-state view assembled from
|
|
1348
|
-
* the current graph entities (per the mappings), then the resulting slices are
|
|
1349
|
-
* re-projected back into the graph. This lets path-based deltas target nested
|
|
1350
|
-
* entity fields without the caller tracking the full agent state themselves.
|
|
1351
|
-
*/
|
|
1352
|
-
declare function applyAgUiDelta(event: AgUiStateDeltaEvent, options: ApplyAgUiOptions,
|
|
1353
|
-
/** Current agent-state view; if omitted, reconstructed from the graph mappings. */
|
|
1354
|
-
currentState?: Record<string, unknown>): void;
|
|
1355
|
-
|
|
1356
|
-
/**
|
|
1357
|
-
* adapters/types.ts
|
|
1358
|
-
*
|
|
1359
|
-
* Common contract every data-source adapter implements.
|
|
1360
|
-
* The entity graph doesn't care whether data comes from REST, GraphQL,
|
|
1361
|
-
* WebSocket, Supabase, Convex, PGlite shape sync — they all speak this
|
|
1362
|
-
* interface and write into the same graph.
|
|
1363
|
-
*/
|
|
1364
|
-
|
|
1365
|
-
type ChangeOperation = "insert" | "update" | "delete" | "upsert";
|
|
1366
|
-
interface EntityChange<T = Record<string, unknown>> {
|
|
1367
|
-
op: ChangeOperation;
|
|
1368
|
-
type: EntityType;
|
|
1369
|
-
id: EntityId;
|
|
1370
|
-
data?: T;
|
|
1371
|
-
patch?: Partial<T>;
|
|
1372
|
-
}
|
|
1373
|
-
interface ChangeSet<T = Record<string, unknown>> {
|
|
1374
|
-
changes: EntityChange<T>[];
|
|
1375
|
-
affectedListKeys?: string[];
|
|
1376
|
-
timestamp?: string;
|
|
1377
|
-
}
|
|
1378
|
-
type UnsubscribeFn = () => void;
|
|
1379
|
-
interface SubscriptionConfig {
|
|
1380
|
-
label?: string;
|
|
1381
|
-
replayOnConnect?: boolean;
|
|
1382
|
-
}
|
|
1383
|
-
interface RealtimeAdapter {
|
|
1384
|
-
readonly name: string;
|
|
1385
|
-
subscribe(config: SubscriptionConfig, handler: (changeset: ChangeSet) => void): UnsubscribeFn;
|
|
1386
|
-
onStatusChange?: (cb: (status: AdapterStatus) => void) => UnsubscribeFn;
|
|
1387
|
-
}
|
|
1388
|
-
type AdapterStatus = "connecting" | "connected" | "disconnected" | "error";
|
|
1389
|
-
interface SyncQueryResult<T> {
|
|
1390
|
-
rows: T[];
|
|
1391
|
-
total?: number;
|
|
1392
|
-
}
|
|
1393
|
-
interface SyncAdapter extends RealtimeAdapter {
|
|
1394
|
-
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<SyncQueryResult<T>>;
|
|
1395
|
-
execute(sql: string, params?: unknown[]): Promise<void>;
|
|
1396
|
-
isSynced(): boolean;
|
|
1397
|
-
onSyncComplete(cb: () => void): UnsubscribeFn;
|
|
1398
|
-
}
|
|
1399
|
-
interface ChannelConfig {
|
|
1400
|
-
type: EntityType;
|
|
1401
|
-
filter?: Record<string, unknown>;
|
|
1402
|
-
id?: EntityId;
|
|
1403
|
-
operations?: ChangeOperation[];
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
interface ManagerOptions {
|
|
1407
|
-
flushInterval?: number;
|
|
1408
|
-
store?: GraphStore$1;
|
|
1409
|
-
onStatusChange?: (adapter: string, status: AdapterStatus) => void;
|
|
1410
|
-
onChangeReceived?: (adapter: string, change: EntityChange) => void;
|
|
1411
|
-
}
|
|
1412
|
-
declare class RealtimeManager {
|
|
1413
|
-
private adapters;
|
|
1414
|
-
private pendingChanges;
|
|
1415
|
-
private pendingListKeys;
|
|
1416
|
-
private flushTimer;
|
|
1417
|
-
private opts;
|
|
1418
|
-
private store;
|
|
1419
|
-
constructor(opts?: ManagerOptions);
|
|
1420
|
-
register(adapter: RealtimeAdapter, channels: ChannelConfig[], normalize?: (raw: unknown) => EntityChange | null): UnsubscribeFn;
|
|
1421
|
-
unregister(name: string): void;
|
|
1422
|
-
unregisterAll(): void;
|
|
1423
|
-
private handleChangeset;
|
|
1424
|
-
private scheduleFlush;
|
|
1425
|
-
flush(): void;
|
|
1426
|
-
forceFlush(): void;
|
|
1427
|
-
}
|
|
1428
|
-
declare function getRealtimeManager(opts?: ManagerOptions): RealtimeManager;
|
|
1429
|
-
declare function resetRealtimeManager(): void;
|
|
1430
|
-
|
|
1431
|
-
/**
|
|
1432
|
-
* adapters/realtime-adapters.ts
|
|
1433
|
-
*
|
|
1434
|
-
* WebSocket, Supabase Realtime, Convex, and GraphQL subscription adapters.
|
|
1435
|
-
* All implement RealtimeAdapter and route through RealtimeManager → entity graph.
|
|
1436
|
-
*/
|
|
1437
|
-
|
|
1438
|
-
interface WebSocketAdapterOptions {
|
|
1439
|
-
url: string | (() => string);
|
|
1440
|
-
parseMessage?: (data: unknown) => EntityChange[] | null;
|
|
1441
|
-
protocols?: string | string[];
|
|
1442
|
-
reconnectBaseDelay?: number;
|
|
1443
|
-
maxReconnectAttempts?: number;
|
|
1444
|
-
pingInterval?: number;
|
|
1445
|
-
pingMessage?: string;
|
|
1446
|
-
}
|
|
1447
|
-
declare function createWebSocketAdapter(opts: WebSocketAdapterOptions): RealtimeAdapter;
|
|
1448
|
-
interface SupabaseClient {
|
|
1449
|
-
channel(name: string): SupabaseChannel;
|
|
1450
|
-
}
|
|
1451
|
-
interface SupabaseChannel {
|
|
1452
|
-
on(event: "postgres_changes", config: {
|
|
1453
|
-
event: "*" | "INSERT" | "UPDATE" | "DELETE";
|
|
1454
|
-
schema: string;
|
|
1455
|
-
table: string;
|
|
1456
|
-
filter?: string;
|
|
1457
|
-
}, handler: (payload: SupabasePayload) => void): SupabaseChannel;
|
|
1458
|
-
subscribe(cb?: (status: string) => void): SupabaseChannel;
|
|
1459
|
-
unsubscribe(): Promise<void>;
|
|
1460
|
-
}
|
|
1461
|
-
interface SupabasePayload {
|
|
1462
|
-
eventType: "INSERT" | "UPDATE" | "DELETE";
|
|
1463
|
-
new: Record<string, unknown>;
|
|
1464
|
-
old: Record<string, unknown>;
|
|
1465
|
-
table: string;
|
|
1466
|
-
}
|
|
1467
|
-
interface SupabaseAdapterOptions {
|
|
1468
|
-
tableTypeMap?: Record<string, string>;
|
|
1469
|
-
extractId?: (record: Record<string, unknown>) => string;
|
|
1470
|
-
schema?: string;
|
|
1471
|
-
}
|
|
1472
|
-
declare function createSupabaseRealtimeAdapter(client: SupabaseClient, opts?: SupabaseAdapterOptions): RealtimeAdapter & {
|
|
1473
|
-
subscribeChannel: (config: ChannelConfig & {
|
|
1474
|
-
_handler?: (cs: ChangeSet) => void;
|
|
1475
|
-
}) => UnsubscribeFn;
|
|
1476
|
-
};
|
|
1477
|
-
interface ConvexClient {
|
|
1478
|
-
onUpdate<T>(query: unknown, args: Record<string, unknown>, handler: (result: T) => void): UnsubscribeFn;
|
|
1479
|
-
}
|
|
1480
|
-
interface ConvexChannelConfig<T extends object> {
|
|
1481
|
-
type: string;
|
|
1482
|
-
query: unknown;
|
|
1483
|
-
args?: Record<string, unknown>;
|
|
1484
|
-
extractId?: (record: T) => string;
|
|
1485
|
-
normalize?: (record: T) => Record<string, unknown>;
|
|
1486
|
-
}
|
|
1487
|
-
declare function createConvexAdapter<T extends object>(opts: {
|
|
1488
|
-
client: ConvexClient;
|
|
1489
|
-
channels: ConvexChannelConfig<T>[];
|
|
1490
|
-
}): RealtimeAdapter;
|
|
1491
|
-
interface GQLWsClient {
|
|
1492
|
-
subscribe<T>(payload: {
|
|
1493
|
-
query: string;
|
|
1494
|
-
variables?: Record<string, unknown>;
|
|
1495
|
-
}, sink: {
|
|
1496
|
-
next: (value: {
|
|
1497
|
-
data: T;
|
|
1498
|
-
}) => void;
|
|
1499
|
-
error: (err: unknown) => void;
|
|
1500
|
-
complete: () => void;
|
|
1501
|
-
}): UnsubscribeFn;
|
|
1502
|
-
}
|
|
1503
|
-
interface GQLSubscriptionConfig<T extends object> {
|
|
1504
|
-
type: string;
|
|
1505
|
-
document: string;
|
|
1506
|
-
variables?: Record<string, unknown>;
|
|
1507
|
-
getPayload: (data: T) => GQLPayload | GQLPayload[] | null;
|
|
1508
|
-
}
|
|
1509
|
-
interface GQLPayload {
|
|
1510
|
-
type?: string;
|
|
1511
|
-
node?: Record<string, unknown>;
|
|
1512
|
-
id?: string;
|
|
1513
|
-
}
|
|
1514
|
-
declare function createGraphQLSubscriptionAdapter<T extends object>(opts: {
|
|
1515
|
-
client: GQLWsClient;
|
|
1516
|
-
subscriptions: GQLSubscriptionConfig<T>[];
|
|
1517
|
-
extractId?: (node: Record<string, unknown>, type: string) => string;
|
|
1518
|
-
normalize?: (node: Record<string, unknown>, type: string) => Record<string, unknown>;
|
|
1519
|
-
}): RealtimeAdapter;
|
|
1520
|
-
|
|
1521
|
-
/**
|
|
1522
|
-
* adapters/surreal-live.ts
|
|
1523
|
-
*
|
|
1524
|
-
* SurrealDB LIVE SELECT realtime adapter.
|
|
1525
|
-
*
|
|
1526
|
-
* SurrealDB live stream → per-channel state machine → RealtimeAdapter contract
|
|
1527
|
-
* one ChannelConfig = one LIVE SELECT = one independent reconnect/replay state
|
|
1528
|
-
*
|
|
1529
|
-
* Implements the RealtimeAdapter contract (NOT SyncAdapter) per the corrected
|
|
1530
|
-
* spec at openspec/specs/entity-surreal-live-adapter/spec.md. The consumer
|
|
1531
|
-
* owns the SurrealDB client; the adapter only orchestrates live queries.
|
|
1532
|
-
*/
|
|
1533
|
-
|
|
1534
|
-
interface SurrealLike {
|
|
1535
|
-
query<T = unknown>(sql: string, vars?: Record<string, unknown>): Promise<T[]>;
|
|
1536
|
-
live<T = unknown>(table: string, callback: (action: SurrealLiveAction<T>) => void, diff?: boolean): Promise<string>;
|
|
1537
|
-
kill(uuid: string): Promise<void>;
|
|
1538
|
-
}
|
|
1539
|
-
interface SurrealLiveAction<T = unknown> {
|
|
1540
|
-
action: "CREATE" | "UPDATE" | "DELETE" | "CLOSE" | string;
|
|
1541
|
-
result: T;
|
|
1542
|
-
}
|
|
1543
|
-
interface SurrealCheckpointStore {
|
|
1544
|
-
get(channelKey: string): Promise<string | undefined>;
|
|
1545
|
-
set(channelKey: string, value: string): Promise<void>;
|
|
1546
|
-
}
|
|
1547
|
-
interface SurrealTableConfig {
|
|
1548
|
-
type: EntityType;
|
|
1549
|
-
/** SurrealDB table name; defaults to `type`. */
|
|
1550
|
-
table?: string;
|
|
1551
|
-
/** Field in the row that carries the entity id; defaults to "id". */
|
|
1552
|
-
idField?: string;
|
|
1553
|
-
}
|
|
1554
|
-
interface SurrealLiveAdapterOptions {
|
|
1555
|
-
name?: string;
|
|
1556
|
-
surreal: SurrealLike;
|
|
1557
|
-
tables: SurrealTableConfig[];
|
|
1558
|
-
initialQueryStrategy?: "select-then-live" | "live-only";
|
|
1559
|
-
initialDelayMs?: number;
|
|
1560
|
-
maxDelayMs?: number;
|
|
1561
|
-
connectedSettleMs?: number;
|
|
1562
|
-
checkpointStore?: SurrealCheckpointStore;
|
|
1563
|
-
checkpointField?: string;
|
|
1564
|
-
listKeyResolver?: (change: EntityChange) => string[] | undefined;
|
|
1565
|
-
permanentErrorPatterns?: RegExp[];
|
|
1566
|
-
}
|
|
1567
|
-
declare function createSurrealLiveAdapter(opts: SurrealLiveAdapterOptions): RealtimeAdapter;
|
|
1568
|
-
|
|
1569
|
-
/**
|
|
1570
|
-
* adapters/flint.ts — Flint Realtime Fabric adapter.
|
|
1571
|
-
*
|
|
1572
|
-
* Flint frf-entity-management `watchEntities()` AsyncIterable
|
|
1573
|
-
* → our ChangeSet stream → RealtimeManager → entity graph
|
|
1574
|
-
*
|
|
1575
|
-
* GAP-1 is a BRIDGE, not a from-scratch build: the Flint repo already ships
|
|
1576
|
-
* `@prometheusags/frf-entity-management` whose `RealtimeAdapter.watchEntities()`
|
|
1577
|
-
* yields a plain `EntityEvent` (it JSON-decodes the spine envelope — no proto
|
|
1578
|
-
* types leak). We consume that entity-shaped facade behind a minimal-surface
|
|
1579
|
-
* type, so:
|
|
1580
|
-
* - The unfrozen `proto-v1` risk is contained BELOW this seam.
|
|
1581
|
-
* - `@prometheusags/frf-sdk` stays an OPTIONAL peer; this module imports
|
|
1582
|
-
* nothing from it. The consumer constructs the Flint client and passes it in.
|
|
1583
|
-
*
|
|
1584
|
-
* `EntityEvent.offset` (bigint) is forwarded to an optional checkpoint store so
|
|
1585
|
-
* reconnects resume from the last seen offset (mirrors the surreal-live adapter).
|
|
1586
|
-
*/
|
|
1587
|
-
|
|
1588
|
-
/** A decoded entity change event received from the Flint spine. */
|
|
1589
|
-
interface FlintEntityEvent {
|
|
1590
|
-
entityType: string;
|
|
1591
|
-
entityId: string;
|
|
1592
|
-
tenantId: string;
|
|
1593
|
-
channelId: string;
|
|
1594
|
-
data: Record<string, unknown>;
|
|
1595
|
-
offset: bigint;
|
|
1596
|
-
correlationId?: string;
|
|
1597
|
-
}
|
|
1598
|
-
/** Filter criteria for a Flint entity subscription. */
|
|
1599
|
-
interface FlintEntityQuery {
|
|
1600
|
-
channelId: string;
|
|
1601
|
-
consumerId: string;
|
|
1602
|
-
entityType?: string;
|
|
1603
|
-
fromOffset?: bigint;
|
|
1604
|
-
}
|
|
1605
|
-
/** An entity mutation to publish on the Flint spine. */
|
|
1606
|
-
interface FlintEntityRecord {
|
|
1607
|
-
entityType: string;
|
|
1608
|
-
entityId: string;
|
|
1609
|
-
tenantId: string;
|
|
1610
|
-
channelId: string;
|
|
1611
|
-
data: Record<string, unknown>;
|
|
1612
|
-
correlationId?: string;
|
|
1613
|
-
}
|
|
1614
|
-
/** Minimal surface of the Flint `RealtimeAdapter` we consume. */
|
|
1615
|
-
interface FlintClientLike {
|
|
1616
|
-
watchEntities(query: FlintEntityQuery): AsyncIterable<FlintEntityEvent>;
|
|
1617
|
-
mutateEntity(record: FlintEntityRecord): Promise<void>;
|
|
1618
|
-
}
|
|
1619
|
-
/** Optional resume-offset persistence (per channel+consumer). */
|
|
1620
|
-
interface FlintCheckpointStore {
|
|
1621
|
-
get(key: string): Promise<bigint | undefined> | bigint | undefined;
|
|
1622
|
-
set(key: string, offset: bigint): Promise<void> | void;
|
|
1623
|
-
}
|
|
1624
|
-
interface CreateFlintAdapterOptions {
|
|
1625
|
-
name?: string;
|
|
1626
|
-
/** The Flint entity-management client (frf-entity-management RealtimeAdapter). */
|
|
1627
|
-
client: FlintClientLike;
|
|
1628
|
-
/** Channel to subscribe/publish on. */
|
|
1629
|
-
channelId: string;
|
|
1630
|
-
/** Consumer id for this subscription. */
|
|
1631
|
-
consumerId: string;
|
|
1632
|
-
/** Restrict to one entity type (optional). */
|
|
1633
|
-
entityType?: string;
|
|
1634
|
-
/** Resume-offset store; reconnects start `fromOffset = lastSeen + 1`. */
|
|
1635
|
-
checkpoints?: FlintCheckpointStore;
|
|
1636
|
-
/** Map a Flint event to a change operation. Defaults to "upsert". */
|
|
1637
|
-
resolveOp?: (event: FlintEntityEvent) => ChangeOperation;
|
|
1638
|
-
}
|
|
1639
|
-
/**
|
|
1640
|
-
* Build a {@link RealtimeAdapter} backed by the Flint Realtime Fabric.
|
|
1641
|
-
*
|
|
1642
|
-
* The consumer owns the Flint client (constructed from `@prometheusags/frf-sdk`
|
|
1643
|
-
* / `frf-entity-management`); this adapter only orchestrates the stream.
|
|
1644
|
-
*
|
|
1645
|
-
* @example
|
|
1646
|
-
* ```ts
|
|
1647
|
-
* import { RealtimeAdapter as FrfAdapter } from "@prometheusags/frf-entity-management";
|
|
1648
|
-
* import { getRealtimeManager, createFlintAdapter } from "@prometheus-ags/prometheus-entity-management";
|
|
1649
|
-
*
|
|
1650
|
-
* const flint = new FrfAdapter(spineClient);
|
|
1651
|
-
* const adapter = createFlintAdapter({ client: flint, channelId: "tenant-1", consumerId: "web-1" });
|
|
1652
|
-
* getRealtimeManager().register(adapter);
|
|
1653
|
-
* ```
|
|
1654
|
-
*/
|
|
1655
|
-
declare function createFlintAdapter(options: CreateFlintAdapterOptions): RealtimeAdapter;
|
|
1656
|
-
/**
|
|
1657
|
-
* Publish an entity mutation to the Flint spine via the client.
|
|
1658
|
-
* Thin pass-through kept here so consumers import one Flint surface from us.
|
|
1659
|
-
*/
|
|
1660
|
-
declare function publishFlintMutation(client: FlintClientLike, record: FlintEntityRecord): Promise<void>;
|
|
1661
|
-
|
|
1662
|
-
/**
|
|
1663
|
-
* adapters/electricsql.ts (core)
|
|
1664
|
-
*
|
|
1665
|
-
* ElectricSQL + PGlite local-first adapter — the React-free base.
|
|
1666
|
-
*
|
|
1667
|
-
* Server Postgres → ElectricSQL shape sync (SSE) → PGlite (local WASM Postgres)
|
|
1668
|
-
* ↓ NOTIFY
|
|
1669
|
-
* Entity Graph (Zustand)
|
|
1670
|
-
*
|
|
1671
|
-
* React hooks (`useLocalFirst`, `usePGliteQuery`) live in the binding package
|
|
1672
|
-
* (`@prometheus-ags/entity-graph-react`), built on this adapter.
|
|
1673
|
-
*/
|
|
1674
|
-
|
|
1675
|
-
interface PGlite$1 {
|
|
1676
|
-
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
|
|
1677
|
-
rows: T[];
|
|
1678
|
-
}>;
|
|
1679
|
-
exec(sql: string): Promise<unknown>;
|
|
1680
|
-
listen(channel: string, handler: (payload: string) => void): Promise<() => void>;
|
|
1681
|
-
}
|
|
1682
|
-
interface ShapeMessage$1<T = Record<string, unknown>> {
|
|
1683
|
-
headers: {
|
|
1684
|
-
operation: "insert" | "update" | "delete";
|
|
1685
|
-
};
|
|
1686
|
-
offset: string;
|
|
1687
|
-
value: T;
|
|
1688
|
-
key: string;
|
|
1689
|
-
}
|
|
1690
|
-
interface ShapeStream$1<T = Record<string, unknown>> {
|
|
1691
|
-
subscribe(onMsg: (msgs: ShapeMessage$1<T>[]) => void, onErr?: (e: Error) => void): () => void;
|
|
1692
|
-
isUpToDate: boolean;
|
|
1693
|
-
lastOffset: string;
|
|
1694
|
-
}
|
|
1695
|
-
interface ElectricTableConfig<T extends object> {
|
|
1696
|
-
type: EntityType;
|
|
1697
|
-
table: string;
|
|
1698
|
-
where?: string;
|
|
1699
|
-
idColumn?: string;
|
|
1700
|
-
normalize?: (row: T) => Record<string, unknown>;
|
|
1701
|
-
shapeStream: ShapeStream$1<T>;
|
|
1702
|
-
}
|
|
1703
|
-
interface ElectricAdapterOptions {
|
|
1704
|
-
pglite: PGlite$1;
|
|
1705
|
-
tables: ElectricTableConfig<Record<string, unknown>>[];
|
|
1706
|
-
onSynced?: () => void;
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
declare function createElectricAdapter(opts: ElectricAdapterOptions): SyncAdapter;
|
|
1710
|
-
|
|
1711
|
-
/**
|
|
1712
|
-
* adapters/electricsql-tenant.ts
|
|
1713
|
-
*
|
|
1714
|
-
* Tenant-scoped Electric adapter — the safety primitive that enforces
|
|
1715
|
-
* **RULE 5 — Shape predicates ⊆ RLS** (see hotseaters constraints).
|
|
1716
|
-
*
|
|
1717
|
-
* PGlite has no row-level security. The only way to guarantee a client
|
|
1718
|
-
* never sees cross-tenant data through Electric is to refuse to attach
|
|
1719
|
-
* any shape that lacks a tenant predicate. This wrapper does exactly that:
|
|
1720
|
-
*
|
|
1721
|
-
* - Validates the tenant claim (currently `{ companyId }`) is a UUID.
|
|
1722
|
-
* - Refuses to attach a shape whose `tenantColumn` is `undefined`. We
|
|
1723
|
-
* accept explicit `null` for the company root itself (filtered by `id`).
|
|
1724
|
-
* - Builds the `where` clause from `tenantColumn` and the validated
|
|
1725
|
-
* companyId so individual shape factories cannot drift from RLS.
|
|
1726
|
-
* - Delegates to the existing `createElectricAdapter` for the actual
|
|
1727
|
-
* sync wiring.
|
|
1728
|
-
*
|
|
1729
|
-
* This also fulfils Change 13 item 11 (auth-claim-aware shape registration):
|
|
1730
|
-
* the `tenantClaim` is the typed seam where authn meets shape registration.
|
|
1731
|
-
*
|
|
1732
|
-
* Self-hosted Supabase only. Local stack and `https://electricsql.prometheusags.ai`
|
|
1733
|
-
* are the only acceptable Electric endpoints — this module does not
|
|
1734
|
-
* hard-code either; it only governs the predicate.
|
|
1735
|
-
*/
|
|
1736
|
-
|
|
1737
|
-
interface PGlite {
|
|
1738
|
-
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
|
|
1739
|
-
rows: T[];
|
|
1740
|
-
}>;
|
|
1741
|
-
exec(sql: string): Promise<unknown>;
|
|
1742
|
-
listen(channel: string, handler: (payload: string) => void): Promise<() => void>;
|
|
1743
|
-
}
|
|
1744
|
-
interface ShapeMessage<T = Record<string, unknown>> {
|
|
1745
|
-
headers: {
|
|
1746
|
-
operation: "insert" | "update" | "delete";
|
|
1747
|
-
};
|
|
1748
|
-
offset: string;
|
|
1749
|
-
value: T;
|
|
1750
|
-
key: string;
|
|
1751
|
-
}
|
|
1752
|
-
interface ShapeStream<T = Record<string, unknown>> {
|
|
1753
|
-
subscribe(onMsg: (msgs: ShapeMessage<T>[]) => void, onErr?: (e: Error) => void): () => void;
|
|
1754
|
-
isUpToDate: boolean;
|
|
1755
|
-
lastOffset: string;
|
|
1756
|
-
}
|
|
1757
|
-
/** Auth claim required to register tenant-scoped shapes. */
|
|
1758
|
-
interface TenantClaim {
|
|
1759
|
-
companyId: string;
|
|
1760
|
-
}
|
|
1761
|
-
interface TenantScopedTableConfig<T extends object = Record<string, unknown>> {
|
|
1762
|
-
type: EntityType;
|
|
1763
|
-
table: string;
|
|
1764
|
-
/**
|
|
1765
|
-
* Column used for tenant filtering.
|
|
1766
|
-
*
|
|
1767
|
-
* - A string (`"company_id"`) yields `WHERE company_id = '<companyId>'`.
|
|
1768
|
-
* - Explicit `null` means the table IS the tenant root and is filtered by
|
|
1769
|
-
* `id = '<companyId>'`. Only the `company` table qualifies.
|
|
1770
|
-
* - `undefined` is **rejected** — this is the safety gate.
|
|
1771
|
-
*/
|
|
1772
|
-
tenantColumn: string | null;
|
|
1773
|
-
primaryKey?: string[];
|
|
1774
|
-
/**
|
|
1775
|
-
* Factory invoked with the constructed `where` clause and the tenant claim.
|
|
1776
|
-
* Consumers wire their preferred Electric `ShapeStream` builder here. The
|
|
1777
|
-
* factory must use the supplied `where` verbatim (no widening).
|
|
1778
|
-
*/
|
|
1779
|
-
shapeStreamFactory: (params: {
|
|
1780
|
-
table: string;
|
|
1781
|
-
where: string;
|
|
1782
|
-
tenantClaim: TenantClaim;
|
|
1783
|
-
}) => ShapeStream<T>;
|
|
1784
|
-
normalize?: (row: T) => Record<string, unknown>;
|
|
1785
|
-
}
|
|
1786
|
-
interface TenantScopedAdapterOptions {
|
|
1787
|
-
pglite: PGlite;
|
|
1788
|
-
tenantClaim: TenantClaim;
|
|
1789
|
-
tables: TenantScopedTableConfig[];
|
|
1790
|
-
onSynced?: () => void;
|
|
1791
|
-
}
|
|
1792
|
-
/**
|
|
1793
|
-
* Build the `where` clause for a single shape. Exposed for tests.
|
|
1794
|
-
*
|
|
1795
|
-
* - `tenantColumn === null` → `id = '<companyId>'` (company-root case)
|
|
1796
|
-
* - `tenantColumn === string` → `<tenantColumn> = '<companyId>'`
|
|
1797
|
-
*
|
|
1798
|
-
* Throws if `tenantColumn` is `undefined` or `companyId` is not a UUID.
|
|
1799
|
-
*/
|
|
1800
|
-
declare function buildTenantWhere(tenantColumn: string | null | undefined, companyId: string, tableLabel: string): string;
|
|
1801
|
-
/**
|
|
1802
|
-
* Build a tenant-scoped {@link SyncAdapter}.
|
|
1803
|
-
*
|
|
1804
|
-
* For each table in `tables`:
|
|
1805
|
-
* 1. Validates `tenantColumn` is defined (string or explicit null).
|
|
1806
|
-
* 2. Validates `companyId` is a UUID.
|
|
1807
|
-
* 3. Builds the predicate and calls `shapeStreamFactory(...)` to get the
|
|
1808
|
-
* actual `ShapeStream`.
|
|
1809
|
-
* 4. Hands the resulting list off to `createElectricAdapter` for wiring.
|
|
1810
|
-
*
|
|
1811
|
-
* @throws if any table lacks `tenantColumn`, or the company id is not a UUID.
|
|
1812
|
-
*/
|
|
1813
|
-
declare function createTenantScopedElectricAdapter(opts: TenantScopedAdapterOptions): SyncAdapter;
|
|
1814
|
-
|
|
1815
|
-
/**
|
|
1816
|
-
* adapters/pglite-persistence.ts
|
|
1817
|
-
*
|
|
1818
|
-
* PGlite-backed implementation of {@link GraphPersistenceAdapter}.
|
|
1819
|
-
*
|
|
1820
|
-
* Stores the local-first runtime's graph snapshot inside a PGlite table
|
|
1821
|
-
* (`_graph_snapshot` by default) instead of `localStorage`/`IndexedDB`.
|
|
1822
|
-
*
|
|
1823
|
-
* Why this exists:
|
|
1824
|
-
* - The app already has a PGlite handle for ElectricSQL sync.
|
|
1825
|
-
* - Putting the graph snapshot alongside synced data means one storage
|
|
1826
|
-
* surface to back up, clear, and reason about.
|
|
1827
|
-
* - Works in Tauri WebView + Node (PGlite is a WASM Postgres) without
|
|
1828
|
-
* pulling in browser-only storage.
|
|
1829
|
-
*
|
|
1830
|
-
* Contract:
|
|
1831
|
-
* - `get(key)` -> returns the stored string or null
|
|
1832
|
-
* - `set(key, v)` -> upserts (insert-or-replace), stamping `updated_at`
|
|
1833
|
-
* - `remove(key)` -> deletes the row (no-op if absent)
|
|
1834
|
-
*
|
|
1835
|
-
* The function lazily ensures the storage table exists on first call.
|
|
1836
|
-
* That `CREATE TABLE IF NOT EXISTS` is idempotent so it's safe to retry.
|
|
1837
|
-
*
|
|
1838
|
-
* Self-hosted Supabase only. HotSeatersMVP is the bible. This module does
|
|
1839
|
-
* not import `@electric-sql/pglite` — consumers pass a PGlite-shaped handle.
|
|
1840
|
-
*/
|
|
1841
|
-
|
|
1842
|
-
interface PGlitePersistenceClient {
|
|
1843
|
-
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
|
|
1844
|
-
rows: T[];
|
|
1845
|
-
}>;
|
|
1846
|
-
exec(sql: string): Promise<unknown>;
|
|
1847
|
-
}
|
|
1848
|
-
interface CreatePGlitePersistenceAdapterOptions {
|
|
1849
|
-
/** Name of the snapshot table. Defaults to `_graph_snapshot`. */
|
|
1850
|
-
tableName?: string;
|
|
1851
|
-
}
|
|
1852
|
-
/**
|
|
1853
|
-
* Returns a {@link GraphPersistenceAdapter} that reads/writes the graph
|
|
1854
|
-
* snapshot through a PGlite-shaped client.
|
|
1855
|
-
*
|
|
1856
|
-
* @example
|
|
1857
|
-
* ```ts
|
|
1858
|
-
* import { PGlite } from "@electric-sql/pglite";
|
|
1859
|
-
* import { startLocalFirstGraph, createPGlitePersistenceAdapter } from "@prometheus-ags/prometheus-entity-management";
|
|
1860
|
-
*
|
|
1861
|
-
* const pglite = await PGlite.create("idb://hotseaters");
|
|
1862
|
-
* const storage = await createPGlitePersistenceAdapter(pglite);
|
|
1863
|
-
* const runtime = startLocalFirstGraph({ storage, key: "hotseaters:graph" });
|
|
1864
|
-
* ```
|
|
1865
|
-
*/
|
|
1866
|
-
declare function createPGlitePersistenceAdapter(pglite: PGlitePersistenceClient, options?: CreatePGlitePersistenceAdapterOptions): Promise<GraphPersistenceAdapter>;
|
|
1867
|
-
|
|
1868
|
-
/**
|
|
1869
|
-
* adapters/tauri-sql-persistence.ts
|
|
1870
|
-
*
|
|
1871
|
-
* SQLite-backed implementation of {@link GraphPersistenceAdapter} for Tauri
|
|
1872
|
-
* desktop, via the official `@tauri-apps/plugin-sql` `Database` handle.
|
|
1873
|
-
*
|
|
1874
|
-
* Why this exists:
|
|
1875
|
-
* - On Tauri desktop the natural on-device store is SQLite, not PGlite-wasm.
|
|
1876
|
-
* - This pairs with `createPGlitePersistenceAdapter` (browser/wasm) so the
|
|
1877
|
-
* same local-first runtime persists across web and desktop unchanged.
|
|
1878
|
-
*
|
|
1879
|
-
* The consumer owns the Tauri `Database` handle (from `Database.load(...)`).
|
|
1880
|
-
* This module does NOT import `@tauri-apps/plugin-sql` — it takes a
|
|
1881
|
-
* minimal-surface client, mirroring the PGlite/Electric adapter pattern, so it
|
|
1882
|
-
* adds no hard dependency. `@tauri-apps/plugin-sql` is an optional peer.
|
|
1883
|
-
*
|
|
1884
|
-
* Contract (same as every GraphPersistenceAdapter):
|
|
1885
|
-
* - `get(key)` -> stored string or null
|
|
1886
|
-
* - `set(key, v)` -> upsert (INSERT ... ON CONFLICT)
|
|
1887
|
-
* - `remove(key)` -> delete (no-op if absent)
|
|
1888
|
-
*
|
|
1889
|
-
* Tauri SQL uses SQLite `?`-positional bind params (not `$1`).
|
|
1890
|
-
*/
|
|
1891
|
-
|
|
1892
|
-
/**
|
|
1893
|
-
* Minimal surface of a `@tauri-apps/plugin-sql` `Database` handle.
|
|
1894
|
-
* Avoids a hard dep; matches the loaded-Database shape (`execute` + `select`).
|
|
1895
|
-
*/
|
|
1896
|
-
interface TauriSqlClient {
|
|
1897
|
-
execute(query: string, bindValues?: unknown[]): Promise<unknown>;
|
|
1898
|
-
select<T = Record<string, unknown>>(query: string, bindValues?: unknown[]): Promise<T[]>;
|
|
1899
|
-
}
|
|
1900
|
-
interface CreateTauriSqlPersistenceAdapterOptions {
|
|
1901
|
-
/** Name of the snapshot table. Defaults to `_graph_snapshot`. */
|
|
1902
|
-
tableName?: string;
|
|
1903
|
-
}
|
|
1904
|
-
/**
|
|
1905
|
-
* Returns a {@link GraphPersistenceAdapter} backed by a Tauri SQLite `Database`.
|
|
1906
|
-
*
|
|
1907
|
-
* @example
|
|
1908
|
-
* ```ts
|
|
1909
|
-
* import Database from "@tauri-apps/plugin-sql";
|
|
1910
|
-
* import { startLocalFirstGraph, createTauriSqlPersistenceAdapter } from "@prometheus-ags/prometheus-entity-management";
|
|
1911
|
-
*
|
|
1912
|
-
* const db = await Database.load("sqlite:app.db");
|
|
1913
|
-
* const storage = await createTauriSqlPersistenceAdapter(db);
|
|
1914
|
-
* const runtime = startLocalFirstGraph({ storage, key: "app:graph" });
|
|
1915
|
-
* ```
|
|
1916
|
-
*/
|
|
1917
|
-
declare function createTauriSqlPersistenceAdapter(db: TauriSqlClient, options?: CreateTauriSqlPersistenceAdapterOptions): Promise<GraphPersistenceAdapter>;
|
|
1918
|
-
|
|
1919
|
-
/**
|
|
1920
|
-
* schema-from-sql.ts
|
|
1921
|
-
*
|
|
1922
|
-
* Generates a JSON Schema (and registers it via `registerEntityJsonSchema`)
|
|
1923
|
-
* directly from a Postgres `CREATE TABLE` statement. Lets a consumer keep
|
|
1924
|
-
* `latest-data/supabase/migrations/*.sql` as the single source of truth for
|
|
1925
|
-
* column shapes — no hand-maintained TypeScript schema duplicates.
|
|
1926
|
-
*
|
|
1927
|
-
* Deliberately regex-based: a real SQL parser is overkill for the slice of
|
|
1928
|
-
* DDL we care about, and would add a non-trivial runtime dep.
|
|
1929
|
-
*
|
|
1930
|
-
* Type mapping
|
|
1931
|
-
* ------------
|
|
1932
|
-
* UUID, TEXT, VARCHAR(*) -> { type: "string" }
|
|
1933
|
-
* INTEGER, INT, BIGINT, SMALLINT -> { type: "integer" }
|
|
1934
|
-
* NUMERIC(*), DECIMAL(*) -> { type: "number" }
|
|
1935
|
-
* BOOLEAN, BOOL -> { type: "boolean" }
|
|
1936
|
-
* TIMESTAMPTZ, TIMESTAMP -> { type: "string", format: "date-time" }
|
|
1937
|
-
* DATE -> { type: "string", format: "date" }
|
|
1938
|
-
* JSONB, JSON -> { type: "object" }
|
|
1939
|
-
* TEXT[] -> { type: "array", items: { type: "string" } }
|
|
1940
|
-
* anything else -> { type: "string" } + "x-warning"
|
|
1941
|
-
*
|
|
1942
|
-
* `required` is populated from `NOT NULL` columns that lack a `DEFAULT`.
|
|
1943
|
-
* Callers can pass `overrides` to deep-merge a partial config (typically to
|
|
1944
|
-
* narrow a JSONB column to an array, or to add `enum`/`format` hints).
|
|
1945
|
-
*/
|
|
1946
|
-
|
|
1947
|
-
interface RegisterEntityFromSqlOptions {
|
|
1948
|
-
entityType: string;
|
|
1949
|
-
/** A single `CREATE TABLE` statement (extra DDL around it is ignored). */
|
|
1950
|
-
createTableSql: string;
|
|
1951
|
-
/** Optional deep-merge overrides (overrides win). */
|
|
1952
|
-
overrides?: Partial<EntityJsonSchemaConfig>;
|
|
1953
|
-
}
|
|
1954
|
-
interface ParsedColumn {
|
|
1955
|
-
name: string;
|
|
1956
|
-
sqlType: string;
|
|
1957
|
-
notNull: boolean;
|
|
1958
|
-
hasDefault: boolean;
|
|
1959
|
-
}
|
|
1960
|
-
interface ParsedTable {
|
|
1961
|
-
tableName: string;
|
|
1962
|
-
columns: ParsedColumn[];
|
|
1963
|
-
}
|
|
1964
|
-
/**
|
|
1965
|
-
* Parse a `CREATE TABLE` block. Exposed for tests and for callers who need
|
|
1966
|
-
* the intermediate representation.
|
|
1967
|
-
*/
|
|
1968
|
-
declare function parseCreateTable(sql: string): ParsedTable;
|
|
1969
|
-
/**
|
|
1970
|
-
* Map a normalized (uppercased, whitespace-stripped) SQL type to a JSON
|
|
1971
|
-
* schema fragment.
|
|
1972
|
-
*
|
|
1973
|
-
* Returns `{ schema, warning }` so the caller can surface "unmapped type"
|
|
1974
|
-
* notes via `x-warning` on the property.
|
|
1975
|
-
*/
|
|
1976
|
-
declare function sqlTypeToJsonSchema(sqlType: string): {
|
|
1977
|
-
schema: JsonSchemaObject;
|
|
1978
|
-
warning?: string;
|
|
1979
|
-
};
|
|
1980
|
-
/**
|
|
1981
|
-
* Build (and register) an `EntityJsonSchemaConfig` from a CREATE TABLE
|
|
1982
|
-
* statement. Returns the registered config so callers can introspect it.
|
|
1983
|
-
*/
|
|
1984
|
-
declare function registerEntityFromSql(opts: RegisterEntityFromSqlOptions): EntityJsonSchemaConfig;
|
|
1985
|
-
|
|
1986
|
-
/**
|
|
1987
|
-
* table/types.ts
|
|
1988
|
-
*
|
|
1989
|
-
* Pure table engine type definitions — zero framework dependencies.
|
|
1990
|
-
* Structurally compatible with TanStack Table v8 for easy migration,
|
|
1991
|
-
* but fully self-contained within the prometheus-entity-management library.
|
|
1992
|
-
*/
|
|
1993
|
-
type ViewMode = "table" | "gallery" | "list";
|
|
1994
|
-
type Updater<T> = T | ((prev: T) => T);
|
|
1995
|
-
type AccessorFn<TData, TValue = unknown> = (row: TData, index: number) => TValue;
|
|
1996
|
-
type HeaderContext<TData> = {
|
|
1997
|
-
table: TableInstance<TData>;
|
|
1998
|
-
header: Header<TData>;
|
|
1999
|
-
column: Column<TData>;
|
|
2000
|
-
};
|
|
2001
|
-
type CellContext<TData> = {
|
|
2002
|
-
table: TableInstance<TData>;
|
|
2003
|
-
row: Row<TData>;
|
|
2004
|
-
cell: Cell<TData>;
|
|
2005
|
-
column: Column<TData>;
|
|
2006
|
-
getValue: <T = unknown>() => T;
|
|
2007
|
-
renderValue: <T = unknown>() => T | null;
|
|
2008
|
-
};
|
|
2009
|
-
type HeaderRenderer<TData> = string | ((context: HeaderContext<TData>) => unknown);
|
|
2010
|
-
type CellRenderer<TData> = string | ((context: CellContext<TData>) => unknown);
|
|
2011
|
-
type FilterFn<TData> = (row: Row<TData>, columnId: string, filterValue: unknown) => boolean;
|
|
2012
|
-
type SortingFn<TData> = (rowA: Row<TData>, rowB: Row<TData>, columnId: string) => number;
|
|
2013
|
-
type AggregationFn<TData> = (columnId: string, leafRows: Row<TData>[], childRows: Row<TData>[]) => unknown;
|
|
2014
|
-
interface ColumnMeta<TData = unknown> {
|
|
2015
|
-
entityMeta?: {
|
|
2016
|
-
field: keyof TData;
|
|
2017
|
-
filterType: "text" | "number" | "date" | "dateRange" | "boolean" | "enum" | "relation" | "none";
|
|
2018
|
-
enumOptions?: Array<{
|
|
2019
|
-
label: string;
|
|
2020
|
-
value: string;
|
|
2021
|
-
color?: string;
|
|
2022
|
-
}>;
|
|
2023
|
-
relationEntityType?: string;
|
|
2024
|
-
editable?: boolean;
|
|
2025
|
-
hideable?: boolean;
|
|
2026
|
-
};
|
|
2027
|
-
[key: string]: unknown;
|
|
2028
|
-
}
|
|
2029
|
-
interface ColumnDef<TData, TValue = unknown> {
|
|
2030
|
-
id?: string;
|
|
2031
|
-
accessorKey?: keyof TData & string;
|
|
2032
|
-
accessorFn?: AccessorFn<TData, TValue>;
|
|
2033
|
-
header?: HeaderRenderer<TData>;
|
|
2034
|
-
cell?: CellRenderer<TData>;
|
|
2035
|
-
footer?: HeaderRenderer<TData>;
|
|
2036
|
-
size?: number;
|
|
2037
|
-
minSize?: number;
|
|
2038
|
-
maxSize?: number;
|
|
2039
|
-
enableSorting?: boolean;
|
|
2040
|
-
enableFiltering?: boolean;
|
|
2041
|
-
enableHiding?: boolean;
|
|
2042
|
-
enablePinning?: boolean;
|
|
2043
|
-
enableGrouping?: boolean;
|
|
2044
|
-
enableResizing?: boolean;
|
|
2045
|
-
filterFn?: FilterFn<TData> | "auto";
|
|
2046
|
-
sortingFn?: SortingFn<TData> | "auto";
|
|
2047
|
-
aggregationFn?: AggregationFn<TData> | "auto" | "sum" | "min" | "max" | "count" | "mean" | "median" | "unique";
|
|
2048
|
-
sortDescFirst?: boolean;
|
|
2049
|
-
sortUndefined?: "first" | "last" | false;
|
|
2050
|
-
invertSorting?: boolean;
|
|
2051
|
-
meta?: ColumnMeta<TData>;
|
|
2052
|
-
columns?: ColumnDef<TData, unknown>[];
|
|
2053
|
-
}
|
|
2054
|
-
interface SortingColumn {
|
|
2055
|
-
id: string;
|
|
2056
|
-
desc: boolean;
|
|
2057
|
-
}
|
|
2058
|
-
type SortingState = SortingColumn[];
|
|
2059
|
-
interface ColumnFilter {
|
|
2060
|
-
id: string;
|
|
2061
|
-
value: unknown;
|
|
2062
|
-
}
|
|
2063
|
-
type ColumnFiltersState = ColumnFilter[];
|
|
2064
|
-
type RowSelectionState = Record<string, boolean>;
|
|
2065
|
-
type ColumnVisibilityState = Record<string, boolean>;
|
|
2066
|
-
type ColumnOrderState = string[];
|
|
2067
|
-
interface ColumnPinningState {
|
|
2068
|
-
left?: string[];
|
|
2069
|
-
right?: string[];
|
|
2070
|
-
}
|
|
2071
|
-
type ColumnSizingState = Record<string, number>;
|
|
2072
|
-
type ColumnSizingInfoState = {
|
|
2073
|
-
startOffset: number | null;
|
|
2074
|
-
startSize: number | null;
|
|
2075
|
-
deltaOffset: number | null;
|
|
2076
|
-
deltaPercentage: number | null;
|
|
2077
|
-
isResizingColumn: string | false;
|
|
2078
|
-
columnSizingStart: [string, number][];
|
|
2079
|
-
};
|
|
2080
|
-
type ExpandedState = Record<string, boolean> | true;
|
|
2081
|
-
type GroupingState = string[];
|
|
2082
|
-
interface PaginationState {
|
|
2083
|
-
pageIndex: number;
|
|
2084
|
-
pageSize: number;
|
|
2085
|
-
}
|
|
2086
|
-
interface TableState {
|
|
2087
|
-
sorting: SortingState;
|
|
2088
|
-
columnFilters: ColumnFiltersState;
|
|
2089
|
-
globalFilter: unknown;
|
|
2090
|
-
rowSelection: RowSelectionState;
|
|
2091
|
-
columnVisibility: ColumnVisibilityState;
|
|
2092
|
-
columnOrder: ColumnOrderState;
|
|
2093
|
-
columnPinning: ColumnPinningState;
|
|
2094
|
-
columnSizing: ColumnSizingState;
|
|
2095
|
-
columnSizingInfo: ColumnSizingInfoState;
|
|
2096
|
-
expanded: ExpandedState;
|
|
2097
|
-
grouping: GroupingState;
|
|
2098
|
-
pagination: PaginationState;
|
|
2099
|
-
}
|
|
2100
|
-
interface Row<TData> {
|
|
2101
|
-
id: string;
|
|
2102
|
-
index: number;
|
|
2103
|
-
original: TData;
|
|
2104
|
-
depth: number;
|
|
2105
|
-
parentId?: string;
|
|
2106
|
-
subRows: Row<TData>[];
|
|
2107
|
-
getValue: <T = unknown>(columnId: string) => T;
|
|
2108
|
-
renderValue: <T = unknown>(columnId: string) => T | null;
|
|
2109
|
-
getIsSelected: () => boolean;
|
|
2110
|
-
getCanSelect: () => boolean;
|
|
2111
|
-
getIsAllSubRowsSelected: () => boolean;
|
|
2112
|
-
getIsSomeSelected: () => boolean;
|
|
2113
|
-
toggleSelected: (value?: boolean) => void;
|
|
2114
|
-
getToggleSelectedHandler: () => (e: unknown) => void;
|
|
2115
|
-
getIsExpanded: () => boolean;
|
|
2116
|
-
getCanExpand: () => boolean;
|
|
2117
|
-
toggleExpanded: (value?: boolean) => void;
|
|
2118
|
-
getToggleExpandedHandler: () => () => void;
|
|
2119
|
-
getIsGrouped: () => boolean;
|
|
2120
|
-
groupingColumnId?: string;
|
|
2121
|
-
groupingValue?: unknown;
|
|
2122
|
-
getVisibleCells: () => Cell<TData>[];
|
|
2123
|
-
getAllCells: () => Cell<TData>[];
|
|
2124
|
-
getIsPinned: () => "top" | "bottom" | false;
|
|
2125
|
-
pin: (position: "top" | "bottom" | false) => void;
|
|
2126
|
-
}
|
|
2127
|
-
interface Cell<TData> {
|
|
2128
|
-
id: string;
|
|
2129
|
-
row: Row<TData>;
|
|
2130
|
-
column: Column<TData>;
|
|
2131
|
-
getValue: <T = unknown>() => T;
|
|
2132
|
-
renderValue: <T = unknown>() => T | null;
|
|
2133
|
-
getIsGrouped: () => boolean;
|
|
2134
|
-
getIsPlaceholder: () => boolean;
|
|
2135
|
-
getIsAggregated: () => boolean;
|
|
2136
|
-
getContext: () => CellContext<TData>;
|
|
2137
|
-
}
|
|
2138
|
-
interface Header<TData> {
|
|
2139
|
-
id: string;
|
|
2140
|
-
index: number;
|
|
2141
|
-
depth: number;
|
|
2142
|
-
column: Column<TData>;
|
|
2143
|
-
isPlaceholder: boolean;
|
|
2144
|
-
placeholderId?: string;
|
|
2145
|
-
subHeaders: Header<TData>[];
|
|
2146
|
-
colSpan: number;
|
|
2147
|
-
rowSpan: number;
|
|
2148
|
-
getSize: () => number;
|
|
2149
|
-
getStart: () => number;
|
|
2150
|
-
getContext: () => HeaderContext<TData>;
|
|
2151
|
-
getResizeHandler: () => (event: unknown) => void;
|
|
2152
|
-
getLeafHeaders: () => Header<TData>[];
|
|
2153
|
-
}
|
|
2154
|
-
interface HeaderGroup<TData> {
|
|
2155
|
-
id: string;
|
|
2156
|
-
depth: number;
|
|
2157
|
-
headers: Header<TData>[];
|
|
2158
|
-
}
|
|
2159
|
-
interface Column<TData> {
|
|
2160
|
-
id: string;
|
|
2161
|
-
depth: number;
|
|
2162
|
-
columnDef: ColumnDef<TData>;
|
|
2163
|
-
columns: Column<TData>[];
|
|
2164
|
-
parent?: Column<TData>;
|
|
2165
|
-
getFlatColumns: () => Column<TData>[];
|
|
2166
|
-
getLeafColumns: () => Column<TData>[];
|
|
2167
|
-
getIsSorted: () => false | "asc" | "desc";
|
|
2168
|
-
getNextSortingOrder: () => "asc" | "desc" | false;
|
|
2169
|
-
getCanSort: () => boolean;
|
|
2170
|
-
toggleSorting: (desc?: boolean, isMulti?: boolean) => void;
|
|
2171
|
-
clearSorting: () => void;
|
|
2172
|
-
getSortIndex: () => number;
|
|
2173
|
-
getAutoSortingFn: () => SortingFn<TData>;
|
|
2174
|
-
getAutoSortDir: () => "asc" | "desc";
|
|
2175
|
-
getIsFiltered: () => boolean;
|
|
2176
|
-
getFilterValue: () => unknown;
|
|
2177
|
-
setFilterValue: (value: unknown) => void;
|
|
2178
|
-
getCanFilter: () => boolean;
|
|
2179
|
-
getAutoFilterFn: () => FilterFn<TData> | undefined;
|
|
2180
|
-
getIsVisible: () => boolean;
|
|
2181
|
-
toggleVisibility: (value?: boolean) => void;
|
|
2182
|
-
getCanHide: () => boolean;
|
|
2183
|
-
getIsPinned: () => "left" | "right" | false;
|
|
2184
|
-
pin: (position: "left" | "right" | false) => void;
|
|
2185
|
-
getCanPin: () => boolean;
|
|
2186
|
-
getIsGrouped: () => boolean;
|
|
2187
|
-
toggleGrouping: () => void;
|
|
2188
|
-
getCanGroup: () => boolean;
|
|
2189
|
-
getGroupedIndex: () => number;
|
|
2190
|
-
getSize: () => number;
|
|
2191
|
-
getStart: (position?: "left" | "center" | "right") => number;
|
|
2192
|
-
getCanResize: () => boolean;
|
|
2193
|
-
resetSize: () => void;
|
|
2194
|
-
getIndex: (position?: "left" | "center" | "right") => number;
|
|
2195
|
-
}
|
|
2196
|
-
interface RowModel<TData> {
|
|
2197
|
-
rows: Row<TData>[];
|
|
2198
|
-
flatRows: Row<TData>[];
|
|
2199
|
-
rowsById: Record<string, Row<TData>>;
|
|
2200
|
-
}
|
|
2201
|
-
interface TableOptions<TData> {
|
|
2202
|
-
data: TData[];
|
|
2203
|
-
columns: ColumnDef<TData>[];
|
|
2204
|
-
getRowId?: (row: TData, index: number, parent?: Row<TData>) => string;
|
|
2205
|
-
defaultColumn?: Partial<ColumnDef<TData>>;
|
|
2206
|
-
/** Seed the initial value for any internal state slice without making it controlled. */
|
|
2207
|
-
initialState?: Partial<TableState>;
|
|
2208
|
-
/** Fully controlled state — every key provided here locks that slice and must be updated externally. */
|
|
2209
|
-
state?: Partial<TableState>;
|
|
2210
|
-
onStateChange?: (updater: Updater<TableState>) => void;
|
|
2211
|
-
manualSorting?: boolean;
|
|
2212
|
-
enableSorting?: boolean;
|
|
2213
|
-
enableMultiSort?: boolean;
|
|
2214
|
-
enableSortingRemoval?: boolean;
|
|
2215
|
-
enableMultiRemove?: boolean;
|
|
2216
|
-
maxMultiSortColCount?: number;
|
|
2217
|
-
sortDescFirst?: boolean;
|
|
2218
|
-
onSortingChange?: (updater: Updater<SortingState>) => void;
|
|
2219
|
-
manualFiltering?: boolean;
|
|
2220
|
-
enableFiltering?: boolean;
|
|
2221
|
-
enableColumnFilters?: boolean;
|
|
2222
|
-
enableGlobalFilter?: boolean;
|
|
2223
|
-
globalFilterFn?: FilterFn<TData>;
|
|
2224
|
-
onColumnFiltersChange?: (updater: Updater<ColumnFiltersState>) => void;
|
|
2225
|
-
onGlobalFilterChange?: (updater: Updater<unknown>) => void;
|
|
2226
|
-
manualPagination?: boolean;
|
|
2227
|
-
pageCount?: number;
|
|
2228
|
-
autoResetPageIndex?: boolean;
|
|
2229
|
-
onPaginationChange?: (updater: Updater<PaginationState>) => void;
|
|
2230
|
-
enableRowSelection?: boolean | ((row: Row<TData>) => boolean);
|
|
2231
|
-
enableMultiRowSelection?: boolean | ((row: Row<TData>) => boolean);
|
|
2232
|
-
enableSubRowSelection?: boolean | ((row: Row<TData>) => boolean);
|
|
2233
|
-
onRowSelectionChange?: (updater: Updater<RowSelectionState>) => void;
|
|
2234
|
-
enableHiding?: boolean;
|
|
2235
|
-
onColumnVisibilityChange?: (updater: Updater<ColumnVisibilityState>) => void;
|
|
2236
|
-
onColumnOrderChange?: (updater: Updater<ColumnOrderState>) => void;
|
|
2237
|
-
enablePinning?: boolean;
|
|
2238
|
-
onColumnPinningChange?: (updater: Updater<ColumnPinningState>) => void;
|
|
2239
|
-
enableColumnResizing?: boolean;
|
|
2240
|
-
columnResizeMode?: "onChange" | "onEnd";
|
|
2241
|
-
columnResizeDirection?: "ltr" | "rtl";
|
|
2242
|
-
onColumnSizingChange?: (updater: Updater<ColumnSizingState>) => void;
|
|
2243
|
-
onColumnSizingInfoChange?: (updater: Updater<ColumnSizingInfoState>) => void;
|
|
2244
|
-
manualGrouping?: boolean;
|
|
2245
|
-
enableGrouping?: boolean;
|
|
2246
|
-
onGroupingChange?: (updater: Updater<GroupingState>) => void;
|
|
2247
|
-
manualExpanding?: boolean;
|
|
2248
|
-
enableExpanding?: boolean;
|
|
2249
|
-
getSubRows?: (row: TData, index: number) => TData[] | undefined;
|
|
2250
|
-
getIsRowExpanded?: (row: Row<TData>) => boolean;
|
|
2251
|
-
onExpandedChange?: (updater: Updater<ExpandedState>) => void;
|
|
2252
|
-
paginateExpandedRows?: boolean;
|
|
2253
|
-
enableRowPinning?: boolean | ((row: Row<TData>) => boolean);
|
|
2254
|
-
keepPinnedRows?: boolean;
|
|
2255
|
-
onRowPinningChange?: (updater: Updater<Record<string, "top" | "bottom">>) => void;
|
|
2256
|
-
}
|
|
2257
|
-
interface TableInstance<TData> {
|
|
2258
|
-
options: TableOptions<TData>;
|
|
2259
|
-
getState: () => TableState;
|
|
2260
|
-
setState: (updater: Updater<TableState>) => void;
|
|
2261
|
-
reset: () => void;
|
|
2262
|
-
getAllColumns: () => Column<TData>[];
|
|
2263
|
-
getAllFlatColumns: () => Column<TData>[];
|
|
2264
|
-
getAllLeafColumns: () => Column<TData>[];
|
|
2265
|
-
getColumn: (id: string) => Column<TData> | undefined;
|
|
2266
|
-
getHeaderGroups: () => HeaderGroup<TData>[];
|
|
2267
|
-
getLeftHeaderGroups: () => HeaderGroup<TData>[];
|
|
2268
|
-
getCenterHeaderGroups: () => HeaderGroup<TData>[];
|
|
2269
|
-
getRightHeaderGroups: () => HeaderGroup<TData>[];
|
|
2270
|
-
getFooterGroups: () => HeaderGroup<TData>[];
|
|
2271
|
-
getCoreRowModel: () => RowModel<TData>;
|
|
2272
|
-
getRowModel: () => RowModel<TData>;
|
|
2273
|
-
getPreFilteredRowModel: () => RowModel<TData>;
|
|
2274
|
-
getFilteredRowModel: () => RowModel<TData>;
|
|
2275
|
-
getPreSortedRowModel: () => RowModel<TData>;
|
|
2276
|
-
getSortedRowModel: () => RowModel<TData>;
|
|
2277
|
-
getGroupedRowModel: () => RowModel<TData>;
|
|
2278
|
-
getExpandedRowModel: () => RowModel<TData>;
|
|
2279
|
-
getPrePaginationRowModel: () => RowModel<TData>;
|
|
2280
|
-
getPaginationRowModel: () => RowModel<TData>;
|
|
2281
|
-
getSelectedRowModel: () => RowModel<TData>;
|
|
2282
|
-
getRow: (id: string) => Row<TData>;
|
|
2283
|
-
setSorting: (updater: Updater<SortingState>) => void;
|
|
2284
|
-
resetSorting: (defaultState?: boolean) => void;
|
|
2285
|
-
setColumnFilters: (updater: Updater<ColumnFiltersState>) => void;
|
|
2286
|
-
resetColumnFilters: (defaultState?: boolean) => void;
|
|
2287
|
-
setGlobalFilter: (value: unknown) => void;
|
|
2288
|
-
resetGlobalFilter: (defaultState?: boolean) => void;
|
|
2289
|
-
setPageIndex: (updater: Updater<number>) => void;
|
|
2290
|
-
resetPageIndex: (defaultState?: boolean) => void;
|
|
2291
|
-
setPageSize: (updater: Updater<number>) => void;
|
|
2292
|
-
resetPageSize: (defaultState?: boolean) => void;
|
|
2293
|
-
getPageCount: () => number;
|
|
2294
|
-
getCanPreviousPage: () => boolean;
|
|
2295
|
-
getCanNextPage: () => boolean;
|
|
2296
|
-
previousPage: () => void;
|
|
2297
|
-
nextPage: () => void;
|
|
2298
|
-
firstPage: () => void;
|
|
2299
|
-
lastPage: () => void;
|
|
2300
|
-
setRowSelection: (updater: Updater<RowSelectionState>) => void;
|
|
2301
|
-
resetRowSelection: (defaultState?: boolean) => void;
|
|
2302
|
-
toggleAllRowsSelected: (value?: boolean) => void;
|
|
2303
|
-
toggleAllPageRowsSelected: (value?: boolean) => void;
|
|
2304
|
-
getIsAllRowsSelected: () => boolean;
|
|
2305
|
-
getIsAllPageRowsSelected: () => boolean;
|
|
2306
|
-
getIsSomeRowsSelected: () => boolean;
|
|
2307
|
-
getIsSomePageRowsSelected: () => boolean;
|
|
2308
|
-
getToggleAllRowsSelectedHandler: () => (e: unknown) => void;
|
|
2309
|
-
getToggleAllPageRowsSelectedHandler: () => (e: unknown) => void;
|
|
2310
|
-
setColumnVisibility: (updater: Updater<ColumnVisibilityState>) => void;
|
|
2311
|
-
resetColumnVisibility: (defaultState?: boolean) => void;
|
|
2312
|
-
toggleAllColumnsVisible: (value?: boolean) => void;
|
|
2313
|
-
getIsAllColumnsVisible: () => boolean;
|
|
2314
|
-
getIsSomeColumnsVisible: () => boolean;
|
|
2315
|
-
getToggleAllColumnsVisibilityHandler: () => (e: unknown) => void;
|
|
2316
|
-
getVisibleFlatColumns: () => Column<TData>[];
|
|
2317
|
-
getVisibleLeafColumns: () => Column<TData>[];
|
|
2318
|
-
setColumnOrder: (updater: Updater<ColumnOrderState>) => void;
|
|
2319
|
-
resetColumnOrder: (defaultState?: boolean) => void;
|
|
2320
|
-
setColumnPinning: (updater: Updater<ColumnPinningState>) => void;
|
|
2321
|
-
resetColumnPinning: (defaultState?: boolean) => void;
|
|
2322
|
-
getLeftFlatColumns: () => Column<TData>[];
|
|
2323
|
-
getRightFlatColumns: () => Column<TData>[];
|
|
2324
|
-
getCenterFlatColumns: () => Column<TData>[];
|
|
2325
|
-
getLeftLeafColumns: () => Column<TData>[];
|
|
2326
|
-
getRightLeafColumns: () => Column<TData>[];
|
|
2327
|
-
getCenterLeafColumns: () => Column<TData>[];
|
|
2328
|
-
setColumnSizing: (updater: Updater<ColumnSizingState>) => void;
|
|
2329
|
-
setColumnSizingInfo: (updater: Updater<ColumnSizingInfoState>) => void;
|
|
2330
|
-
resetColumnSizing: (defaultState?: boolean) => void;
|
|
2331
|
-
setGrouping: (updater: Updater<GroupingState>) => void;
|
|
2332
|
-
resetGrouping: (defaultState?: boolean) => void;
|
|
2333
|
-
setExpanded: (updater: Updater<ExpandedState>) => void;
|
|
2334
|
-
resetExpanded: (defaultState?: boolean) => void;
|
|
2335
|
-
toggleAllRowsExpanded: (expanded?: boolean) => void;
|
|
2336
|
-
getIsAllRowsExpanded: () => boolean;
|
|
2337
|
-
getIsSomeRowsExpanded: () => boolean;
|
|
2338
|
-
getCanSomeRowsExpand: () => boolean;
|
|
2339
|
-
getExpandedDepth: () => number;
|
|
2340
|
-
}
|
|
2341
|
-
|
|
2342
|
-
/**
|
|
2343
|
-
* table/row-models.ts
|
|
2344
|
-
*
|
|
2345
|
-
* Pure row model pipeline functions. Each stage transforms data
|
|
2346
|
-
* into a RowModel — no side effects, no external dependencies.
|
|
2347
|
-
*/
|
|
2348
|
-
|
|
2349
|
-
declare function createRow<TData>(original: TData, index: number, columns: Column<TData>[], table: TableInstance<TData>, depth?: number, parentId?: string, subRows?: Row<TData>[]): Row<TData>;
|
|
2350
|
-
declare function getCoreRowModel<TData>(data: TData[], columns: Column<TData>[], table: TableInstance<TData>): RowModel<TData>;
|
|
2351
|
-
declare function getFilteredRowModel<TData>(rowModel: RowModel<TData>, columnFilters: ColumnFiltersState, globalFilter: unknown, columns: Column<TData>[], globalFilterFn?: FilterFn<TData>): RowModel<TData>;
|
|
2352
|
-
declare function getSortedRowModel<TData>(rowModel: RowModel<TData>, sorting: SortingState, columns: Column<TData>[]): RowModel<TData>;
|
|
2353
|
-
declare function getGroupedRowModel<TData>(rowModel: RowModel<TData>, grouping: GroupingState, columns: Column<TData>[], table: TableInstance<TData>): RowModel<TData>;
|
|
2354
|
-
declare function getExpandedRowModel<TData>(rowModel: RowModel<TData>, expanded: ExpandedState): RowModel<TData>;
|
|
2355
|
-
declare function getPaginatedRowModel<TData>(rowModel: RowModel<TData>, pagination: PaginationState): RowModel<TData>;
|
|
2356
|
-
declare function getSelectedRowModel<TData>(rowModel: RowModel<TData>, selection: Record<string, boolean>): RowModel<TData>;
|
|
2357
|
-
|
|
2358
|
-
/**
|
|
2359
|
-
* table/faceting.ts
|
|
2360
|
-
*
|
|
2361
|
-
* Column faceting utilities — compute unique values, counts,
|
|
2362
|
-
* and min/max for filter UI controls.
|
|
2363
|
-
*/
|
|
2364
|
-
|
|
2365
|
-
/**
|
|
2366
|
-
* Compute unique values and their counts for a given column.
|
|
2367
|
-
* Useful for rendering filter dropdown options with hit counts.
|
|
2368
|
-
*/
|
|
2369
|
-
declare function getFacetedUniqueValues<TData>(rowModel: RowModel<TData>, columnId: string): Map<unknown, number>;
|
|
2370
|
-
/**
|
|
2371
|
-
* Compute min and max numeric values for a given column.
|
|
2372
|
-
* Returns [min, max] or undefined if no numeric values exist.
|
|
2373
|
-
*/
|
|
2374
|
-
declare function getFacetedMinMaxValues<TData>(rowModel: RowModel<TData>, columnId: string): [number, number] | undefined;
|
|
2375
|
-
/**
|
|
2376
|
-
* Get a filtered row model scoped to a single column's facet.
|
|
2377
|
-
* Returns a row model that excludes the given column's own filter,
|
|
2378
|
-
* so the facet counts reflect what would be available if that
|
|
2379
|
-
* specific filter were removed.
|
|
2380
|
-
*/
|
|
2381
|
-
declare function getFacetedRowModel<TData>(preFilteredRowModel: RowModel<TData>, columnId: string, allFilteredRowModel: RowModel<TData>): RowModel<TData>;
|
|
2382
|
-
|
|
2383
|
-
export { type AccessorFn, type AdapterStatus, type AgUiStateDeltaEvent, type AgUiStateMapping, type AgUiStateSnapshotEvent, type AggregationFn, type ApplyAgUiOptions, type BelongsToRelation, type CascadeContext, type Cell, type CellContext, type CellRenderer, type ChangeEvent, type ChangeOp, type ChangeOperation, type ChangeSet, type ChannelConfig, type Column, type ColumnDef, type ColumnFiltersState, type ColumnMeta, type ColumnOrderState, type ColumnPinningState, type ColumnSizingInfoState, type ColumnSizingState, type ColumnVisibilityState, type CreateFlintAdapterOptions, type CreatePGlitePersistenceAdapterOptions, type CreateTauriSqlPersistenceAdapterOptions, type DevtoolsEvent, type DevtoolsEventBus, type DevtoolsEventBusOptions, type DevtoolsSourceFn, type ElectricAdapterOptions, type ElectricTableConfig, type EngineOptions, type EntityChange, EntityId, type EntityJsonSchemaConfig, type EntityQueryOptions, type EntitySchema, EntitySnapshot, EntitySyncMetadata, type EntityTransport, EntityType, type ExpandedState, type FilterFn, FilterSpec, type FlintCheckpointStore, type FlintClientLike, type FlintEntityEvent, type FlintEntityQuery, type FlintEntityRecord, type GetEntityJsonSchemaOptions, type GraphActionEvent, type GraphActionOptions, type GraphActionRecord$1 as GraphActionRecord, type GraphEffectEvent, type GraphEffectHandle, type GraphEffectOptions, type GraphIncludeMap, type GraphIncludeRelation, type GraphPersistenceAdapter, type GraphQueryOptions, type GraphSnapshotExportOptions, type GraphSnapshotPayload, type GraphSnapshotWithSchemasOptions, GraphStore$1 as GraphStore, type GraphSyncStatus, type GraphToolContext, type GraphTransaction, type GroupingState, type HasManyRelation, type Header, type HeaderContext, type HeaderGroup, type HeaderRenderer, IncrementalView, type IncrementalViewOptions, type JsonPatchOp, type JsonSchemaObject, type ListFetchParams, type ListQuery, type ListQueryOptions, type ListResponse, type ListResult, type LocalFirstGraphRuntime, type LoroModuleLoader, type MakeRestTransportOptions, type ManagerOptions, type ManyToManyRelation, type MergeContext, type MergeStrategy, type PGlitePersistenceClient, type PaginationState, type ColumnDef as PureColumnDef, type ColumnMeta as PureColumnMeta, QueryKey, type RealtimeAdapter, RealtimeManager, type RegisterEntityFromSqlOptions, type RegisteredStore, type RelationDescriptor, type ReplayRetryPolicy, type Row, type RowModel, type RowSelectionState, type SchemaGraphToolContext, SortSpec, type SortingFn, type SortingState, type StartLocalFirstGraphOptions, type SubscriptionConfig, type SupabaseAdapterOptions, type SupabaseLike, type SupabaseQueryBuilderLike, type SurrealCheckpointStore, type SurrealLike, type SurrealLiveAction, type SurrealLiveAdapterOptions, type SurrealTableConfig, type SyncAdapter, SyncOrigin, type TableInstance, type TableOptions, type TableState, type TauriSqlClient, type TenantClaim, type TenantScopedAdapterOptions, type TenantScopedTableConfig, type TimeTravelSnapshot, type TimeTravelState, type UnsubscribeFn, type Updater, type ViewMode, type WebSocketAdapterOptions, __resetActiveGraphStore, __resetEntityTransports, __resetStoreRegistry, applyAgUiDelta, applyAgUiSnapshot, applyJsonPatch, applyView, attachGlobalListeners, buildTenantWhere, cascadeInvalidation, checkCompleteness, collectDirtyPaths, compareEntities, configureEngine, configureTimeTravel, createConvexAdapter, createDevtoolsEventBus, createElectricAdapter, createFlintAdapter, createGraphAction, createGraphEffect, createGraphQLSubscriptionAdapter, createGraphTool, createGraphTransaction, createLoroMergeStrategy, createPGlitePersistenceAdapter, createRow, createSchemaGraphTool, createSupabaseRealtimeAdapter, createSurrealLiveAdapter, createTauriSqlPersistenceAdapter, createTenantScopedElectricAdapter, createWebSocketAdapter, dedupe, escapeHtml, exportGraphSnapshot, exportGraphSnapshotWithSchemas, fetchEntity, fetchList, findInsertionIndex, getActiveSubscriberCount, getCoreRowModel, getRealtimeManager as getElectricRealtimeManager, getEngineOptions, getEntityJsonSchema, getEntityTransport, getExpandedRowModel, getFacetedMinMaxValues, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getGraphSyncStatus, getGroupedRowModel, getMergeStrategy, getPaginatedRowModel, getRealtimeManager, getRegisteredEntityTypes, getRegisteredStores, getSchema, getSelectedRowModel, getSortedRowModel, getTimeTravelState, getValueAtPath, graphStore, graphSyncStatusStore, hasMergeStrategy, humanizeFieldName, hydrateGraphFromStorage, inferSchemaFieldType, lwwStrategy, makeRestTransport, matchesFilter, matchesSearch, parseCreateTable, persistGraphToStorage, prepareGraphStoreScope, publishFlintMutation, queryOnce, readRelations, recordGraphSnapshot, registerEntityFromSql, registerEntityJsonSchema, registerEntityTransport, registerMergeStrategy, registerRuntimeSchema, registerSchema, registerStore, registerSubscriber, registryKey, renderMarkdownToHtml, replayActionWithRetry, resetRealtimeManager, resolveActiveGraphStore, restoreGraphSnapshot, restoreGraphSnapshotBySeq, runWithGraphStore, selectGraph, serializeKey, setActiveGraphStore, setDefaultMergeStrategy, setValueAtPath, sqlTypeToJsonSchema, startGarbageCollector, startLocalFirstGraph, stepTimeTravel, stopGarbageCollector, subscribeDevtoolsEvent, subscribeSubscriberStats, subscribeTimeTravel, toPrismaOrderBy, toPrismaWhere, unregisterSubscriber, useGraphStore };
|