@typicalday/firegraph 0.11.1 → 0.12.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 (44) hide show
  1. package/README.md +40 -15
  2. package/dist/backend-BsR0lnFL.d.ts +200 -0
  3. package/dist/backend-Ct-fLlkG.d.cts +200 -0
  4. package/dist/backend.cjs +143 -2
  5. package/dist/backend.cjs.map +1 -1
  6. package/dist/backend.d.cts +3 -3
  7. package/dist/backend.d.ts +3 -3
  8. package/dist/backend.js +13 -4
  9. package/dist/backend.js.map +1 -1
  10. package/dist/chunk-AWW4MUJ5.js +245 -0
  11. package/dist/chunk-AWW4MUJ5.js.map +1 -0
  12. package/dist/{chunk-5753Y42M.js → chunk-C2QMD7RY.js} +6 -10
  13. package/dist/chunk-C2QMD7RY.js.map +1 -0
  14. package/dist/chunk-EQJUUVFG.js +14 -0
  15. package/dist/chunk-EQJUUVFG.js.map +1 -0
  16. package/dist/{chunk-6SB34IPQ.js → chunk-HONQY4HF.js} +100 -28
  17. package/dist/chunk-HONQY4HF.js.map +1 -0
  18. package/dist/cloudflare/index.cjs +509 -102
  19. package/dist/cloudflare/index.cjs.map +1 -1
  20. package/dist/cloudflare/index.d.cts +45 -17
  21. package/dist/cloudflare/index.d.ts +45 -17
  22. package/dist/cloudflare/index.js +265 -74
  23. package/dist/cloudflare/index.js.map +1 -1
  24. package/dist/codegen/index.d.cts +1 -1
  25. package/dist/codegen/index.d.ts +1 -1
  26. package/dist/index.cjs +291 -47
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +59 -77
  29. package/dist/index.d.ts +59 -77
  30. package/dist/index.js +58 -28
  31. package/dist/index.js.map +1 -1
  32. package/dist/registry-B1qsVL0E.d.cts +64 -0
  33. package/dist/registry-Fi074zVa.d.ts +64 -0
  34. package/dist/{serialization-ZZ7RSDRX.js → serialization-OE2PFZMY.js} +6 -4
  35. package/dist/{types-BGWxcpI_.d.cts → types-DxYLy8Ol.d.cts} +36 -2
  36. package/dist/{types-BGWxcpI_.d.ts → types-DxYLy8Ol.d.ts} +36 -2
  37. package/package.json +8 -3
  38. package/dist/backend-U-MLShlg.d.ts +0 -97
  39. package/dist/backend-np4gEVhB.d.cts +0 -97
  40. package/dist/chunk-5753Y42M.js.map +0 -1
  41. package/dist/chunk-6SB34IPQ.js.map +0 -1
  42. package/dist/chunk-R7CRGYY4.js +0 -94
  43. package/dist/chunk-R7CRGYY4.js.map +0 -1
  44. /package/dist/{serialization-ZZ7RSDRX.js.map → serialization-OE2PFZMY.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1,9 +1,11 @@
1
- import { S as StorageBackend } from './backend-np4gEVhB.cjs';
2
- import { G as GraphClientOptions, a as GraphClient, D as DynamicGraphClient, I as IndexSpec, b as DiscoveryResult, R as RegistryEntry, c as GraphRegistry, d as GraphReader, M as MigrationExecutor, e 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-BGWxcpI_.cjs';
3
- 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, x as IndexFieldSpec, N as NodeTypeData, y as QueryMode, z as QueryOptions, A as ScanProtection, J as TraversalOptions, K as TraversalResult, V as ViewContext, L as ViewDefaultsConfig, O as ViewResolverConfig, W as WhereClause, P as defineConfig, U as resolveView } from './types-BGWxcpI_.cjs';
1
+ import { S as StorageBackend } from './backend-Ct-fLlkG.cjs';
2
+ export { d as deleteField } from './backend-Ct-fLlkG.cjs';
3
+ import { G as GraphClientOptions, a as GraphClient, D as DynamicGraphClient, I as IndexSpec, b as DiscoveryResult, c as DynamicRegistryConfig, R as RegistryEntry, S as StoredGraphRecord, M as MigrationWriteBack, d as MigrationStep, e as GraphRegistry, F as FindEdgesParams, Q as QueryPlan, f as FindNodesParams, g as QueryFilter, h as GraphRecord, i as MigrationExecutor, j as MigrationFn, k as StoredMigrationStep, l as GraphReader, T as TraversalBuilder } from './types-DxYLy8Ol.cjs';
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, x as IndexFieldSpec, N as NodeTypeData, y as QueryMode, z as QueryOptions, A as ScanProtection, J as TraversalOptions, K as TraversalResult, V as ViewContext, L as ViewDefaultsConfig, O as ViewResolverConfig, W as WhereClause, P as defineConfig, U as resolveView } from './types-DxYLy8Ol.cjs';
4
5
  export { CodegenOptions, generateTypes } from './codegen/index.cjs';
5
6
  import { F as FiregraphError } from './scope-path-B1G3YiA7.cjs';
6
7
  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, b as RegistryViolationError, S as StorageScopeSegment, T as TraversalError, V as ValidationError, a as appendStorageScope, i as isAncestorScopeUid, p as parseStorageScope, r as resolveAncestorScope } from './scope-path-B1G3YiA7.cjs';
8
+ export { B as BOOTSTRAP_ENTRIES, E as EDGE_TYPE_SCHEMA, M as META_EDGE_TYPE, a as META_NODE_TYPE, N as NODE_TYPE_SCHEMA, c as createBootstrapRegistry, b as createMergedRegistry, d as createRegistry, e as createRegistryFromGraph, g as generateDeterministicUid, f as generateId } from './registry-B1qsVL0E.cjs';
7
9
  import { Firestore } from '@google-cloud/firestore';
8
10
  export { Q as QueryClient, a as QueryClientError, b as QueryClientErrorCode, c as QueryClientOptions } from './client-Bk2Cm6xv.cjs';
9
11
  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.cjs';
@@ -165,40 +167,6 @@ declare function discoverEntities(entitiesDir: string): DiscoverResult;
165
167
  declare function computeNodeDocId(uid: string): string;
166
168
  declare function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string;
167
169
 
168
- /** The aType used for node type definition meta-nodes. */
169
- declare const META_NODE_TYPE = "nodeType";
170
- /** The aType used for edge type definition meta-nodes. */
171
- declare const META_EDGE_TYPE = "edgeType";
172
- /** JSON Schema for the `data` payload of a `nodeType` meta-node. */
173
- declare const NODE_TYPE_SCHEMA: object;
174
- /** JSON Schema for the `data` payload of an `edgeType` meta-node. */
175
- declare const EDGE_TYPE_SCHEMA: object;
176
- /** Registry entries for the two meta-types (always present). */
177
- declare const BOOTSTRAP_ENTRIES: readonly RegistryEntry[];
178
- /**
179
- * Build the bootstrap registry that validates meta-type writes.
180
- * This is always available, even before any dynamic types are loaded.
181
- */
182
- declare function createBootstrapRegistry(): GraphRegistry;
183
- /**
184
- * Generate a deterministic UID for a meta-type definition.
185
- * This ensures that defining the same type name always targets the same
186
- * Firestore document, enabling upsert semantics.
187
- *
188
- * Format: 21-char base64url substring of SHA-256(`metaType:name`).
189
- */
190
- declare function generateDeterministicUid(metaType: string, name: string): string;
191
- /**
192
- * Read meta-type nodes from the graph and compile them into a GraphRegistry.
193
- *
194
- * The returned registry includes both the dynamic entries AND the bootstrap
195
- * meta-type entries, so meta-type writes remain validateable after a reload.
196
- *
197
- * @param reader - A GraphReader pointed at the collection containing meta-nodes.
198
- * @param executor - Optional custom executor for compiling stored migration source strings.
199
- */
200
- declare function createRegistryFromGraph(reader: GraphReader, executor?: MigrationExecutor): Promise<GraphRegistry>;
201
-
202
170
  /**
203
171
  * Firestore-specific client factory.
204
172
  *
@@ -214,8 +182,6 @@ declare function createGraphClient(db: Firestore, collectionPath: string, option
214
182
  }): DynamicGraphClient;
215
183
  declare function createGraphClient(db: Firestore, collectionPath: string, options?: GraphClientOptions): GraphClient;
216
184
 
217
- declare function generateId(): string;
218
-
219
185
  /**
220
186
  * Firestore composite index generator.
221
187
  *
@@ -296,9 +262,17 @@ declare const DEFAULT_QUERY_LIMIT = 500;
296
262
  /**
297
263
  * JSON Schema validation and introspection utilities.
298
264
  *
299
- * Standard JSON Schema validation and introspection
300
- * processing. Uses ajv for validation and a recursive walker for converting
301
- * JSON Schema properties into FieldMeta objects for editor form generation.
265
+ * Uses `@cfworker/json-schema` for validation a runtime-interpreter
266
+ * JSON Schema validator that does not rely on `new Function()` and is
267
+ * therefore compatible with Cloudflare Workers (which run V8 with
268
+ * `--disallow-code-generation-from-strings`). Ajv was used here
269
+ * previously, but its `ajv.compile(schema)` generates a validator via
270
+ * the Function constructor and fails with "Code generation from strings
271
+ * disallowed for this context" whenever firegraph's dynamic-registry
272
+ * bootstrap or `reloadRegistry` runs inside a Worker.
273
+ *
274
+ * The introspection half (`jsonSchemaToFieldMeta`) is pure string/object
275
+ * manipulation with no validator dependency.
302
276
  */
303
277
  interface FieldMeta {
304
278
  name: string;
@@ -317,7 +291,33 @@ interface FieldMeta {
317
291
  }
318
292
  /**
319
293
  * Compile a JSON Schema into a validation function.
320
- * The returned function throws `ValidationError` if data is invalid.
294
+ *
295
+ * The returned function throws `ValidationError` if data is invalid. The
296
+ * error's `details` is the `OutputUnit[]` array produced by
297
+ * `@cfworker/json-schema` — consumers that previously inspected Ajv's
298
+ * `ErrorObject[]` need to map to the cfworker shape
299
+ * (`{ keyword, keywordLocation, instanceLocation, error }`).
300
+ *
301
+ * Draft 2020-12 is requested by default to match the library's richest
302
+ * feature set; schemas that omit `$schema` still validate under it
303
+ * since keyword semantics back-compat to draft-07 for the fields
304
+ * firegraph actually uses.
305
+ *
306
+ * `shortCircuit` is explicitly disabled so `result.errors` contains
307
+ * every violation, not just the first one — humans rely on the joined
308
+ * error message to debug bad writes from the editor / chat UI. The
309
+ * full array is preserved on `ValidationError.details`; only the
310
+ * rendered message is capped at `MAX_RENDERED_ERRORS` lines so
311
+ * pathological `oneOf`/`anyOf` schemas can't blow up log lines.
312
+ *
313
+ * Format keywords supported by `@cfworker/json-schema` (anything else
314
+ * is silently passed through — see node_modules/@cfworker/json-schema/
315
+ * src/format.ts):
316
+ * `date`, `time`, `date-time`, `duration`,
317
+ * `email`, `hostname`, `ipv4`, `ipv6`,
318
+ * `uri`, `uri-reference`, `uri-template`, `url`,
319
+ * `uuid`, `regex`,
320
+ * `json-pointer`, `relative-json-pointer`, `json-pointer-uri-fragment`.
321
321
  */
322
322
  declare function compileSchema(schema: object, label?: string): (data: unknown) => void;
323
323
  /**
@@ -398,35 +398,6 @@ declare function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult;
398
398
  declare function buildNodeRecord(aType: string, uid: string, data: Record<string, unknown>): GraphRecord;
399
399
  declare function buildEdgeRecord(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): GraphRecord;
400
400
 
401
- /**
402
- * Build a registry from either explicit entries or a DiscoveryResult.
403
- *
404
- * @example
405
- * ```ts
406
- * // From explicit entries (programmatic)
407
- * const registry = createRegistry([
408
- * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },
409
- * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },
410
- * ]);
411
- *
412
- * // From discovery result (folder convention)
413
- * const discovered = await discoverEntities('./entities');
414
- * const registry = createRegistry(discovered);
415
- * ```
416
- */
417
- declare function createRegistry(input: RegistryEntry[] | DiscoveryResult): GraphRegistry;
418
- /**
419
- * Create a merged registry where `base` entries take priority and `extension`
420
- * entries fill in gaps. Lookups and validation check `base` first; only if the
421
- * triple is not found there does the merged registry fall through to
422
- * `extension`.
423
- *
424
- * The `entries()` method returns a deduplicated list (base wins on collision).
425
- * The `lookupByAxbType()` method merges results from both registries,
426
- * deduplicating by triple key with base entries winning.
427
- */
428
- declare function createMergedRegistry(base: GraphRegistry, extension: GraphRegistry): GraphRegistry;
429
-
430
401
  /**
431
402
  * Sandbox module for compiling dynamic registry migration source strings
432
403
  * into executable functions.
@@ -531,6 +502,21 @@ declare function matchScope(scopePath: string, pattern: string): boolean;
531
502
  */
532
503
  declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
533
504
 
505
+ /**
506
+ * Firegraph serialization tag — split from `src/serialization.ts` so it can
507
+ * be imported from Workers-facing code without dragging in
508
+ * `@google-cloud/firestore`.
509
+ *
510
+ * The full serialization module (with Timestamp/GeoPoint round-tripping)
511
+ * lives one folder up because the sandbox migration pipeline needs it; the
512
+ * write-plan helper only needs to recognise tagged objects to keep them
513
+ * terminal during patch flattening, so it imports just the tag from here.
514
+ */
515
+ /** Sentinel key used to tag serialized Firestore types. */
516
+ declare const SERIALIZATION_TAG: "__firegraph_ser__";
517
+ /** Check if a value is a tagged serialized Firestore type. */
518
+ declare function isTaggedValue(value: unknown): boolean;
519
+
534
520
  /**
535
521
  * Firestore-aware serialization for the sandbox migration pipeline.
536
522
  *
@@ -544,10 +530,6 @@ declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
544
530
  * (in-memory functions) receive raw Firestore objects directly.
545
531
  */
546
532
 
547
- /** Sentinel key used to tag serialized Firestore types. */
548
- declare const SERIALIZATION_TAG: "__firegraph_ser__";
549
- /** Check if a value is a tagged serialized Firestore type. */
550
- declare function isTaggedValue(value: unknown): boolean;
551
533
  /**
552
534
  * Recursively walk a data object and replace Firestore types with tagged
553
535
  * plain objects suitable for JSON serialization.
@@ -580,4 +562,4 @@ declare function deserializeFirestoreTypes(data: Record<string, unknown>, db?: F
580
562
  */
581
563
  declare function createTraversal(reader: GraphClient | GraphReader, startUid: string, registry?: GraphRegistry): TraversalBuilder;
582
564
 
583
- export { BOOTSTRAP_ENTRIES, DEFAULT_CORE_INDEXES, 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, type GenerateIndexOptions, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, IndexSpec, 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 };
565
+ export { DEFAULT_CORE_INDEXES, DEFAULT_QUERY_LIMIT, type DiscoverResult, DiscoveryError, DiscoveryResult, type DiscoveryWarning, DynamicGraphClient, DynamicRegistryConfig, type FieldMeta, FindEdgesParams, FindNodesParams, FiregraphError, type FirestoreIndex, type FirestoreIndexConfig, type FirestoreIndexField, type GenerateIndexOptions, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, IndexSpec, MigrationExecutor, MigrationFn, type MigrationResult, MigrationStep, MigrationWriteBack, QueryFilter, QueryPlan, type QuerySafetyResult, RegistryEntry, SERIALIZATION_TAG, StoredGraphRecord, StoredMigrationStep, TraversalBuilder, analyzeQuerySafety, applyMigrationChain, buildEdgeQueryPlan, buildEdgeRecord, buildNodeQueryPlan, buildNodeRecord, compileMigrationFn, compileMigrations, compileSchema, computeEdgeDocId, computeNodeDocId, createGraphClient, createGraphClientFromBackend, createTraversal, defaultExecutor, deserializeFirestoreTypes, destroySandboxWorker, discoverEntities, generateIndexConfig, isAncestorUid, isTaggedValue, jsonSchemaToFieldMeta, matchScope, matchScopeAny, migrateRecord, migrateRecords, precompileSource, resolveAncestorCollection, serializeFirestoreTypes, validateMigrationChain };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import { S as StorageBackend } from './backend-U-MLShlg.js';
2
- import { G as GraphClientOptions, a as GraphClient, D as DynamicGraphClient, I as IndexSpec, b as DiscoveryResult, R as RegistryEntry, c as GraphRegistry, d as GraphReader, M as MigrationExecutor, e 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-BGWxcpI_.js';
3
- 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, x as IndexFieldSpec, N as NodeTypeData, y as QueryMode, z as QueryOptions, A as ScanProtection, J as TraversalOptions, K as TraversalResult, V as ViewContext, L as ViewDefaultsConfig, O as ViewResolverConfig, W as WhereClause, P as defineConfig, U as resolveView } from './types-BGWxcpI_.js';
1
+ import { S as StorageBackend } from './backend-BsR0lnFL.js';
2
+ export { d as deleteField } from './backend-BsR0lnFL.js';
3
+ import { G as GraphClientOptions, a as GraphClient, D as DynamicGraphClient, I as IndexSpec, b as DiscoveryResult, c as DynamicRegistryConfig, R as RegistryEntry, S as StoredGraphRecord, M as MigrationWriteBack, d as MigrationStep, e as GraphRegistry, F as FindEdgesParams, Q as QueryPlan, f as FindNodesParams, g as QueryFilter, h as GraphRecord, i as MigrationExecutor, j as MigrationFn, k as StoredMigrationStep, l as GraphReader, T as TraversalBuilder } from './types-DxYLy8Ol.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, x as IndexFieldSpec, N as NodeTypeData, y as QueryMode, z as QueryOptions, A as ScanProtection, J as TraversalOptions, K as TraversalResult, V as ViewContext, L as ViewDefaultsConfig, O as ViewResolverConfig, W as WhereClause, P as defineConfig, U as resolveView } from './types-DxYLy8Ol.js';
4
5
  export { CodegenOptions, generateTypes } from './codegen/index.js';
5
6
  import { F as FiregraphError } from './scope-path-B1G3YiA7.js';
6
7
  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, b as RegistryViolationError, S as StorageScopeSegment, T as TraversalError, V as ValidationError, a as appendStorageScope, i as isAncestorScopeUid, p as parseStorageScope, r as resolveAncestorScope } from './scope-path-B1G3YiA7.js';
8
+ export { B as BOOTSTRAP_ENTRIES, E as EDGE_TYPE_SCHEMA, M as META_EDGE_TYPE, a as META_NODE_TYPE, N as NODE_TYPE_SCHEMA, c as createBootstrapRegistry, b as createMergedRegistry, d as createRegistry, e as createRegistryFromGraph, g as generateDeterministicUid, f as generateId } from './registry-Fi074zVa.js';
7
9
  import { Firestore } from '@google-cloud/firestore';
8
10
  export { Q as QueryClient, a as QueryClientError, b as QueryClientErrorCode, c as QueryClientOptions } from './client-Bk2Cm6xv.js';
9
11
  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';
@@ -165,40 +167,6 @@ declare function discoverEntities(entitiesDir: string): DiscoverResult;
165
167
  declare function computeNodeDocId(uid: string): string;
166
168
  declare function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string;
167
169
 
168
- /** The aType used for node type definition meta-nodes. */
169
- declare const META_NODE_TYPE = "nodeType";
170
- /** The aType used for edge type definition meta-nodes. */
171
- declare const META_EDGE_TYPE = "edgeType";
172
- /** JSON Schema for the `data` payload of a `nodeType` meta-node. */
173
- declare const NODE_TYPE_SCHEMA: object;
174
- /** JSON Schema for the `data` payload of an `edgeType` meta-node. */
175
- declare const EDGE_TYPE_SCHEMA: object;
176
- /** Registry entries for the two meta-types (always present). */
177
- declare const BOOTSTRAP_ENTRIES: readonly RegistryEntry[];
178
- /**
179
- * Build the bootstrap registry that validates meta-type writes.
180
- * This is always available, even before any dynamic types are loaded.
181
- */
182
- declare function createBootstrapRegistry(): GraphRegistry;
183
- /**
184
- * Generate a deterministic UID for a meta-type definition.
185
- * This ensures that defining the same type name always targets the same
186
- * Firestore document, enabling upsert semantics.
187
- *
188
- * Format: 21-char base64url substring of SHA-256(`metaType:name`).
189
- */
190
- declare function generateDeterministicUid(metaType: string, name: string): string;
191
- /**
192
- * Read meta-type nodes from the graph and compile them into a GraphRegistry.
193
- *
194
- * The returned registry includes both the dynamic entries AND the bootstrap
195
- * meta-type entries, so meta-type writes remain validateable after a reload.
196
- *
197
- * @param reader - A GraphReader pointed at the collection containing meta-nodes.
198
- * @param executor - Optional custom executor for compiling stored migration source strings.
199
- */
200
- declare function createRegistryFromGraph(reader: GraphReader, executor?: MigrationExecutor): Promise<GraphRegistry>;
201
-
202
170
  /**
203
171
  * Firestore-specific client factory.
204
172
  *
@@ -214,8 +182,6 @@ declare function createGraphClient(db: Firestore, collectionPath: string, option
214
182
  }): DynamicGraphClient;
215
183
  declare function createGraphClient(db: Firestore, collectionPath: string, options?: GraphClientOptions): GraphClient;
216
184
 
217
- declare function generateId(): string;
218
-
219
185
  /**
220
186
  * Firestore composite index generator.
221
187
  *
@@ -296,9 +262,17 @@ declare const DEFAULT_QUERY_LIMIT = 500;
296
262
  /**
297
263
  * JSON Schema validation and introspection utilities.
298
264
  *
299
- * Standard JSON Schema validation and introspection
300
- * processing. Uses ajv for validation and a recursive walker for converting
301
- * JSON Schema properties into FieldMeta objects for editor form generation.
265
+ * Uses `@cfworker/json-schema` for validation a runtime-interpreter
266
+ * JSON Schema validator that does not rely on `new Function()` and is
267
+ * therefore compatible with Cloudflare Workers (which run V8 with
268
+ * `--disallow-code-generation-from-strings`). Ajv was used here
269
+ * previously, but its `ajv.compile(schema)` generates a validator via
270
+ * the Function constructor and fails with "Code generation from strings
271
+ * disallowed for this context" whenever firegraph's dynamic-registry
272
+ * bootstrap or `reloadRegistry` runs inside a Worker.
273
+ *
274
+ * The introspection half (`jsonSchemaToFieldMeta`) is pure string/object
275
+ * manipulation with no validator dependency.
302
276
  */
303
277
  interface FieldMeta {
304
278
  name: string;
@@ -317,7 +291,33 @@ interface FieldMeta {
317
291
  }
318
292
  /**
319
293
  * Compile a JSON Schema into a validation function.
320
- * The returned function throws `ValidationError` if data is invalid.
294
+ *
295
+ * The returned function throws `ValidationError` if data is invalid. The
296
+ * error's `details` is the `OutputUnit[]` array produced by
297
+ * `@cfworker/json-schema` — consumers that previously inspected Ajv's
298
+ * `ErrorObject[]` need to map to the cfworker shape
299
+ * (`{ keyword, keywordLocation, instanceLocation, error }`).
300
+ *
301
+ * Draft 2020-12 is requested by default to match the library's richest
302
+ * feature set; schemas that omit `$schema` still validate under it
303
+ * since keyword semantics back-compat to draft-07 for the fields
304
+ * firegraph actually uses.
305
+ *
306
+ * `shortCircuit` is explicitly disabled so `result.errors` contains
307
+ * every violation, not just the first one — humans rely on the joined
308
+ * error message to debug bad writes from the editor / chat UI. The
309
+ * full array is preserved on `ValidationError.details`; only the
310
+ * rendered message is capped at `MAX_RENDERED_ERRORS` lines so
311
+ * pathological `oneOf`/`anyOf` schemas can't blow up log lines.
312
+ *
313
+ * Format keywords supported by `@cfworker/json-schema` (anything else
314
+ * is silently passed through — see node_modules/@cfworker/json-schema/
315
+ * src/format.ts):
316
+ * `date`, `time`, `date-time`, `duration`,
317
+ * `email`, `hostname`, `ipv4`, `ipv6`,
318
+ * `uri`, `uri-reference`, `uri-template`, `url`,
319
+ * `uuid`, `regex`,
320
+ * `json-pointer`, `relative-json-pointer`, `json-pointer-uri-fragment`.
321
321
  */
322
322
  declare function compileSchema(schema: object, label?: string): (data: unknown) => void;
323
323
  /**
@@ -398,35 +398,6 @@ declare function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult;
398
398
  declare function buildNodeRecord(aType: string, uid: string, data: Record<string, unknown>): GraphRecord;
399
399
  declare function buildEdgeRecord(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): GraphRecord;
400
400
 
401
- /**
402
- * Build a registry from either explicit entries or a DiscoveryResult.
403
- *
404
- * @example
405
- * ```ts
406
- * // From explicit entries (programmatic)
407
- * const registry = createRegistry([
408
- * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },
409
- * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },
410
- * ]);
411
- *
412
- * // From discovery result (folder convention)
413
- * const discovered = await discoverEntities('./entities');
414
- * const registry = createRegistry(discovered);
415
- * ```
416
- */
417
- declare function createRegistry(input: RegistryEntry[] | DiscoveryResult): GraphRegistry;
418
- /**
419
- * Create a merged registry where `base` entries take priority and `extension`
420
- * entries fill in gaps. Lookups and validation check `base` first; only if the
421
- * triple is not found there does the merged registry fall through to
422
- * `extension`.
423
- *
424
- * The `entries()` method returns a deduplicated list (base wins on collision).
425
- * The `lookupByAxbType()` method merges results from both registries,
426
- * deduplicating by triple key with base entries winning.
427
- */
428
- declare function createMergedRegistry(base: GraphRegistry, extension: GraphRegistry): GraphRegistry;
429
-
430
401
  /**
431
402
  * Sandbox module for compiling dynamic registry migration source strings
432
403
  * into executable functions.
@@ -531,6 +502,21 @@ declare function matchScope(scopePath: string, pattern: string): boolean;
531
502
  */
532
503
  declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
533
504
 
505
+ /**
506
+ * Firegraph serialization tag — split from `src/serialization.ts` so it can
507
+ * be imported from Workers-facing code without dragging in
508
+ * `@google-cloud/firestore`.
509
+ *
510
+ * The full serialization module (with Timestamp/GeoPoint round-tripping)
511
+ * lives one folder up because the sandbox migration pipeline needs it; the
512
+ * write-plan helper only needs to recognise tagged objects to keep them
513
+ * terminal during patch flattening, so it imports just the tag from here.
514
+ */
515
+ /** Sentinel key used to tag serialized Firestore types. */
516
+ declare const SERIALIZATION_TAG: "__firegraph_ser__";
517
+ /** Check if a value is a tagged serialized Firestore type. */
518
+ declare function isTaggedValue(value: unknown): boolean;
519
+
534
520
  /**
535
521
  * Firestore-aware serialization for the sandbox migration pipeline.
536
522
  *
@@ -544,10 +530,6 @@ declare function matchScopeAny(scopePath: string, patterns: string[]): boolean;
544
530
  * (in-memory functions) receive raw Firestore objects directly.
545
531
  */
546
532
 
547
- /** Sentinel key used to tag serialized Firestore types. */
548
- declare const SERIALIZATION_TAG: "__firegraph_ser__";
549
- /** Check if a value is a tagged serialized Firestore type. */
550
- declare function isTaggedValue(value: unknown): boolean;
551
533
  /**
552
534
  * Recursively walk a data object and replace Firestore types with tagged
553
535
  * plain objects suitable for JSON serialization.
@@ -580,4 +562,4 @@ declare function deserializeFirestoreTypes(data: Record<string, unknown>, db?: F
580
562
  */
581
563
  declare function createTraversal(reader: GraphClient | GraphReader, startUid: string, registry?: GraphRegistry): TraversalBuilder;
582
564
 
583
- export { BOOTSTRAP_ENTRIES, DEFAULT_CORE_INDEXES, 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, type GenerateIndexOptions, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, IndexSpec, 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 };
565
+ export { DEFAULT_CORE_INDEXES, DEFAULT_QUERY_LIMIT, type DiscoverResult, DiscoveryError, DiscoveryResult, type DiscoveryWarning, DynamicGraphClient, DynamicRegistryConfig, type FieldMeta, FindEdgesParams, FindNodesParams, FiregraphError, type FirestoreIndex, type FirestoreIndexConfig, type FirestoreIndexField, type GenerateIndexOptions, GraphClient, GraphClientOptions, GraphReader, GraphRecord, GraphRegistry, IndexSpec, MigrationExecutor, MigrationFn, type MigrationResult, MigrationStep, MigrationWriteBack, QueryFilter, QueryPlan, type QuerySafetyResult, RegistryEntry, SERIALIZATION_TAG, StoredGraphRecord, StoredMigrationStep, TraversalBuilder, analyzeQuerySafety, applyMigrationChain, buildEdgeQueryPlan, buildEdgeRecord, buildNodeQueryPlan, buildNodeRecord, compileMigrationFn, compileMigrations, compileSchema, computeEdgeDocId, computeNodeDocId, createGraphClient, createGraphClientFromBackend, createTraversal, defaultExecutor, deserializeFirestoreTypes, destroySandboxWorker, discoverEntities, generateIndexConfig, isAncestorUid, isTaggedValue, jsonSchemaToFieldMeta, matchScope, matchScopeAny, migrateRecord, migrateRecords, precompileSource, resolveAncestorCollection, serializeFirestoreTypes, validateMigrationChain };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ import {
31
31
  defaultExecutor,
32
32
  destroySandboxWorker,
33
33
  generateDeterministicUid,
34
+ generateId,
34
35
  jsonSchemaToFieldMeta,
35
36
  matchScope,
36
37
  matchScopeAny,
@@ -38,7 +39,7 @@ import {
38
39
  migrateRecords,
39
40
  precompileSource,
40
41
  validateMigrationChain
41
- } from "./chunk-6SB34IPQ.js";
42
+ } from "./chunk-HONQY4HF.js";
42
43
  import {
43
44
  CrossBackendTransactionError,
44
45
  DynamicRegistryError,
@@ -51,8 +52,11 @@ import {
51
52
  RegistryScopeError,
52
53
  RegistryViolationError,
53
54
  TraversalError,
54
- ValidationError
55
- } from "./chunk-R7CRGYY4.js";
55
+ ValidationError,
56
+ assertSafePath,
57
+ assertUpdatePayloadExclusive,
58
+ deleteField
59
+ } from "./chunk-AWW4MUJ5.js";
56
60
  import {
57
61
  generateTypes
58
62
  } from "./chunk-GJVVRTQT.js";
@@ -61,11 +65,13 @@ import {
61
65
  QueryClientError
62
66
  } from "./chunk-EEKWRX5E.js";
63
67
  import {
64
- SERIALIZATION_TAG,
65
68
  deserializeFirestoreTypes,
66
- isTaggedValue,
67
69
  serializeFirestoreTypes
68
- } from "./chunk-5753Y42M.js";
70
+ } from "./chunk-C2QMD7RY.js";
71
+ import {
72
+ SERIALIZATION_TAG,
73
+ isTaggedValue
74
+ } from "./chunk-EQJUUVFG.js";
69
75
 
70
76
  // src/config.ts
71
77
  function defineConfig(config) {
@@ -457,8 +463,12 @@ function createFirestoreAdapter(db, collectionPath) {
457
463
  if (!snap.exists) return null;
458
464
  return snap.data();
459
465
  },
460
- async setDoc(docId, data) {
461
- await collectionRef.doc(docId).set(data);
466
+ async setDoc(docId, data, options) {
467
+ if (options?.merge) {
468
+ await collectionRef.doc(docId).set(data, { merge: true });
469
+ } else {
470
+ await collectionRef.doc(docId).set(data);
471
+ }
462
472
  },
463
473
  async updateDoc(docId, data) {
464
474
  await collectionRef.doc(docId).update(data);
@@ -490,8 +500,12 @@ function createTransactionAdapter(db, collectionPath, tx) {
490
500
  if (!snap.exists) return null;
491
501
  return snap.data();
492
502
  },
493
- setDoc(docId, data) {
494
- tx.set(collectionRef.doc(docId), data);
503
+ setDoc(docId, data, options) {
504
+ if (options?.merge) {
505
+ tx.set(collectionRef.doc(docId), data, { merge: true });
506
+ } else {
507
+ tx.set(collectionRef.doc(docId), data);
508
+ }
495
509
  },
496
510
  updateDoc(docId, data) {
497
511
  tx.update(collectionRef.doc(docId), data);
@@ -519,8 +533,12 @@ function createBatchAdapter(db, collectionPath) {
519
533
  const collectionRef = db.collection(collectionPath);
520
534
  const batch = db.batch();
521
535
  return {
522
- setDoc(docId, data) {
523
- batch.set(collectionRef.doc(docId), data);
536
+ setDoc(docId, data, options) {
537
+ if (options?.merge) {
538
+ batch.set(collectionRef.doc(docId), data, { merge: true });
539
+ } else {
540
+ batch.set(collectionRef.doc(docId), data);
541
+ }
524
542
  },
525
543
  updateDoc(docId, data) {
526
544
  batch.update(collectionRef.doc(docId), data);
@@ -596,16 +614,21 @@ function createPipelineQueryAdapter(db, collectionPath) {
596
614
  }
597
615
 
598
616
  // src/internal/firestore-backend.ts
617
+ function dottedDataPath(op) {
618
+ assertSafePath(op.path);
619
+ return `data.${op.path.join(".")}`;
620
+ }
599
621
  function buildFirestoreUpdate(update, db) {
622
+ assertUpdatePayloadExclusive(update);
600
623
  const out = {
601
624
  updatedAt: FieldValue.serverTimestamp()
602
625
  };
603
626
  if (update.replaceData) {
604
627
  out.data = deserializeFirestoreTypes(update.replaceData, db);
605
- }
606
- if (update.dataFields) {
607
- for (const [k, v] of Object.entries(update.dataFields)) {
608
- out[`data.${k}`] = v;
628
+ } else if (update.dataOps) {
629
+ for (const op of update.dataOps) {
630
+ const key = dottedDataPath(op);
631
+ out[key] = op.delete ? FieldValue.delete() : op.value;
609
632
  }
610
633
  }
611
634
  if (update.v !== void 0) {
@@ -639,8 +662,12 @@ var FirestoreTransactionBackend = class {
639
662
  query(filters, options) {
640
663
  return this.adapter.query(filters, options);
641
664
  }
642
- async setDoc(docId, record) {
643
- this.adapter.setDoc(docId, stampWritableRecord(record));
665
+ async setDoc(docId, record, mode) {
666
+ this.adapter.setDoc(
667
+ docId,
668
+ stampWritableRecord(record),
669
+ mode === "merge" ? { merge: true } : void 0
670
+ );
644
671
  }
645
672
  async updateDoc(docId, update) {
646
673
  this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
@@ -654,8 +681,12 @@ var FirestoreBatchBackend = class {
654
681
  this.adapter = adapter;
655
682
  this.db = db;
656
683
  }
657
- setDoc(docId, record) {
658
- this.adapter.setDoc(docId, stampWritableRecord(record));
684
+ setDoc(docId, record, mode) {
685
+ this.adapter.setDoc(
686
+ docId,
687
+ stampWritableRecord(record),
688
+ mode === "merge" ? { merge: true } : void 0
689
+ );
659
690
  }
660
691
  updateDoc(docId, update) {
661
692
  this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
@@ -693,8 +724,12 @@ var FirestoreBackendImpl = class _FirestoreBackendImpl {
693
724
  return this.adapter.query(filters, options);
694
725
  }
695
726
  // --- Writes ---
696
- setDoc(docId, record) {
697
- return this.adapter.setDoc(docId, stampWritableRecord(record));
727
+ setDoc(docId, record, mode) {
728
+ return this.adapter.setDoc(
729
+ docId,
730
+ stampWritableRecord(record),
731
+ mode === "merge" ? { merge: true } : void 0
732
+ );
698
733
  }
699
734
  updateDoc(docId, update) {
700
735
  return this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
@@ -779,12 +814,6 @@ function createGraphClient(db, collectionPath, options) {
779
814
  return new GraphClientImpl(backend, options, metaBackend);
780
815
  }
781
816
 
782
- // src/id.ts
783
- import { nanoid } from "nanoid";
784
- function generateId() {
785
- return nanoid();
786
- }
787
-
788
817
  // src/indexes.ts
789
818
  function normalizeField(f) {
790
819
  return typeof f === "string" ? { path: f, desc: false } : { path: f.path, desc: !!f.desc };
@@ -1222,6 +1251,7 @@ export {
1222
1251
  defaultExecutor,
1223
1252
  defineConfig,
1224
1253
  defineViews,
1254
+ deleteField,
1225
1255
  deserializeFirestoreTypes,
1226
1256
  destroySandboxWorker,
1227
1257
  discoverEntities,