@prometheus-ags/entity-graph-core 3.2.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 };