@typicalday/firegraph 0.11.2 → 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.
- package/README.md +38 -5
- package/dist/backend-BsR0lnFL.d.ts +200 -0
- package/dist/backend-Ct-fLlkG.d.cts +200 -0
- package/dist/backend.cjs +143 -2
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.d.cts +3 -3
- package/dist/backend.d.ts +3 -3
- package/dist/backend.js +13 -4
- package/dist/backend.js.map +1 -1
- package/dist/chunk-AWW4MUJ5.js +245 -0
- package/dist/chunk-AWW4MUJ5.js.map +1 -0
- package/dist/{chunk-5753Y42M.js → chunk-C2QMD7RY.js} +6 -10
- package/dist/chunk-C2QMD7RY.js.map +1 -0
- package/dist/chunk-EQJUUVFG.js +14 -0
- package/dist/chunk-EQJUUVFG.js.map +1 -0
- package/dist/{chunk-NJSOD64C.js → chunk-HONQY4HF.js} +80 -17
- package/dist/chunk-HONQY4HF.js.map +1 -0
- package/dist/cloudflare/index.cjs +458 -73
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.d.cts +8 -5
- package/dist/cloudflare/index.d.ts +8 -5
- package/dist/cloudflare/index.js +234 -56
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/index.cjs +271 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -69
- package/dist/index.d.ts +21 -69
- package/dist/index.js +58 -28
- package/dist/index.js.map +1 -1
- package/dist/registry-B1qsVL0E.d.cts +64 -0
- package/dist/registry-Fi074zVa.d.ts +64 -0
- package/dist/{serialization-ZZ7RSDRX.js → serialization-OE2PFZMY.js} +6 -4
- package/dist/{types-BGWxcpI_.d.cts → types-DxYLy8Ol.d.cts} +36 -2
- package/dist/{types-BGWxcpI_.d.ts → types-DxYLy8Ol.d.ts} +36 -2
- package/package.json +1 -1
- package/dist/backend-U-MLShlg.d.ts +0 -97
- package/dist/backend-np4gEVhB.d.cts +0 -97
- package/dist/chunk-5753Y42M.js.map +0 -1
- package/dist/chunk-NJSOD64C.js.map +0 -1
- package/dist/chunk-R7CRGYY4.js +0 -94
- package/dist/chunk-R7CRGYY4.js.map +0 -1
- /package/dist/{serialization-ZZ7RSDRX.js.map → serialization-OE2PFZMY.js.map} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { R as RegistryEntry, e as GraphRegistry, l as GraphReader, i as MigrationExecutor, b as DiscoveryResult } from './types-DxYLy8Ol.js';
|
|
2
|
+
|
|
3
|
+
/** The aType used for node type definition meta-nodes. */
|
|
4
|
+
declare const META_NODE_TYPE = "nodeType";
|
|
5
|
+
/** The aType used for edge type definition meta-nodes. */
|
|
6
|
+
declare const META_EDGE_TYPE = "edgeType";
|
|
7
|
+
/** JSON Schema for the `data` payload of a `nodeType` meta-node. */
|
|
8
|
+
declare const NODE_TYPE_SCHEMA: object;
|
|
9
|
+
/** JSON Schema for the `data` payload of an `edgeType` meta-node. */
|
|
10
|
+
declare const EDGE_TYPE_SCHEMA: object;
|
|
11
|
+
/** Registry entries for the two meta-types (always present). */
|
|
12
|
+
declare const BOOTSTRAP_ENTRIES: readonly RegistryEntry[];
|
|
13
|
+
declare function createBootstrapRegistry(): GraphRegistry;
|
|
14
|
+
/**
|
|
15
|
+
* Generate a deterministic UID for a meta-type definition.
|
|
16
|
+
* This ensures that defining the same type name always targets the same
|
|
17
|
+
* Firestore document, enabling upsert semantics.
|
|
18
|
+
*
|
|
19
|
+
* Format: 21-char base64url substring of SHA-256(`metaType:name`).
|
|
20
|
+
*/
|
|
21
|
+
declare function generateDeterministicUid(metaType: string, name: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Read meta-type nodes from the graph and compile them into a GraphRegistry.
|
|
24
|
+
*
|
|
25
|
+
* The returned registry includes both the dynamic entries AND the bootstrap
|
|
26
|
+
* meta-type entries, so meta-type writes remain validateable after a reload.
|
|
27
|
+
*
|
|
28
|
+
* @param reader - A GraphReader pointed at the collection containing meta-nodes.
|
|
29
|
+
* @param executor - Optional custom executor for compiling stored migration source strings.
|
|
30
|
+
*/
|
|
31
|
+
declare function createRegistryFromGraph(reader: GraphReader, executor?: MigrationExecutor): Promise<GraphRegistry>;
|
|
32
|
+
|
|
33
|
+
declare function generateId(): string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Build a registry from either explicit entries or a DiscoveryResult.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // From explicit entries (programmatic)
|
|
41
|
+
* const registry = createRegistry([
|
|
42
|
+
* { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },
|
|
43
|
+
* { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },
|
|
44
|
+
* ]);
|
|
45
|
+
*
|
|
46
|
+
* // From discovery result (folder convention)
|
|
47
|
+
* const discovered = await discoverEntities('./entities');
|
|
48
|
+
* const registry = createRegistry(discovered);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function createRegistry(input: RegistryEntry[] | DiscoveryResult): GraphRegistry;
|
|
52
|
+
/**
|
|
53
|
+
* Create a merged registry where `base` entries take priority and `extension`
|
|
54
|
+
* entries fill in gaps. Lookups and validation check `base` first; only if the
|
|
55
|
+
* triple is not found there does the merged registry fall through to
|
|
56
|
+
* `extension`.
|
|
57
|
+
*
|
|
58
|
+
* The `entries()` method returns a deduplicated list (base wins on collision).
|
|
59
|
+
* The `lookupByAxbType()` method merges results from both registries,
|
|
60
|
+
* deduplicating by triple key with base entries winning.
|
|
61
|
+
*/
|
|
62
|
+
declare function createMergedRegistry(base: GraphRegistry, extension: GraphRegistry): GraphRegistry;
|
|
63
|
+
|
|
64
|
+
export { BOOTSTRAP_ENTRIES as B, EDGE_TYPE_SCHEMA as E, META_EDGE_TYPE as M, NODE_TYPE_SCHEMA as N, META_NODE_TYPE as a, createMergedRegistry as b, createBootstrapRegistry as c, createRegistry as d, createRegistryFromGraph as e, generateId as f, generateDeterministicUid as g };
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SERIALIZATION_TAG,
|
|
3
2
|
deserializeFirestoreTypes,
|
|
4
|
-
isTaggedValue,
|
|
5
3
|
serializeFirestoreTypes
|
|
6
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-C2QMD7RY.js";
|
|
5
|
+
import {
|
|
6
|
+
SERIALIZATION_TAG,
|
|
7
|
+
isTaggedValue
|
|
8
|
+
} from "./chunk-EQJUUVFG.js";
|
|
7
9
|
export {
|
|
8
10
|
SERIALIZATION_TAG,
|
|
9
11
|
deserializeFirestoreTypes,
|
|
10
12
|
isTaggedValue,
|
|
11
13
|
serializeFirestoreTypes
|
|
12
14
|
};
|
|
13
|
-
//# sourceMappingURL=serialization-
|
|
15
|
+
//# sourceMappingURL=serialization-OE2PFZMY.js.map
|
|
@@ -260,7 +260,8 @@ interface IndexFieldSpec {
|
|
|
260
260
|
* because SQLite expression indexes must match the query compiler's
|
|
261
261
|
* output verbatim, and inlining quoted path components into DDL would
|
|
262
262
|
* desynchronize the two compilers. If you need to filter by an exotic
|
|
263
|
-
* key, use `
|
|
263
|
+
* key, use `replaceNode` / `replaceEdge` writes rather than an indexed
|
|
264
|
+
* field.
|
|
264
265
|
*/
|
|
265
266
|
path: string;
|
|
266
267
|
/** Descending order; defaults to ascending. */
|
|
@@ -583,9 +584,42 @@ interface GraphReader {
|
|
|
583
584
|
findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]>;
|
|
584
585
|
}
|
|
585
586
|
interface GraphWriter {
|
|
587
|
+
/**
|
|
588
|
+
* Write a node, deep-merging into any existing record.
|
|
589
|
+
*
|
|
590
|
+
* Nested objects are merged recursively — sibling keys at any depth
|
|
591
|
+
* survive. Arrays are terminal (replaced as a unit, not element-merged).
|
|
592
|
+
* `undefined` values are omitted; `null` is preserved. To delete a field,
|
|
593
|
+
* pass the `deleteField()` sentinel as its value.
|
|
594
|
+
*
|
|
595
|
+
* Use {@link replaceNode} when you want full-document replacement.
|
|
596
|
+
*/
|
|
586
597
|
putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void>;
|
|
598
|
+
/**
|
|
599
|
+
* Write an edge, deep-merging into any existing record. See
|
|
600
|
+
* {@link putNode} for the merge contract.
|
|
601
|
+
*/
|
|
587
602
|
putEdge(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
603
|
+
/**
|
|
604
|
+
* Replace a node's `data` payload entirely. Any field absent from
|
|
605
|
+
* `data` is dropped. Use sparingly — prefer {@link putNode} unless you
|
|
606
|
+
* specifically need to drop unknown fields.
|
|
607
|
+
*/
|
|
608
|
+
replaceNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void>;
|
|
609
|
+
/**
|
|
610
|
+
* Replace an edge's `data` payload entirely. See {@link replaceNode}.
|
|
611
|
+
*/
|
|
612
|
+
replaceEdge(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
613
|
+
/**
|
|
614
|
+
* Patch a node's `data` payload. Like {@link putNode} this is a deep
|
|
615
|
+
* merge — nested objects are walked, only leaves are written. Use the
|
|
616
|
+
* `deleteField()` sentinel to remove a field.
|
|
617
|
+
*/
|
|
588
618
|
updateNode(uid: string, data: Record<string, unknown>): Promise<void>;
|
|
619
|
+
/**
|
|
620
|
+
* Patch an edge's `data` payload. See {@link updateNode}.
|
|
621
|
+
*/
|
|
622
|
+
updateEdge(aUid: string, axbType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
589
623
|
removeNode(uid: string): Promise<void>;
|
|
590
624
|
removeEdge(aUid: string, axbType: string, bUid: string): Promise<void>;
|
|
591
625
|
}
|
|
@@ -733,4 +767,4 @@ interface CascadeResult extends BulkResult {
|
|
|
733
767
|
nodeDeleted: boolean;
|
|
734
768
|
}
|
|
735
769
|
|
|
736
|
-
export { type ScanProtection as A, type BulkBatchError as B, type CascadeResult as C, type DynamicGraphClient as D, type EdgeTopology as E, type FindEdgesParams as F, type GraphClientOptions as G, type HopDefinition as H, type IndexSpec as I, type TraversalOptions as J, type TraversalResult as K, type ViewDefaultsConfig as L, type
|
|
770
|
+
export { type ScanProtection as A, type BulkBatchError as B, type CascadeResult as C, type DynamicGraphClient as D, type EdgeTopology as E, type FindEdgesParams as F, type GraphClientOptions as G, type HopDefinition as H, type IndexSpec as I, type TraversalOptions as J, type TraversalResult as K, type ViewDefaultsConfig as L, type MigrationWriteBack as M, type NodeTypeData as N, type ViewResolverConfig as O, defineConfig as P, type QueryPlan as Q, type RegistryEntry as R, type StoredGraphRecord as S, type TraversalBuilder as T, resolveView as U, type ViewContext as V, type WhereClause as W, type GraphClient as a, type DiscoveryResult as b, type DynamicRegistryConfig as c, type MigrationStep as d, type GraphRegistry as e, type FindNodesParams as f, type QueryFilter as g, type GraphRecord as h, type MigrationExecutor as i, type MigrationFn as j, type StoredMigrationStep as k, type GraphReader as l, type BulkOptions as m, type BulkProgress as n, type BulkResult as o, type DefineTypeOptions as p, type DiscoveredEntity as q, type EdgeTypeData as r, type FiregraphConfig as s, type GraphBatch as t, type GraphTransaction as u, type GraphWriter as v, type HopResult as w, type IndexFieldSpec as x, type QueryMode as y, type QueryOptions as z };
|
|
@@ -260,7 +260,8 @@ interface IndexFieldSpec {
|
|
|
260
260
|
* because SQLite expression indexes must match the query compiler's
|
|
261
261
|
* output verbatim, and inlining quoted path components into DDL would
|
|
262
262
|
* desynchronize the two compilers. If you need to filter by an exotic
|
|
263
|
-
* key, use `
|
|
263
|
+
* key, use `replaceNode` / `replaceEdge` writes rather than an indexed
|
|
264
|
+
* field.
|
|
264
265
|
*/
|
|
265
266
|
path: string;
|
|
266
267
|
/** Descending order; defaults to ascending. */
|
|
@@ -583,9 +584,42 @@ interface GraphReader {
|
|
|
583
584
|
findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]>;
|
|
584
585
|
}
|
|
585
586
|
interface GraphWriter {
|
|
587
|
+
/**
|
|
588
|
+
* Write a node, deep-merging into any existing record.
|
|
589
|
+
*
|
|
590
|
+
* Nested objects are merged recursively — sibling keys at any depth
|
|
591
|
+
* survive. Arrays are terminal (replaced as a unit, not element-merged).
|
|
592
|
+
* `undefined` values are omitted; `null` is preserved. To delete a field,
|
|
593
|
+
* pass the `deleteField()` sentinel as its value.
|
|
594
|
+
*
|
|
595
|
+
* Use {@link replaceNode} when you want full-document replacement.
|
|
596
|
+
*/
|
|
586
597
|
putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void>;
|
|
598
|
+
/**
|
|
599
|
+
* Write an edge, deep-merging into any existing record. See
|
|
600
|
+
* {@link putNode} for the merge contract.
|
|
601
|
+
*/
|
|
587
602
|
putEdge(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
603
|
+
/**
|
|
604
|
+
* Replace a node's `data` payload entirely. Any field absent from
|
|
605
|
+
* `data` is dropped. Use sparingly — prefer {@link putNode} unless you
|
|
606
|
+
* specifically need to drop unknown fields.
|
|
607
|
+
*/
|
|
608
|
+
replaceNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void>;
|
|
609
|
+
/**
|
|
610
|
+
* Replace an edge's `data` payload entirely. See {@link replaceNode}.
|
|
611
|
+
*/
|
|
612
|
+
replaceEdge(aType: string, aUid: string, axbType: string, bType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
613
|
+
/**
|
|
614
|
+
* Patch a node's `data` payload. Like {@link putNode} this is a deep
|
|
615
|
+
* merge — nested objects are walked, only leaves are written. Use the
|
|
616
|
+
* `deleteField()` sentinel to remove a field.
|
|
617
|
+
*/
|
|
588
618
|
updateNode(uid: string, data: Record<string, unknown>): Promise<void>;
|
|
619
|
+
/**
|
|
620
|
+
* Patch an edge's `data` payload. See {@link updateNode}.
|
|
621
|
+
*/
|
|
622
|
+
updateEdge(aUid: string, axbType: string, bUid: string, data: Record<string, unknown>): Promise<void>;
|
|
589
623
|
removeNode(uid: string): Promise<void>;
|
|
590
624
|
removeEdge(aUid: string, axbType: string, bUid: string): Promise<void>;
|
|
591
625
|
}
|
|
@@ -733,4 +767,4 @@ interface CascadeResult extends BulkResult {
|
|
|
733
767
|
nodeDeleted: boolean;
|
|
734
768
|
}
|
|
735
769
|
|
|
736
|
-
export { type ScanProtection as A, type BulkBatchError as B, type CascadeResult as C, type DynamicGraphClient as D, type EdgeTopology as E, type FindEdgesParams as F, type GraphClientOptions as G, type HopDefinition as H, type IndexSpec as I, type TraversalOptions as J, type TraversalResult as K, type ViewDefaultsConfig as L, type
|
|
770
|
+
export { type ScanProtection as A, type BulkBatchError as B, type CascadeResult as C, type DynamicGraphClient as D, type EdgeTopology as E, type FindEdgesParams as F, type GraphClientOptions as G, type HopDefinition as H, type IndexSpec as I, type TraversalOptions as J, type TraversalResult as K, type ViewDefaultsConfig as L, type MigrationWriteBack as M, type NodeTypeData as N, type ViewResolverConfig as O, defineConfig as P, type QueryPlan as Q, type RegistryEntry as R, type StoredGraphRecord as S, type TraversalBuilder as T, resolveView as U, type ViewContext as V, type WhereClause as W, type GraphClient as a, type DiscoveryResult as b, type DynamicRegistryConfig as c, type MigrationStep as d, type GraphRegistry as e, type FindNodesParams as f, type QueryFilter as g, type GraphRecord as h, type MigrationExecutor as i, type MigrationFn as j, type StoredMigrationStep as k, type GraphReader as l, type BulkOptions as m, type BulkProgress as n, type BulkResult as o, type DefineTypeOptions as p, type DiscoveredEntity as q, type EdgeTypeData as r, type FiregraphConfig as s, type GraphBatch as t, type GraphTransaction as u, type GraphWriter as v, type HopResult as w, type IndexFieldSpec as x, type QueryMode as y, type QueryOptions as z };
|
package/package.json
CHANGED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { S as StoredGraphRecord, i as QueryFilter, z as QueryOptions, d as GraphReader, m as BulkOptions, C as CascadeResult, F as FindEdgesParams, o as BulkResult } from './types-BGWxcpI_.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Backend abstraction for firegraph.
|
|
5
|
-
*
|
|
6
|
-
* `StorageBackend` is the single interface every storage driver implements.
|
|
7
|
-
* The Firestore backend wraps `@google-cloud/firestore`; the SQLite backend
|
|
8
|
-
* (shared by D1 and Durable Object SQLite) uses a parameterized SQL executor.
|
|
9
|
-
*
|
|
10
|
-
* `GraphClientImpl` and friends depend only on this interface — they have
|
|
11
|
-
* no direct knowledge of Firestore or SQLite.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Per-record write payload — backend-agnostic. Timestamps are not present;
|
|
16
|
-
* the backend supplies them via `serverTimestamp()` placeholders that it
|
|
17
|
-
* itself resolves at commit time.
|
|
18
|
-
*/
|
|
19
|
-
interface WritableRecord {
|
|
20
|
-
aType: string;
|
|
21
|
-
aUid: string;
|
|
22
|
-
axbType: string;
|
|
23
|
-
bType: string;
|
|
24
|
-
bUid: string;
|
|
25
|
-
data: Record<string, unknown>;
|
|
26
|
-
/** Schema version (set by the writer when registry has migrations). */
|
|
27
|
-
v?: number;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Patch shape for `updateDoc`. Captures the two patterns that exist today:
|
|
31
|
-
* - `dataFields`: shallow merge under `data` (used by `updateNode`)
|
|
32
|
-
* - `replaceData`: full data replacement (used by migration write-back)
|
|
33
|
-
* - `v`: optional schema-version stamp
|
|
34
|
-
*
|
|
35
|
-
* `updatedAt` is always set by the backend.
|
|
36
|
-
*/
|
|
37
|
-
interface UpdatePayload {
|
|
38
|
-
dataFields?: Record<string, unknown>;
|
|
39
|
-
replaceData?: Record<string, unknown>;
|
|
40
|
-
v?: number;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Read/write transaction adapter. Mirrors Firestore's transaction semantics:
|
|
44
|
-
* reads are snapshot-consistent; writes are issued inside the transaction
|
|
45
|
-
* and a rejection from any write aborts the surrounding `runTransaction`.
|
|
46
|
-
*
|
|
47
|
-
* Writes return `Promise<void>` so SQL drivers can surface row-level errors
|
|
48
|
-
* (constraint violations, malformed JSON paths) rather than swallowing them.
|
|
49
|
-
* Firestore implementations can resolve synchronously since the underlying
|
|
50
|
-
* `Transaction.set/update/delete` calls are themselves synchronous buffers.
|
|
51
|
-
*/
|
|
52
|
-
interface TransactionBackend {
|
|
53
|
-
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
54
|
-
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
55
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
56
|
-
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
57
|
-
deleteDoc(docId: string): Promise<void>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Atomic multi-write batch.
|
|
61
|
-
*/
|
|
62
|
-
interface BatchBackend {
|
|
63
|
-
setDoc(docId: string, record: WritableRecord): void;
|
|
64
|
-
updateDoc(docId: string, update: UpdatePayload): void;
|
|
65
|
-
deleteDoc(docId: string): void;
|
|
66
|
-
commit(): Promise<void>;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* The single storage abstraction.
|
|
70
|
-
*
|
|
71
|
-
* Each backend instance is scoped to a "graph location" — for Firestore
|
|
72
|
-
* that's a collection path; for SQLite it's a (table, scopePath) pair.
|
|
73
|
-
* `subgraph()` returns a child backend bound to a nested location.
|
|
74
|
-
*/
|
|
75
|
-
interface StorageBackend {
|
|
76
|
-
/** Backend-internal location identifier (collection path or table name). */
|
|
77
|
-
readonly collectionPath: string;
|
|
78
|
-
/** Subgraph scope (empty string for root). */
|
|
79
|
-
readonly scopePath: string;
|
|
80
|
-
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
81
|
-
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
82
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
83
|
-
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
84
|
-
deleteDoc(docId: string): Promise<void>;
|
|
85
|
-
runTransaction<T>(fn: (tx: TransactionBackend) => Promise<T>): Promise<T>;
|
|
86
|
-
createBatch(): BatchBackend;
|
|
87
|
-
subgraph(parentNodeUid: string, name: string): StorageBackend;
|
|
88
|
-
removeNodeCascade(uid: string, reader: GraphReader, options?: BulkOptions): Promise<CascadeResult>;
|
|
89
|
-
bulkRemoveEdges(params: FindEdgesParams, reader: GraphReader, options?: BulkOptions): Promise<BulkResult>;
|
|
90
|
-
/**
|
|
91
|
-
* Find edges across all subgraphs sharing a given collection name.
|
|
92
|
-
* Optional — backends that can't support this should throw a clear error.
|
|
93
|
-
*/
|
|
94
|
-
findEdgesGlobal?(params: FindEdgesParams, collectionName?: string): Promise<StoredGraphRecord[]>;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export type { BatchBackend as B, StorageBackend as S, TransactionBackend as T, UpdatePayload as U, WritableRecord as W };
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { S as StoredGraphRecord, i as QueryFilter, z as QueryOptions, d as GraphReader, m as BulkOptions, C as CascadeResult, F as FindEdgesParams, o as BulkResult } from './types-BGWxcpI_.cjs';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Backend abstraction for firegraph.
|
|
5
|
-
*
|
|
6
|
-
* `StorageBackend` is the single interface every storage driver implements.
|
|
7
|
-
* The Firestore backend wraps `@google-cloud/firestore`; the SQLite backend
|
|
8
|
-
* (shared by D1 and Durable Object SQLite) uses a parameterized SQL executor.
|
|
9
|
-
*
|
|
10
|
-
* `GraphClientImpl` and friends depend only on this interface — they have
|
|
11
|
-
* no direct knowledge of Firestore or SQLite.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Per-record write payload — backend-agnostic. Timestamps are not present;
|
|
16
|
-
* the backend supplies them via `serverTimestamp()` placeholders that it
|
|
17
|
-
* itself resolves at commit time.
|
|
18
|
-
*/
|
|
19
|
-
interface WritableRecord {
|
|
20
|
-
aType: string;
|
|
21
|
-
aUid: string;
|
|
22
|
-
axbType: string;
|
|
23
|
-
bType: string;
|
|
24
|
-
bUid: string;
|
|
25
|
-
data: Record<string, unknown>;
|
|
26
|
-
/** Schema version (set by the writer when registry has migrations). */
|
|
27
|
-
v?: number;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Patch shape for `updateDoc`. Captures the two patterns that exist today:
|
|
31
|
-
* - `dataFields`: shallow merge under `data` (used by `updateNode`)
|
|
32
|
-
* - `replaceData`: full data replacement (used by migration write-back)
|
|
33
|
-
* - `v`: optional schema-version stamp
|
|
34
|
-
*
|
|
35
|
-
* `updatedAt` is always set by the backend.
|
|
36
|
-
*/
|
|
37
|
-
interface UpdatePayload {
|
|
38
|
-
dataFields?: Record<string, unknown>;
|
|
39
|
-
replaceData?: Record<string, unknown>;
|
|
40
|
-
v?: number;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Read/write transaction adapter. Mirrors Firestore's transaction semantics:
|
|
44
|
-
* reads are snapshot-consistent; writes are issued inside the transaction
|
|
45
|
-
* and a rejection from any write aborts the surrounding `runTransaction`.
|
|
46
|
-
*
|
|
47
|
-
* Writes return `Promise<void>` so SQL drivers can surface row-level errors
|
|
48
|
-
* (constraint violations, malformed JSON paths) rather than swallowing them.
|
|
49
|
-
* Firestore implementations can resolve synchronously since the underlying
|
|
50
|
-
* `Transaction.set/update/delete` calls are themselves synchronous buffers.
|
|
51
|
-
*/
|
|
52
|
-
interface TransactionBackend {
|
|
53
|
-
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
54
|
-
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
55
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
56
|
-
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
57
|
-
deleteDoc(docId: string): Promise<void>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Atomic multi-write batch.
|
|
61
|
-
*/
|
|
62
|
-
interface BatchBackend {
|
|
63
|
-
setDoc(docId: string, record: WritableRecord): void;
|
|
64
|
-
updateDoc(docId: string, update: UpdatePayload): void;
|
|
65
|
-
deleteDoc(docId: string): void;
|
|
66
|
-
commit(): Promise<void>;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* The single storage abstraction.
|
|
70
|
-
*
|
|
71
|
-
* Each backend instance is scoped to a "graph location" — for Firestore
|
|
72
|
-
* that's a collection path; for SQLite it's a (table, scopePath) pair.
|
|
73
|
-
* `subgraph()` returns a child backend bound to a nested location.
|
|
74
|
-
*/
|
|
75
|
-
interface StorageBackend {
|
|
76
|
-
/** Backend-internal location identifier (collection path or table name). */
|
|
77
|
-
readonly collectionPath: string;
|
|
78
|
-
/** Subgraph scope (empty string for root). */
|
|
79
|
-
readonly scopePath: string;
|
|
80
|
-
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
81
|
-
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
82
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
83
|
-
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
84
|
-
deleteDoc(docId: string): Promise<void>;
|
|
85
|
-
runTransaction<T>(fn: (tx: TransactionBackend) => Promise<T>): Promise<T>;
|
|
86
|
-
createBatch(): BatchBackend;
|
|
87
|
-
subgraph(parentNodeUid: string, name: string): StorageBackend;
|
|
88
|
-
removeNodeCascade(uid: string, reader: GraphReader, options?: BulkOptions): Promise<CascadeResult>;
|
|
89
|
-
bulkRemoveEdges(params: FindEdgesParams, reader: GraphReader, options?: BulkOptions): Promise<BulkResult>;
|
|
90
|
-
/**
|
|
91
|
-
* Find edges across all subgraphs sharing a given collection name.
|
|
92
|
-
* Optional — backends that can't support this should throw a clear error.
|
|
93
|
-
*/
|
|
94
|
-
findEdgesGlobal?(params: FindEdgesParams, collectionName?: string): Promise<StoredGraphRecord[]>;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export type { BatchBackend as B, StorageBackend as S, TransactionBackend as T, UpdatePayload as U, WritableRecord as W };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/serialization.ts"],"sourcesContent":["/**\n * Firestore-aware serialization for the sandbox migration pipeline.\n *\n * Firestore documents can contain special types (Timestamp, GeoPoint,\n * VectorValue, DocumentReference) that don't survive plain JSON\n * round-tripping. This module provides tagged serialization: Firestore\n * types are wrapped in tagged plain objects before JSON marshaling and\n * reconstructed after.\n *\n * Only used by the `defaultExecutor` sandbox path. Static migrations\n * (in-memory functions) receive raw Firestore objects directly.\n */\n\nimport type { DocumentReference, Firestore } from '@google-cloud/firestore';\nimport { FieldValue, GeoPoint, Timestamp } from '@google-cloud/firestore';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Sentinel key used to tag serialized Firestore types. */\nexport const SERIALIZATION_TAG = '__firegraph_ser__' as const;\n\n/** Known discriminator values for tagged types. */\nconst KNOWN_TYPES = new Set(['Timestamp', 'GeoPoint', 'VectorValue', 'DocumentReference']);\n\n// One-time warning for DocumentReference deserialization without db\nlet _docRefWarned = false;\n\n// ---------------------------------------------------------------------------\n// Type guard\n// ---------------------------------------------------------------------------\n\n/** Check if a value is a tagged serialized Firestore type. */\nexport function isTaggedValue(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false;\n const tag = (value as Record<string, unknown>)[SERIALIZATION_TAG];\n return typeof tag === 'string' && KNOWN_TYPES.has(tag);\n}\n\n// ---------------------------------------------------------------------------\n// Detection helpers\n// ---------------------------------------------------------------------------\n\nfunction isTimestamp(value: unknown): value is Timestamp {\n return value instanceof Timestamp;\n}\n\nfunction isGeoPoint(value: unknown): value is GeoPoint {\n return value instanceof GeoPoint;\n}\n\nfunction isDocumentReference(value: unknown): value is DocumentReference {\n // Duck-type check: DocumentReference has path (string) and firestore properties\n if (value === null || typeof value !== 'object') return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.path === 'string' &&\n v.firestore !== undefined &&\n typeof v.id === 'string' &&\n v.constructor?.name === 'DocumentReference'\n );\n}\n\nfunction isVectorValue(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false;\n const v = value as Record<string, unknown>;\n return (\n v.constructor?.name === 'VectorValue' && Array.isArray((v as Record<string, unknown>)._values)\n );\n}\n\n// ---------------------------------------------------------------------------\n// Serialize\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walk a data object and replace Firestore types with tagged\n * plain objects suitable for JSON serialization.\n *\n * Returns a new object tree — the input is never mutated.\n */\nexport function serializeFirestoreTypes(data: Record<string, unknown>): Record<string, unknown> {\n return serializeValue(data) as Record<string, unknown>;\n}\n\nfunction serializeValue(value: unknown): unknown {\n // Primitives\n if (value === null || value === undefined) return value;\n if (typeof value !== 'object') return value;\n\n // Firestore types (check before generic object/array)\n if (isTimestamp(value)) {\n return {\n [SERIALIZATION_TAG]: 'Timestamp',\n seconds: value.seconds,\n nanoseconds: value.nanoseconds,\n };\n }\n if (isGeoPoint(value)) {\n return {\n [SERIALIZATION_TAG]: 'GeoPoint',\n latitude: value.latitude,\n longitude: value.longitude,\n };\n }\n if (isDocumentReference(value)) {\n return { [SERIALIZATION_TAG]: 'DocumentReference', path: (value as DocumentReference).path };\n }\n if (isVectorValue(value)) {\n // Prefer toArray() (public API) over _values (private internal property)\n const v = value as Record<string, unknown>;\n const values =\n typeof v.toArray === 'function' ? (v.toArray as () => number[])() : (v._values as number[]);\n return { [SERIALIZATION_TAG]: 'VectorValue', values: [...values] };\n }\n\n // Arrays\n if (Array.isArray(value)) {\n return value.map(serializeValue);\n }\n\n // Plain objects — recurse\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>)) {\n result[key] = serializeValue((value as Record<string, unknown>)[key]);\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Deserialize\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walk a data object and reconstruct Firestore types from\n * tagged plain objects.\n *\n * @param data - The data to deserialize (typically from JSON.parse)\n * @param db - Optional Firestore instance for DocumentReference reconstruction.\n * If not provided, tagged DocumentReferences are left as-is with a one-time warning.\n *\n * Returns a new object tree — the input is never mutated.\n */\nexport function deserializeFirestoreTypes(\n data: Record<string, unknown>,\n db?: Firestore,\n): Record<string, unknown> {\n return deserializeValue(data, db) as Record<string, unknown>;\n}\n\nfunction deserializeValue(value: unknown, db?: Firestore): unknown {\n if (value === null || value === undefined) return value;\n if (typeof value !== 'object') return value;\n\n // Short-circuit for values that are already real Firestore types.\n // This makes deserializeFirestoreTypes idempotent — safe to call on data\n // that has already been deserialized (e.g., write-back after defaultExecutor\n // already reconstructed types, or static migrations that return raw types).\n if (\n isTimestamp(value) ||\n isGeoPoint(value) ||\n isDocumentReference(value) ||\n isVectorValue(value)\n ) {\n return value;\n }\n\n // Arrays\n if (Array.isArray(value)) {\n return value.map((v) => deserializeValue(v, db));\n }\n\n const obj = value as Record<string, unknown>;\n\n // Check for tagged Firestore type\n if (isTaggedValue(obj)) {\n const tag = obj[SERIALIZATION_TAG] as string;\n\n switch (tag) {\n case 'Timestamp':\n // Validate expected fields before reconstruction\n if (typeof obj.seconds !== 'number' || typeof obj.nanoseconds !== 'number') return obj;\n return new Timestamp(obj.seconds, obj.nanoseconds);\n\n case 'GeoPoint':\n if (typeof obj.latitude !== 'number' || typeof obj.longitude !== 'number') return obj;\n return new GeoPoint(obj.latitude, obj.longitude);\n\n case 'VectorValue':\n if (!Array.isArray(obj.values)) return obj;\n return FieldValue.vector(obj.values as number[]);\n\n case 'DocumentReference':\n if (typeof obj.path !== 'string') return obj;\n if (db) {\n return db.doc(obj.path);\n }\n // No db available — leave as tagged object with one-time warning\n if (!_docRefWarned) {\n _docRefWarned = true;\n console.warn(\n '[firegraph] DocumentReference encountered during migration deserialization ' +\n 'but no Firestore instance available. The reference will remain as a tagged ' +\n 'object with its path. Enable write-back for full reconstruction.',\n );\n }\n return obj;\n\n default:\n // Unknown tag — leave as-is (forward compatibility)\n return obj;\n }\n }\n\n // Plain object — recurse\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n result[key] = deserializeValue(obj[key], db);\n }\n return result;\n}\n"],"mappings":"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","names":[]}
|