@typicalday/firegraph 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/backend.cjs +222 -0
  2. package/dist/backend.cjs.map +1 -0
  3. package/dist/backend.d.cts +121 -0
  4. package/dist/backend.d.ts +121 -0
  5. package/dist/backend.js +136 -0
  6. package/dist/backend.js.map +1 -0
  7. package/dist/chunk-5753Y42M.js +118 -0
  8. package/dist/chunk-5753Y42M.js.map +1 -0
  9. package/dist/chunk-EVUM6ORB.js +1575 -0
  10. package/dist/chunk-EVUM6ORB.js.map +1 -0
  11. package/dist/chunk-GLOVWKQH.js +94 -0
  12. package/dist/chunk-GLOVWKQH.js.map +1 -0
  13. package/dist/{chunk-KFA7G37W.js → chunk-SU4FNLC3.js} +32 -30
  14. package/dist/chunk-SU4FNLC3.js.map +1 -0
  15. package/dist/chunk-SZ6W4VAS.js +701 -0
  16. package/dist/chunk-SZ6W4VAS.js.map +1 -0
  17. package/dist/chunk-TYYPRVIE.js +57 -0
  18. package/dist/chunk-TYYPRVIE.js.map +1 -0
  19. package/dist/codegen/index.d.cts +25 -1
  20. package/dist/codegen/index.d.ts +25 -1
  21. package/dist/d1.cjs +2421 -0
  22. package/dist/d1.cjs.map +1 -0
  23. package/dist/d1.d.cts +54 -0
  24. package/dist/d1.d.ts +54 -0
  25. package/dist/d1.js +76 -0
  26. package/dist/d1.js.map +1 -0
  27. package/dist/do-sqlite.cjs +2424 -0
  28. package/dist/do-sqlite.cjs.map +1 -0
  29. package/dist/do-sqlite.d.cts +41 -0
  30. package/dist/do-sqlite.d.ts +41 -0
  31. package/dist/do-sqlite.js +79 -0
  32. package/dist/do-sqlite.js.map +1 -0
  33. package/dist/editor/client/assets/index-Bq2bfzeY.js +411 -0
  34. package/dist/editor/client/index.html +1 -1
  35. package/dist/editor/server/index.mjs +6524 -6355
  36. package/dist/index.cjs +2881 -2714
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +259 -275
  39. package/dist/index.d.ts +259 -275
  40. package/dist/index.js +728 -2304
  41. package/dist/index.js.map +1 -1
  42. package/dist/query-client/index.cjs +30 -28
  43. package/dist/query-client/index.cjs.map +1 -1
  44. package/dist/query-client/index.d.cts +2 -2
  45. package/dist/query-client/index.d.ts +2 -2
  46. package/dist/query-client/index.js +1 -1
  47. package/dist/react.cjs +0 -1
  48. package/dist/react.cjs.map +1 -1
  49. package/dist/react.js +0 -1
  50. package/dist/react.js.map +1 -1
  51. package/dist/scope-path-BtajqNK5.d.ts +234 -0
  52. package/dist/scope-path-D2mNENJ-.d.cts +234 -0
  53. package/dist/serialization-ZZ7RSDRX.js +13 -0
  54. package/dist/serialization-ZZ7RSDRX.js.map +1 -0
  55. package/dist/svelte.cjs +0 -2
  56. package/dist/svelte.cjs.map +1 -1
  57. package/dist/svelte.js +0 -2
  58. package/dist/svelte.js.map +1 -1
  59. package/dist/{index-B9aodfYD.d.ts → types-DfWVTsMn.d.cts} +28 -26
  60. package/dist/{index-B9aodfYD.d.cts → types-DfWVTsMn.d.ts} +28 -26
  61. package/package.json +35 -1
  62. package/dist/chunk-KFA7G37W.js.map +0 -1
  63. package/dist/editor/client/assets/index-tyFcX6qG.js +0 -411
package/dist/index.d.ts CHANGED
@@ -1,136 +1,66 @@
1
+ import { S as StorageBackend, F as FiregraphError } from './scope-path-BtajqNK5.js';
2
+ export { C as CrossBackendTransactionError, D as DynamicRegistryError, E as EdgeNotFoundError, I as InvalidQueryError, M as MigrationError, N as NodeNotFoundError, Q as QuerySafetyError, R as RegistryScopeError, c as RegistryViolationError, a as StorageScopeSegment, d as TraversalError, V as ValidationError, b as appendStorageScope, i as isAncestorScopeUid, p as parseStorageScope, r as resolveAncestorScope } from './scope-path-BtajqNK5.js';
3
+ import { G as GraphClientOptions, b as GraphClient, a as DynamicGraphClient, c as DiscoveryResult, R as RegistryEntry, d as GraphRegistry, e as GraphReader, M as MigrationExecutor, D as DynamicRegistryConfig, S as StoredGraphRecord, f as MigrationWriteBack, g as MigrationStep, F as FindEdgesParams, Q as QueryPlan, h as FindNodesParams, i as QueryFilter, j as GraphRecord, k as MigrationFn, l as StoredMigrationStep, T as TraversalBuilder } from './types-DfWVTsMn.js';
4
+ export { B as BulkBatchError, m as BulkOptions, n as BulkProgress, o as BulkResult, C as CascadeResult, p as DefineTypeOptions, q as DiscoveredEntity, E as EdgeTopology, r as EdgeTypeData, s as FiregraphConfig, t as GraphBatch, u as GraphTransaction, v as GraphWriter, H as HopDefinition, w as HopResult, N as NodeTypeData, x as QueryMode, y as QueryOptions, z as ScanProtection, A as TraversalOptions, I as TraversalResult, V as ViewContext, J as ViewDefaultsConfig, K as ViewResolverConfig, W as WhereClause, L as defineConfig, O as resolveView } from './types-DfWVTsMn.js';
5
+ export { CodegenOptions, generateTypes } from './codegen/index.js';
1
6
  import { Firestore } from '@google-cloud/firestore';
2
- import { G as GraphClientOptions, D as DynamicRegistryConfig, a as DynamicGraphClient, b as GraphClient, c as GraphRegistry, R as RegistryEntry, d as DiscoveryResult, e as GraphReader, M as MigrationExecutor, f as GraphRecord, F as FindEdgesParams, Q as QueryPlan, g as FindNodesParams, T as TraversalBuilder, h as MigrationFn, S as StoredMigrationStep, i as MigrationStep, j as StoredGraphRecord, k as MigrationWriteBack, l as QueryFilter } from './index-B9aodfYD.js';
3
- export { B as BulkBatchError, m as BulkOptions, n as BulkProgress, o as BulkResult, C as CascadeResult, p as CodegenOptions, q as DefineTypeOptions, r as DiscoveredEntity, E as EdgeTopology, s as EdgeTypeData, t as FiregraphConfig, u as GraphBatch, v as GraphTransaction, w as GraphWriter, H as HopDefinition, x as HopResult, N as NodeTypeData, y as QueryMode, z as QueryOptions, A as ScanProtection, I as TraversalOptions, J as TraversalResult, V as ViewContext, K as ViewDefaultsConfig, L as ViewResolverConfig, W as WhereClause, O as defineConfig, P as generateTypes, U as resolveView } from './index-B9aodfYD.js';
4
- export { E as EntityViewConfig, a as EntityViewMeta, V as ViewComponentClass, b as ViewMeta, c as ViewRegistry, d as ViewRegistryInput, e as defineViews } from './views-DL60k0cf.js';
5
7
  export { Q as QueryClient, a as QueryClientError, b as QueryClientErrorCode, c as QueryClientOptions } from './client-Bk2Cm6xv.js';
8
+ export { E as EntityViewConfig, a as EntityViewMeta, V as ViewComponentClass, b as ViewMeta, c as ViewRegistry, d as ViewRegistryInput, e as defineViews } from './views-DL60k0cf.js';
6
9
 
7
- declare function createGraphClient(db: Firestore, collectionPath: string, options: GraphClientOptions & {
8
- registryMode: DynamicRegistryConfig;
9
- }): DynamicGraphClient;
10
- declare function createGraphClient(db: Firestore, collectionPath: string, options?: GraphClientOptions): GraphClient;
11
-
12
- /**
13
- * Build a registry from either explicit entries or a DiscoveryResult.
14
- *
15
- * @example
16
- * ```ts
17
- * // From explicit entries (programmatic)
18
- * const registry = createRegistry([
19
- * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },
20
- * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },
21
- * ]);
22
- *
23
- * // From discovery result (folder convention)
24
- * const discovered = await discoverEntities('./entities');
25
- * const registry = createRegistry(discovered);
26
- * ```
27
- */
28
- declare function createRegistry(input: RegistryEntry[] | DiscoveryResult): GraphRegistry;
29
10
  /**
30
- * Create a merged registry where `base` entries take priority and `extension`
31
- * entries fill in gaps. Lookups and validation check `base` first; only if the
32
- * triple is not found there does the merged registry fall through to
33
- * `extension`.
11
+ * Create a `GraphClient` backed by an arbitrary `StorageBackend`.
34
12
  *
35
- * The `entries()` method returns a deduplicated list (base wins on collision).
36
- * The `lookupByAxbType()` method merges results from both registries,
37
- * deduplicating by triple key with base entries winning.
13
+ * Used by backend-specific factories (D1, DO-SQLite, etc.) most callers
14
+ * should use the higher-level `createGraphClient(firestore, ...)` overload
15
+ * below or import the equivalent from `firegraph/d1` / `firegraph/do-sqlite`.
38
16
  */
39
- declare function createMergedRegistry(base: GraphRegistry, extension: GraphRegistry): GraphRegistry;
17
+ declare function createGraphClientFromBackend(backend: StorageBackend, options?: GraphClientOptions, metaBackend?: StorageBackend): GraphClient | DynamicGraphClient;
40
18
 
41
- /** The aType used for node type definition meta-nodes. */
42
- declare const META_NODE_TYPE = "nodeType";
43
- /** The aType used for edge type definition meta-nodes. */
44
- declare const META_EDGE_TYPE = "edgeType";
45
- /** JSON Schema for the `data` payload of a `nodeType` meta-node. */
46
- declare const NODE_TYPE_SCHEMA: object;
47
- /** JSON Schema for the `data` payload of an `edgeType` meta-node. */
48
- declare const EDGE_TYPE_SCHEMA: object;
49
- /** Registry entries for the two meta-types (always present). */
50
- declare const BOOTSTRAP_ENTRIES: readonly RegistryEntry[];
51
- /**
52
- * Build the bootstrap registry that validates meta-type writes.
53
- * This is always available, even before any dynamic types are loaded.
54
- */
55
- declare function createBootstrapRegistry(): GraphRegistry;
56
19
  /**
57
- * Generate a deterministic UID for a meta-type definition.
58
- * This ensures that defining the same type name always targets the same
59
- * Firestore document, enabling upsert semantics.
20
+ * Cross-graph edge resolution utilities.
60
21
  *
61
- * Format: 21-char base64url substring of SHA-256(`metaType:name`).
22
+ * Provides path-scanning resolution for determining whether an edge's source
23
+ * (aUid) is an ancestor node by checking if the UID appears in the Firestore
24
+ * collection path.
25
+ *
26
+ * Firestore paths have a rigid alternating structure:
27
+ * collection / docId / collection / docId / collection
28
+ *
29
+ * Given a path like `graph/A/workspace/B/context`, segments at even indices
30
+ * are collection names and odd indices are document IDs. When we find a UID
31
+ * at an odd index, the collection containing that document is the path up to
32
+ * (and including) the preceding even-index segment.
62
33
  */
63
- declare function generateDeterministicUid(metaType: string, name: string): string;
64
34
  /**
65
- * Read meta-type nodes from the graph and compile them into a GraphRegistry.
35
+ * Parse a Firestore collection path and determine the collection path
36
+ * where a given UID's document lives, if that UID is an ancestor in the path.
66
37
  *
67
- * The returned registry includes both the dynamic entries AND the bootstrap
68
- * meta-type entries, so meta-type writes remain validateable after a reload.
38
+ * @param collectionPath - The full Firestore collection path of the current client
39
+ * @param uid - The UID to search for in the path
40
+ * @returns The collection path containing the UID, or `null` if not found in the path
69
41
  *
70
- * @param reader - A GraphReader pointed at the collection containing meta-nodes.
71
- * @param executor - Optional custom executor for compiling stored migration source strings.
42
+ * @example
43
+ * ```ts
44
+ * // Path: graph/A/workspace/B/context
45
+ * resolveAncestorCollection('graph/A/workspace/B/context', 'A')
46
+ * // → 'graph'
47
+ *
48
+ * resolveAncestorCollection('graph/A/workspace/B/context', 'B')
49
+ * // → 'graph/A/workspace'
50
+ *
51
+ * resolveAncestorCollection('graph/A/workspace/B/context', 'unknown')
52
+ * // → null
53
+ * ```
72
54
  */
73
- declare function createRegistryFromGraph(reader: GraphReader, executor?: MigrationExecutor): Promise<GraphRegistry>;
74
-
75
- declare function generateId(): string;
76
-
77
- declare function computeNodeDocId(uid: string): string;
78
- declare function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string;
79
-
80
- declare function buildNodeRecord(aType: string, uid: string, data: Record<string, unknown>): GraphRecord;
81
- declare function buildEdgeRecord(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): GraphRecord;
82
-
83
- declare function buildEdgeQueryPlan(params: FindEdgesParams): QueryPlan;
84
- declare function buildNodeQueryPlan(params: FindNodesParams): QueryPlan;
85
-
55
+ declare function resolveAncestorCollection(collectionPath: string, uid: string): string | null;
86
56
  /**
87
- * Create a traversal builder for multi-hop graph traversal.
88
- *
89
- * Accepts either a `GraphReader` (backwards compatible) or a `GraphClient`.
90
- * When a `GraphClient` is provided, cross-graph traversal via `targetGraph`
91
- * is supported — the traversal can follow edges into subgraphs.
57
+ * Check whether a UID belongs to an ancestor node by scanning the collection path.
92
58
  *
93
- * @param reader - A `GraphClient` or `GraphReader` to execute queries against
94
- * @param startUid - UID of the starting node
95
- * @param registry - Optional registry for automatic `targetGraph` resolution
59
+ * @param collectionPath - The full Firestore collection path of the current client
60
+ * @param uid - The UID to check
61
+ * @returns `true` if the UID appears as a document segment in the path
96
62
  */
97
- declare function createTraversal(reader: GraphClient | GraphReader, startUid: string, registry?: GraphRegistry): TraversalBuilder;
98
-
99
- declare class FiregraphError extends Error {
100
- readonly code: string;
101
- constructor(message: string, code: string);
102
- }
103
- declare class NodeNotFoundError extends FiregraphError {
104
- constructor(uid: string);
105
- }
106
- declare class EdgeNotFoundError extends FiregraphError {
107
- constructor(aUid: string, axbType: string, bUid: string);
108
- }
109
- declare class ValidationError extends FiregraphError {
110
- readonly details?: unknown | undefined;
111
- constructor(message: string, details?: unknown | undefined);
112
- }
113
- declare class RegistryViolationError extends FiregraphError {
114
- constructor(aType: string, axbType: string, bType: string);
115
- }
116
- declare class InvalidQueryError extends FiregraphError {
117
- constructor(message: string);
118
- }
119
- declare class TraversalError extends FiregraphError {
120
- constructor(message: string);
121
- }
122
- declare class DynamicRegistryError extends FiregraphError {
123
- constructor(message: string);
124
- }
125
- declare class QuerySafetyError extends FiregraphError {
126
- constructor(message: string);
127
- }
128
- declare class RegistryScopeError extends FiregraphError {
129
- constructor(aType: string, axbType: string, bType: string, scopePath: string, allowedIn: string[]);
130
- }
131
- declare class MigrationError extends FiregraphError {
132
- constructor(message: string);
133
- }
63
+ declare function isAncestorUid(collectionPath: string, uid: string): boolean;
134
64
 
135
65
  /**
136
66
  * Entity Discovery — convention-based auto-discovery of entities from
@@ -182,82 +112,97 @@ interface DiscoverResult {
182
112
  */
183
113
  declare function discoverEntities(entitiesDir: string): DiscoverResult;
184
114
 
115
+ declare function computeNodeDocId(uid: string): string;
116
+ declare function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string;
117
+
118
+ /** The aType used for node type definition meta-nodes. */
119
+ declare const META_NODE_TYPE = "nodeType";
120
+ /** The aType used for edge type definition meta-nodes. */
121
+ declare const META_EDGE_TYPE = "edgeType";
122
+ /** JSON Schema for the `data` payload of a `nodeType` meta-node. */
123
+ declare const NODE_TYPE_SCHEMA: object;
124
+ /** JSON Schema for the `data` payload of an `edgeType` meta-node. */
125
+ declare const EDGE_TYPE_SCHEMA: object;
126
+ /** Registry entries for the two meta-types (always present). */
127
+ declare const BOOTSTRAP_ENTRIES: readonly RegistryEntry[];
185
128
  /**
186
- * Scope path matching for subgraph-level registry constraints.
187
- *
188
- * Scope paths are slash-separated names derived from the chain of
189
- * `subgraph()` calls (e.g., `'agents'`, `'agents/memories'`).
190
- * The root graph has an empty scope path (`''`).
191
- *
192
- * Patterns:
193
- * - `'root'` — matches only the root graph (empty scope path)
194
- * - `'agents'` — matches exactly `'agents'`
195
- * - `'agents/memories'` — matches exactly `'agents/memories'`
196
- * - `'*​/agents'` — `*` matches one segment: `'foo/agents'` but not `'a/b/agents'`
197
- * - `'**​/memories'` — `**` matches zero or more segments
198
- * - `'**'` — matches everything including root
129
+ * Build the bootstrap registry that validates meta-type writes.
130
+ * This is always available, even before any dynamic types are loaded.
199
131
  */
132
+ declare function createBootstrapRegistry(): GraphRegistry;
200
133
  /**
201
- * Test whether a scope path matches a single pattern.
134
+ * Generate a deterministic UID for a meta-type definition.
135
+ * This ensures that defining the same type name always targets the same
136
+ * Firestore document, enabling upsert semantics.
202
137
  *
203
- * @param scopePath - The current scope path (empty string for root)
204
- * @param pattern - The pattern to match against
138
+ * Format: 21-char base64url substring of SHA-256(`metaType:name`).
205
139
  */
206
- declare function matchScope(scopePath: string, pattern: string): boolean;
140
+ declare function generateDeterministicUid(metaType: string, name: string): string;
207
141
  /**
208
- * Test whether a scope path matches any pattern in a list.
209
- * Returns `true` if the list is empty or undefined (allowed everywhere).
142
+ * Read meta-type nodes from the graph and compile them into a GraphRegistry.
210
143
  *
211
- * @param scopePath - The current scope path (empty string for root)
212
- * @param patterns - Array of patterns to match against
144
+ * The returned registry includes both the dynamic entries AND the bootstrap
145
+ * meta-type entries, so meta-type writes remain validateable after a reload.
146
+ *
147
+ * @param reader - A GraphReader pointed at the collection containing meta-nodes.
148
+ * @param executor - Optional custom executor for compiling stored migration source strings.
213
149
  */
214
- declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
150
+ declare function createRegistryFromGraph(reader: GraphReader, executor?: MigrationExecutor): Promise<GraphRegistry>;
215
151
 
216
152
  /**
217
- * Cross-graph edge resolution utilities.
218
- *
219
- * Provides path-scanning resolution for determining whether an edge's source
220
- * (aUid) is an ancestor node by checking if the UID appears in the Firestore
221
- * collection path.
222
- *
223
- * Firestore paths have a rigid alternating structure:
224
- * collection / docId / collection / docId / collection
153
+ * Firestore-specific client factory.
225
154
  *
226
- * Given a path like `graph/A/workspace/B/context`, segments at even indices
227
- * are collection names and odd indices are document IDs. When we find a UID
228
- * at an odd index, the collection containing that document is the path up to
229
- * (and including) the preceding even-index segment.
155
+ * Kept in its own module so that bundlers don't pull
156
+ * `@google-cloud/firestore` into SQLite-only entry points
157
+ * (`firegraph/d1`, `firegraph/do-sqlite`).
230
158
  */
159
+
160
+ declare function createGraphClient(db: Firestore, collectionPath: string, options: GraphClientOptions & {
161
+ registryMode: DynamicRegistryConfig;
162
+ }): DynamicGraphClient;
163
+ declare function createGraphClient(db: Firestore, collectionPath: string, options?: GraphClientOptions): GraphClient;
164
+
165
+ declare function generateId(): string;
166
+
167
+ interface FirestoreIndexField {
168
+ fieldPath: string;
169
+ order: 'ASCENDING' | 'DESCENDING';
170
+ }
171
+ interface FirestoreIndex {
172
+ collectionGroup: string;
173
+ queryScope: 'COLLECTION' | 'COLLECTION_GROUP';
174
+ fields: FirestoreIndexField[];
175
+ }
176
+ interface FirestoreIndexConfig {
177
+ indexes: FirestoreIndex[];
178
+ fieldOverrides: unknown[];
179
+ }
231
180
  /**
232
- * Parse a Firestore collection path and determine the collection path
233
- * where a given UID's document lives, if that UID is an ancestor in the path.
234
- *
235
- * @param collectionPath - The full Firestore collection path of the current client
236
- * @param uid - The UID to search for in the path
237
- * @returns The collection path containing the UID, or `null` if not found in the path
181
+ * Generates a Firestore index configuration for a firegraph collection.
238
182
  *
239
- * @example
240
- * ```ts
241
- * // Path: graph/A/workspace/B/context
242
- * resolveAncestorCollection('graph/A/workspace/B/context', 'A')
243
- * // → 'graph'
183
+ * Always includes the 4 base composite indexes. If an entity discovery result
184
+ * is provided, generates additional data-field indexes for common query
185
+ * patterns on node data fields:
186
+ * (aType, axbType, data.{field})
244
187
  *
245
- * resolveAncestorCollection('graph/A/workspace/B/context', 'B')
246
- * // 'graph/A/workspace'
188
+ * When registry entries with `targetGraph` are provided, also generates
189
+ * collection group indexes for `findEdgesGlobal()` queries. The collection
190
+ * group name defaults to `'graph'` (the standard subgraph name) but can be
191
+ * overridden per `targetGraph` value.
247
192
  *
248
- * resolveAncestorCollection('graph/A/workspace/B/context', 'unknown')
249
- * // null
250
- * ```
193
+ * @param collection - Firestore collection name (e.g. 'graph')
194
+ * @param entities - Optional discovery result for per-entity data field indexes
195
+ * @param registryEntries - Optional registry entries; when any have `targetGraph`,
196
+ * collection group indexes are generated for the distinct subgraph names
251
197
  */
252
- declare function resolveAncestorCollection(collectionPath: string, uid: string): string | null;
198
+ declare function generateIndexConfig(collection: string, entities?: DiscoveryResult, registryEntries?: ReadonlyArray<RegistryEntry>): FirestoreIndexConfig;
199
+
253
200
  /**
254
- * Check whether a UID belongs to an ancestor node by scanning the collection path.
255
- *
256
- * @param collectionPath - The full Firestore collection path of the current client
257
- * @param uid - The UID to check
258
- * @returns `true` if the UID appears as a document segment in the path
201
+ * Default result limit applied to findEdges/findNodes queries
202
+ * when no explicit limit is provided. Prevents unbounded result sets
203
+ * that could be expensive on Enterprise Firestore.
259
204
  */
260
- declare function isAncestorUid(collectionPath: string, uid: string): boolean;
205
+ declare const DEFAULT_QUERY_LIMIT = 500;
261
206
 
262
207
  /**
263
208
  * JSON Schema validation and introspection utilities.
@@ -292,6 +237,107 @@ declare function compileSchema(schema: object, label?: string): (data: unknown)
292
237
  */
293
238
  declare function jsonSchemaToFieldMeta(schema: any): FieldMeta[];
294
239
 
240
+ /**
241
+ * Migration pipeline for auto-migrating records on read.
242
+ *
243
+ * When a record's `v` is behind the version derived from the registry
244
+ * entry's migrations, the pipeline applies migration steps sequentially
245
+ * to bring the data up to the current version.
246
+ */
247
+
248
+ /** Result of attempting to migrate a single record. */
249
+ interface MigrationResult {
250
+ record: StoredGraphRecord;
251
+ migrated: boolean;
252
+ /** Resolved write-back mode for this record (entry-level > global > 'off'). */
253
+ writeBack: MigrationWriteBack;
254
+ }
255
+ /**
256
+ * Apply a chain of migration steps to transform data from `currentVersion`
257
+ * to `targetVersion`. Throws `MigrationError` if the chain is incomplete
258
+ * or a migration function fails.
259
+ *
260
+ * Returns the migrated data payload only — the caller is responsible for
261
+ * stamping `v` on the record envelope.
262
+ */
263
+ declare function applyMigrationChain(data: Record<string, unknown>, currentVersion: number, targetVersion: number, migrations: MigrationStep[]): Promise<Record<string, unknown>>;
264
+ /**
265
+ * Validate that a migration chain forms a contiguous path from version 0
266
+ * to the highest `toVersion`. Throws `MigrationError` if the chain has
267
+ * gaps or duplicate `fromVersion` values.
268
+ *
269
+ * Called at registry construction time to catch incomplete chains early,
270
+ * rather than at read time when a record is migrated.
271
+ */
272
+ declare function validateMigrationChain(migrations: MigrationStep[], label: string): void;
273
+ /**
274
+ * Attempt to migrate a single record based on its registry entry.
275
+ *
276
+ * Returns the original record unchanged if no migration is needed
277
+ * (no schema version, already at current version, or no migrations defined).
278
+ */
279
+ declare function migrateRecord(record: StoredGraphRecord, registry: GraphRegistry, globalWriteBack?: MigrationWriteBack): Promise<MigrationResult>;
280
+ /**
281
+ * Migrate an array of records, returning all results.
282
+ * If any single migration fails, the entire call rejects — a broken
283
+ * migration function is a bug that should surface immediately.
284
+ */
285
+ declare function migrateRecords(records: StoredGraphRecord[], registry: GraphRegistry, globalWriteBack?: MigrationWriteBack): Promise<MigrationResult[]>;
286
+
287
+ declare function buildEdgeQueryPlan(params: FindEdgesParams): QueryPlan;
288
+ declare function buildNodeQueryPlan(params: FindNodesParams): QueryPlan;
289
+
290
+ /**
291
+ * Result of analyzing a query for collection scan risk.
292
+ */
293
+ interface QuerySafetyResult {
294
+ /** Whether the query matches a known indexed pattern. */
295
+ safe: boolean;
296
+ /** Human-readable explanation when the query is unsafe. */
297
+ reason?: string;
298
+ }
299
+ /**
300
+ * Analyzes a set of query filters to determine whether the query would
301
+ * likely cause a full collection scan on Firestore Enterprise.
302
+ *
303
+ * A query is considered "safe" if the builtin fields present in the filters
304
+ * match at least one known composite index pattern. Queries that only use
305
+ * `data.*` fields without a safe base pattern are flagged as unsafe.
306
+ */
307
+ declare function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult;
308
+
309
+ declare function buildNodeRecord(aType: string, uid: string, data: Record<string, unknown>): GraphRecord;
310
+ declare function buildEdgeRecord(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): GraphRecord;
311
+
312
+ /**
313
+ * Build a registry from either explicit entries or a DiscoveryResult.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * // From explicit entries (programmatic)
318
+ * const registry = createRegistry([
319
+ * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },
320
+ * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },
321
+ * ]);
322
+ *
323
+ * // From discovery result (folder convention)
324
+ * const discovered = await discoverEntities('./entities');
325
+ * const registry = createRegistry(discovered);
326
+ * ```
327
+ */
328
+ declare function createRegistry(input: RegistryEntry[] | DiscoveryResult): GraphRegistry;
329
+ /**
330
+ * Create a merged registry where `base` entries take priority and `extension`
331
+ * entries fill in gaps. Lookups and validation check `base` first; only if the
332
+ * triple is not found there does the merged registry fall through to
333
+ * `extension`.
334
+ *
335
+ * The `entries()` method returns a deduplicated list (base wins on collision).
336
+ * The `lookupByAxbType()` method merges results from both registries,
337
+ * deduplicating by triple key with base entries winning.
338
+ */
339
+ declare function createMergedRegistry(base: GraphRegistry, extension: GraphRegistry): GraphRegistry;
340
+
295
341
  /**
296
342
  * Sandbox module for compiling dynamic registry migration source strings
297
343
  * into executable functions.
@@ -365,6 +411,37 @@ declare function compileMigrations(stored: StoredMigrationStep[], executor?: Mig
365
411
  */
366
412
  declare function destroySandboxWorker(): Promise<void>;
367
413
 
414
+ /**
415
+ * Scope path matching for subgraph-level registry constraints.
416
+ *
417
+ * Scope paths are slash-separated names derived from the chain of
418
+ * `subgraph()` calls (e.g., `'agents'`, `'agents/memories'`).
419
+ * The root graph has an empty scope path (`''`).
420
+ *
421
+ * Patterns:
422
+ * - `'root'` — matches only the root graph (empty scope path)
423
+ * - `'agents'` — matches exactly `'agents'`
424
+ * - `'agents/memories'` — matches exactly `'agents/memories'`
425
+ * - `'*​/agents'` — `*` matches one segment: `'foo/agents'` but not `'a/b/agents'`
426
+ * - `'**​/memories'` — `**` matches zero or more segments
427
+ * - `'**'` — matches everything including root
428
+ */
429
+ /**
430
+ * Test whether a scope path matches a single pattern.
431
+ *
432
+ * @param scopePath - The current scope path (empty string for root)
433
+ * @param pattern - The pattern to match against
434
+ */
435
+ declare function matchScope(scopePath: string, pattern: string): boolean;
436
+ /**
437
+ * Test whether a scope path matches any pattern in a list.
438
+ * Returns `true` if the list is empty or undefined (allowed everywhere).
439
+ *
440
+ * @param scopePath - The current scope path (empty string for root)
441
+ * @param patterns - Array of patterns to match against
442
+ */
443
+ declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
444
+
368
445
  /**
369
446
  * Firestore-aware serialization for the sandbox migration pipeline.
370
447
  *
@@ -402,109 +479,16 @@ declare function serializeFirestoreTypes(data: Record<string, unknown>): Record<
402
479
  declare function deserializeFirestoreTypes(data: Record<string, unknown>, db?: Firestore): Record<string, unknown>;
403
480
 
404
481
  /**
405
- * Migration pipeline for auto-migrating records on read.
406
- *
407
- * When a record's `v` is behind the version derived from the registry
408
- * entry's migrations, the pipeline applies migration steps sequentially
409
- * to bring the data up to the current version.
410
- */
411
-
412
- /** Result of attempting to migrate a single record. */
413
- interface MigrationResult {
414
- record: StoredGraphRecord;
415
- migrated: boolean;
416
- /** Resolved write-back mode for this record (entry-level > global > 'off'). */
417
- writeBack: MigrationWriteBack;
418
- }
419
- /**
420
- * Apply a chain of migration steps to transform data from `currentVersion`
421
- * to `targetVersion`. Throws `MigrationError` if the chain is incomplete
422
- * or a migration function fails.
423
- *
424
- * Returns the migrated data payload only — the caller is responsible for
425
- * stamping `v` on the record envelope.
426
- */
427
- declare function applyMigrationChain(data: Record<string, unknown>, currentVersion: number, targetVersion: number, migrations: MigrationStep[]): Promise<Record<string, unknown>>;
428
- /**
429
- * Validate that a migration chain forms a contiguous path from version 0
430
- * to the highest `toVersion`. Throws `MigrationError` if the chain has
431
- * gaps or duplicate `fromVersion` values.
432
- *
433
- * Called at registry construction time to catch incomplete chains early,
434
- * rather than at read time when a record is migrated.
435
- */
436
- declare function validateMigrationChain(migrations: MigrationStep[], label: string): void;
437
- /**
438
- * Attempt to migrate a single record based on its registry entry.
439
- *
440
- * Returns the original record unchanged if no migration is needed
441
- * (no schema version, already at current version, or no migrations defined).
442
- */
443
- declare function migrateRecord(record: StoredGraphRecord, registry: GraphRegistry, globalWriteBack?: MigrationWriteBack): Promise<MigrationResult>;
444
- /**
445
- * Migrate an array of records, returning all results.
446
- * If any single migration fails, the entire call rejects — a broken
447
- * migration function is a bug that should surface immediately.
448
- */
449
- declare function migrateRecords(records: StoredGraphRecord[], registry: GraphRegistry, globalWriteBack?: MigrationWriteBack): Promise<MigrationResult[]>;
450
-
451
- interface FirestoreIndexField {
452
- fieldPath: string;
453
- order: 'ASCENDING' | 'DESCENDING';
454
- }
455
- interface FirestoreIndex {
456
- collectionGroup: string;
457
- queryScope: 'COLLECTION' | 'COLLECTION_GROUP';
458
- fields: FirestoreIndexField[];
459
- }
460
- interface FirestoreIndexConfig {
461
- indexes: FirestoreIndex[];
462
- fieldOverrides: unknown[];
463
- }
464
- /**
465
- * Generates a Firestore index configuration for a firegraph collection.
466
- *
467
- * Always includes the 4 base composite indexes. If an entity discovery result
468
- * is provided, generates additional data-field indexes for common query
469
- * patterns on node data fields:
470
- * (aType, axbType, data.{field})
471
- *
472
- * When registry entries with `targetGraph` are provided, also generates
473
- * collection group indexes for `findEdgesGlobal()` queries. The collection
474
- * group name defaults to `'graph'` (the standard subgraph name) but can be
475
- * overridden per `targetGraph` value.
482
+ * Create a traversal builder for multi-hop graph traversal.
476
483
  *
477
- * @param collection - Firestore collection name (e.g. 'graph')
478
- * @param entities - Optional discovery result for per-entity data field indexes
479
- * @param registryEntries - Optional registry entries; when any have `targetGraph`,
480
- * collection group indexes are generated for the distinct subgraph names
481
- */
482
- declare function generateIndexConfig(collection: string, entities?: DiscoveryResult, registryEntries?: ReadonlyArray<RegistryEntry>): FirestoreIndexConfig;
483
-
484
- /**
485
- * Result of analyzing a query for collection scan risk.
486
- */
487
- interface QuerySafetyResult {
488
- /** Whether the query matches a known indexed pattern. */
489
- safe: boolean;
490
- /** Human-readable explanation when the query is unsafe. */
491
- reason?: string;
492
- }
493
- /**
494
- * Analyzes a set of query filters to determine whether the query would
495
- * likely cause a full collection scan on Firestore Enterprise.
484
+ * Accepts either a `GraphReader` (backwards compatible) or a `GraphClient`.
485
+ * When a `GraphClient` is provided, cross-graph traversal via `targetGraph`
486
+ * is supported the traversal can follow edges into subgraphs.
496
487
  *
497
- * A query is considered "safe" if the builtin fields present in the filters
498
- * match at least one known composite index pattern. Queries that only use
499
- * `data.*` fields without a safe base pattern are flagged as unsafe.
500
- */
501
- declare function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult;
502
-
503
- /**
504
- * Default result limit applied to findEdges/findNodes queries
505
- * when no explicit limit is provided. Prevents unbounded result sets
506
- * that could be expensive on Enterprise Firestore.
488
+ * @param reader - A `GraphClient` or `GraphReader` to execute queries against
489
+ * @param startUid - UID of the starting node
490
+ * @param registry - Optional registry for automatic `targetGraph` resolution
507
491
  */
508
- declare const DEFAULT_QUERY_LIMIT = 500;
492
+ declare function createTraversal(reader: GraphClient | GraphReader, startUid: string, registry?: GraphRegistry): TraversalBuilder;
509
493
 
510
- export { BOOTSTRAP_ENTRIES, DEFAULT_QUERY_LIMIT, type DiscoverResult, DiscoveryError, DiscoveryResult, type DiscoveryWarning, DynamicGraphClient, DynamicRegistryConfig, DynamicRegistryError, EDGE_TYPE_SCHEMA, EdgeNotFoundError, type FieldMeta, FindEdgesParams, FindNodesParams, FiregraphError, type FirestoreIndex, type FirestoreIndexConfig, type FirestoreIndexField, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, InvalidQueryError, META_EDGE_TYPE, META_NODE_TYPE, MigrationError, MigrationExecutor, MigrationFn, type MigrationResult, MigrationStep, MigrationWriteBack, NODE_TYPE_SCHEMA, NodeNotFoundError, QueryFilter, QueryPlan, QuerySafetyError, type QuerySafetyResult, RegistryEntry, RegistryScopeError, RegistryViolationError, SERIALIZATION_TAG, StoredGraphRecord, StoredMigrationStep, TraversalBuilder, TraversalError, ValidationError, analyzeQuerySafety, applyMigrationChain, buildEdgeQueryPlan, buildEdgeRecord, buildNodeQueryPlan, buildNodeRecord, compileMigrationFn, compileMigrations, compileSchema, computeEdgeDocId, computeNodeDocId, createBootstrapRegistry, createGraphClient, createMergedRegistry, createRegistry, createRegistryFromGraph, createTraversal, defaultExecutor, deserializeFirestoreTypes, destroySandboxWorker, discoverEntities, generateDeterministicUid, generateId, generateIndexConfig, isAncestorUid, isTaggedValue, jsonSchemaToFieldMeta, matchScope, matchScopeAny, migrateRecord, migrateRecords, precompileSource, resolveAncestorCollection, serializeFirestoreTypes, validateMigrationChain };
494
+ export { BOOTSTRAP_ENTRIES, DEFAULT_QUERY_LIMIT, type DiscoverResult, DiscoveryError, DiscoveryResult, type DiscoveryWarning, DynamicGraphClient, DynamicRegistryConfig, EDGE_TYPE_SCHEMA, type FieldMeta, FindEdgesParams, FindNodesParams, FiregraphError, type FirestoreIndex, type FirestoreIndexConfig, type FirestoreIndexField, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, META_EDGE_TYPE, META_NODE_TYPE, MigrationExecutor, MigrationFn, type MigrationResult, MigrationStep, MigrationWriteBack, NODE_TYPE_SCHEMA, QueryFilter, QueryPlan, type QuerySafetyResult, RegistryEntry, SERIALIZATION_TAG, StoredGraphRecord, StoredMigrationStep, TraversalBuilder, analyzeQuerySafety, applyMigrationChain, buildEdgeQueryPlan, buildEdgeRecord, buildNodeQueryPlan, buildNodeRecord, compileMigrationFn, compileMigrations, compileSchema, computeEdgeDocId, computeNodeDocId, createBootstrapRegistry, createGraphClient, createGraphClientFromBackend, createMergedRegistry, createRegistry, createRegistryFromGraph, createTraversal, defaultExecutor, deserializeFirestoreTypes, destroySandboxWorker, discoverEntities, generateDeterministicUid, generateId, generateIndexConfig, isAncestorUid, isTaggedValue, jsonSchemaToFieldMeta, matchScope, matchScopeAny, migrateRecord, migrateRecords, precompileSource, resolveAncestorCollection, serializeFirestoreTypes, validateMigrationChain };