@typicalday/firegraph 0.3.0 → 0.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/docid.ts","../src/internal/constants.ts","../src/record.ts","../src/errors.ts","../src/query.ts","../src/internal/firestore-adapter.ts","../src/internal/pipeline-adapter.ts","../src/transaction.ts","../src/query-safety.ts","../src/batch.ts","../src/bulk.ts","../src/dynamic-registry.ts","../src/json-schema.ts","../src/scope.ts","../src/registry.ts","../src/id.ts","../src/traverse.ts","../src/views.ts","../src/config.ts","../src/discover.ts","../src/cross-graph.ts","../src/codegen/index.ts","../src/indexes.ts","../src/query-client/client.ts","../src/query-client/shaping.ts","../src/query-client/config.ts"],"sourcesContent":["export { createGraphClient } from './client.js';\nexport { createRegistry } from './registry.js';\nexport {\n createRegistryFromGraph,\n createBootstrapRegistry,\n generateDeterministicUid,\n META_NODE_TYPE,\n META_EDGE_TYPE,\n NODE_TYPE_SCHEMA,\n EDGE_TYPE_SCHEMA,\n BOOTSTRAP_ENTRIES,\n} from './dynamic-registry.js';\nexport { generateId } from './id.js';\nexport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nexport { buildNodeRecord, buildEdgeRecord } from './record.js';\nexport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nexport { createTraversal } from './traverse.js';\nexport { defineViews } from './views.js';\nexport { defineConfig, resolveView } from './config.js';\nexport { discoverEntities } from './discover.js';\nexport { matchScope, matchScopeAny } from './scope.js';\nexport { resolveAncestorCollection, isAncestorUid } from './cross-graph.js';\nexport { compileSchema, jsonSchemaToFieldMeta } from './json-schema.js';\n\nexport {\n FiregraphError,\n NodeNotFoundError,\n EdgeNotFoundError,\n ValidationError,\n RegistryViolationError,\n InvalidQueryError,\n TraversalError,\n DynamicRegistryError,\n QuerySafetyError,\n RegistryScopeError,\n} from './errors.js';\n\nexport { DiscoveryError } from './discover.js';\n\nexport type {\n GraphRecord,\n StoredGraphRecord,\n WhereClause,\n FindEdgesParams,\n FindNodesParams,\n QueryPlan,\n QueryFilter,\n QueryOptions,\n RegistryEntry,\n GraphClientOptions,\n GraphRegistry,\n GraphReader,\n GraphWriter,\n GraphClient,\n GraphTransaction,\n GraphBatch,\n DynamicGraphClient,\n DynamicRegistryConfig,\n DefineTypeOptions,\n NodeTypeData,\n EdgeTypeData,\n HopDefinition,\n TraversalOptions,\n HopResult,\n TraversalResult,\n TraversalBuilder,\n EdgeTopology,\n DiscoveredEntity,\n DiscoveryResult,\n BulkOptions,\n BulkProgress,\n BulkResult,\n BulkBatchError,\n CascadeResult,\n QueryMode,\n ScanProtection,\n} from './types.js';\n\nexport type {\n ViewComponentClass,\n EntityViewConfig,\n ViewRegistryInput,\n ViewMeta,\n EntityViewMeta,\n ViewRegistry,\n} from './views.js';\n\nexport type {\n FiregraphConfig,\n ViewContext,\n ViewResolverConfig,\n ViewDefaultsConfig,\n} from './config.js';\n\nexport type { FieldMeta } from './json-schema.js';\n\nexport type { DiscoveryWarning, DiscoverResult } from './discover.js';\n\nexport { generateTypes } from './codegen/index.js';\nexport type { CodegenOptions } from './codegen/index.js';\n\nexport { generateIndexConfig } from './indexes.js';\nexport type { FirestoreIndexConfig, FirestoreIndex, FirestoreIndexField } from './indexes.js';\n\nexport { analyzeQuerySafety } from './query-safety.js';\nexport type { QuerySafetyResult } from './query-safety.js';\n\nexport { DEFAULT_QUERY_LIMIT } from './internal/constants.js';\n\nexport { QueryClient, QueryClientError } from './query-client/index.js';\nexport type { QueryClientErrorCode, QueryClientOptions } from './query-client/index.js';\n","import { FieldValue } from '@google-cloud/firestore';\nimport type { Firestore } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport {\n createFirestoreAdapter,\n createTransactionAdapter,\n createBatchAdapter,\n} from './internal/firestore-adapter.js';\nimport type { FirestoreAdapter } from './internal/firestore-adapter.js';\nimport { createPipelineQueryAdapter } from './internal/pipeline-adapter.js';\nimport type { PipelineQueryAdapter } from './internal/pipeline-adapter.js';\nimport { GraphTransactionImpl } from './transaction.js';\nimport { GraphBatchImpl } from './batch.js';\nimport {\n removeNodeCascade as removeNodeCascadeImpl,\n bulkRemoveEdges as bulkRemoveEdgesImpl,\n} from './bulk.js';\nimport { DynamicRegistryError, FiregraphError, QuerySafetyError } from './errors.js';\nimport { analyzeQuerySafety } from './query-safety.js';\nimport {\n createBootstrapRegistry,\n createRegistryFromGraph,\n generateDeterministicUid,\n META_NODE_TYPE,\n META_EDGE_TYPE,\n} from './dynamic-registry.js';\nimport type {\n DefineTypeOptions,\n DynamicGraphClient,\n DynamicRegistryConfig,\n GraphClient,\n GraphClientOptions,\n GraphReader,\n GraphRegistry,\n GraphTransaction,\n GraphBatch,\n StoredGraphRecord,\n FindEdgesParams,\n FindNodesParams,\n EdgeTopology,\n QueryFilter,\n QueryOptions,\n QueryMode,\n ScanProtection,\n BulkOptions,\n BulkResult,\n CascadeResult,\n} from './types.js';\n\nlet _standardModeWarned = false;\n\nconst RESERVED_TYPE_NAMES = new Set([META_NODE_TYPE, META_EDGE_TYPE]);\n\nclass GraphClientImpl implements DynamicGraphClient {\n private readonly adapter: FirestoreAdapter;\n private readonly pipelineAdapter?: PipelineQueryAdapter;\n private readonly queryMode: QueryMode;\n readonly scanProtection: ScanProtection;\n\n // Static mode\n private readonly staticRegistry?: GraphRegistry;\n\n // Dynamic mode\n private readonly dynamicConfig?: DynamicRegistryConfig;\n private readonly bootstrapRegistry?: GraphRegistry;\n private dynamicRegistry?: GraphRegistry;\n private readonly metaAdapter?: FirestoreAdapter;\n private readonly metaPipelineAdapter?: PipelineQueryAdapter;\n\n // Subgraph scope tracking\n private readonly scopePath: string;\n\n constructor(\n private readonly db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n /** @internal Scope path for subgraph clients (empty string = root). */\n scopePath: string = '',\n ) {\n this.scopePath = scopePath;\n this.adapter = createFirestoreAdapter(db, collectionPath);\n\n // Validate mutual exclusivity\n if (options?.registry && options?.registryMode) {\n throw new DynamicRegistryError(\n 'Cannot provide both \"registry\" and \"registryMode\". ' +\n 'Use \"registry\" for static mode or \"registryMode\" for dynamic mode.',\n );\n }\n\n if (options?.registryMode) {\n this.dynamicConfig = options.registryMode;\n this.bootstrapRegistry = createBootstrapRegistry();\n\n // If meta-collection differs from main, create separate adapter\n const metaCollectionPath = options.registryMode.collection;\n if (metaCollectionPath && metaCollectionPath !== collectionPath) {\n this.metaAdapter = createFirestoreAdapter(db, metaCollectionPath);\n }\n } else {\n this.staticRegistry = options?.registry;\n }\n\n // Resolve effective query mode\n const requestedMode = options?.queryMode ?? 'pipeline';\n const isEmulator = !!process.env.FIRESTORE_EMULATOR_HOST;\n\n if (isEmulator) {\n // Emulator doesn't support Pipeline operations — silently fall back\n this.queryMode = 'standard';\n } else {\n this.queryMode = requestedMode;\n }\n\n // Warn once when standard mode is explicitly chosen outside the emulator\n if (\n this.queryMode === 'standard' &&\n !isEmulator &&\n requestedMode === 'standard' &&\n !_standardModeWarned\n ) {\n _standardModeWarned = true;\n console.warn(\n '[firegraph] Standard query mode enabled. This is NOT recommended for production:\\n' +\n ' - Enterprise Firestore: data.* filters cause full collection scans (high billing)\\n' +\n ' - Standard Firestore: data.* filters without composite indexes will fail\\n' +\n ' See: https://github.com/typicalday/firegraph#query-modes',\n );\n }\n\n // Scan protection\n this.scanProtection = options?.scanProtection ?? 'error';\n\n // Create pipeline adapter when in pipeline mode\n if (this.queryMode === 'pipeline') {\n this.pipelineAdapter = createPipelineQueryAdapter(db, collectionPath);\n\n // Also create pipeline adapter for meta-collection if separate\n if (this.metaAdapter) {\n this.metaPipelineAdapter = createPipelineQueryAdapter(\n db,\n options!.registryMode!.collection!,\n );\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Registry routing\n // ---------------------------------------------------------------------------\n\n /**\n * Get the appropriate registry for validating a write to the given type.\n *\n * - Static mode: returns staticRegistry (or undefined if none set)\n * - Dynamic mode:\n * - Meta-types (nodeType, edgeType): validated against bootstrapRegistry\n * - Domain types: validated against dynamicRegistry (falls back to\n * bootstrapRegistry which rejects unknown types)\n */\n private getRegistryForType(aType: string): GraphRegistry | undefined {\n if (!this.dynamicConfig) return this.staticRegistry;\n\n if (aType === META_NODE_TYPE || aType === META_EDGE_TYPE) {\n return this.bootstrapRegistry;\n }\n\n return this.dynamicRegistry ?? this.bootstrapRegistry;\n }\n\n /**\n * Get the Firestore adapter for writing the given type.\n * Meta-types route to metaAdapter if a separate collection is configured.\n */\n private getAdapterForType(aType: string): FirestoreAdapter {\n if (\n this.metaAdapter &&\n (aType === META_NODE_TYPE || aType === META_EDGE_TYPE)\n ) {\n return this.metaAdapter;\n }\n return this.adapter;\n }\n\n /**\n * Get the combined registry for transaction/batch context.\n * In static mode, returns staticRegistry.\n * In dynamic mode, returns dynamicRegistry (which includes bootstrap entries)\n * or bootstrapRegistry if not yet reloaded.\n */\n private getCombinedRegistry(): GraphRegistry | undefined {\n if (!this.dynamicConfig) return this.staticRegistry;\n return this.dynamicRegistry ?? this.bootstrapRegistry;\n }\n\n // ---------------------------------------------------------------------------\n // Query dispatch\n // ---------------------------------------------------------------------------\n\n /**\n * Dispatch a query to the appropriate adapter based on queryMode.\n * Pipeline queries use the PipelineQueryAdapter; standard queries\n * use the FirestoreAdapter.\n */\n private executeQuery(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n if (this.pipelineAdapter) {\n return this.pipelineAdapter.query(filters, options);\n }\n return this.adapter.query(filters, options);\n }\n\n /**\n * Check whether a query's filter set is safe (matches a known index pattern).\n * Throws QuerySafetyError or logs a warning depending on scanProtection config.\n */\n private checkQuerySafety(filters: QueryFilter[], allowCollectionScan?: boolean): void {\n if (allowCollectionScan || this.scanProtection === 'off') return;\n\n const result = analyzeQuerySafety(filters);\n if (result.safe) return;\n\n if (this.scanProtection === 'error') {\n throw new QuerySafetyError(result.reason!);\n }\n\n // scanProtection === 'warn'\n console.warn(`[firegraph] Query safety warning: ${result.reason}`);\n }\n\n // ---------------------------------------------------------------------------\n // GraphReader\n // ---------------------------------------------------------------------------\n\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n const docId = computeNodeDocId(uid);\n return this.adapter.getDoc(docId);\n }\n\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n return this.adapter.getDoc(docId);\n }\n\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await this.getEdge(aUid, axbType, bUid);\n return record !== null;\n }\n\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.executeQuery(plan.filters, plan.options);\n }\n\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.executeQuery(plan.filters, plan.options);\n }\n\n // ---------------------------------------------------------------------------\n // GraphWriter\n // ---------------------------------------------------------------------------\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n const registry = this.getRegistryForType(aType);\n if (registry) {\n registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const adapter = this.getAdapterForType(aType);\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n await adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const registry = this.getRegistryForType(aType);\n if (registry) {\n registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const adapter = this.getAdapterForType(aType);\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n await adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n await this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n await this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n await this.adapter.deleteDoc(docId);\n }\n\n // ---------------------------------------------------------------------------\n // Transactions & Batches\n // ---------------------------------------------------------------------------\n\n async runTransaction<T>(fn: (tx: GraphTransaction) => Promise<T>): Promise<T> {\n return this.db.runTransaction(async (firestoreTx) => {\n const adapter = createTransactionAdapter(\n this.db,\n this.adapter.collectionPath,\n firestoreTx,\n );\n // Transactions always use standard queries — Pipeline is not transactionally bound\n const graphTx = new GraphTransactionImpl(adapter, this.getCombinedRegistry(), this.scanProtection, this.scopePath);\n return fn(graphTx);\n });\n }\n\n batch(): GraphBatch {\n const adapter = createBatchAdapter(this.db, this.adapter.collectionPath);\n return new GraphBatchImpl(adapter, this.getCombinedRegistry(), this.scopePath);\n }\n\n // ---------------------------------------------------------------------------\n // Subgraph\n // ---------------------------------------------------------------------------\n\n subgraph(parentNodeUid: string, name: string = 'graph'): GraphClient {\n if (!parentNodeUid || parentNodeUid.includes('/')) {\n throw new FiregraphError(\n `Invalid parentNodeUid for subgraph: \"${parentNodeUid}\". ` +\n 'Must be a non-empty string without \"/\".',\n 'INVALID_SUBGRAPH',\n );\n }\n if (name.includes('/')) {\n throw new FiregraphError(\n `Subgraph name must not contain \"/\": got \"${name}\". ` +\n 'Use chained .subgraph() calls for nested subgraphs.',\n 'INVALID_SUBGRAPH',\n );\n }\n const subCollectionPath = `${this.adapter.collectionPath}/${parentNodeUid}/${name}`;\n const newScopePath = this.scopePath ? `${this.scopePath}/${name}` : name;\n\n return new GraphClientImpl(\n this.db,\n subCollectionPath,\n {\n registry: this.getCombinedRegistry(),\n queryMode: this.queryMode === 'pipeline' ? 'pipeline' : 'standard',\n scanProtection: this.scanProtection,\n },\n newScopePath,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Collection group query\n // ---------------------------------------------------------------------------\n\n async findEdgesGlobal(\n params: FindEdgesParams,\n collectionName?: string,\n ): Promise<StoredGraphRecord[]> {\n const name = collectionName ?? this.adapter.collectionPath.split('/').pop()!;\n const plan = buildEdgeQueryPlan(params);\n\n if (plan.strategy === 'get') {\n throw new FiregraphError(\n 'findEdgesGlobal() requires a query, not a direct document lookup. ' +\n 'Omit one of aUid/axbType/bUid to force a query strategy.',\n 'INVALID_QUERY',\n );\n }\n\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n\n // Use Firestore collection group query\n const collectionGroupRef = this.db.collectionGroup(name);\n let q: import('@google-cloud/firestore').Query = collectionGroupRef;\n for (const f of plan.filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (plan.options?.orderBy) {\n q = q.orderBy(plan.options.orderBy.field, plan.options.orderBy.direction ?? 'asc');\n }\n if (plan.options?.limit !== undefined) {\n q = q.limit(plan.options.limit);\n }\n\n const snap = await q.get();\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n }\n\n // ---------------------------------------------------------------------------\n // Bulk operations\n // ---------------------------------------------------------------------------\n\n async removeNodeCascade(uid: string, options?: BulkOptions): Promise<CascadeResult> {\n return removeNodeCascadeImpl(this.db, this.adapter.collectionPath, this, uid, options);\n }\n\n async bulkRemoveEdges(params: FindEdgesParams, options?: BulkOptions): Promise<BulkResult> {\n return bulkRemoveEdgesImpl(this.db, this.adapter.collectionPath, this, params, options);\n }\n\n // ---------------------------------------------------------------------------\n // Dynamic registry methods\n // ---------------------------------------------------------------------------\n\n async defineNodeType(\n name: string,\n jsonSchema: object,\n description?: string,\n options?: DefineTypeOptions,\n ): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'defineNodeType() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n if (RESERVED_TYPE_NAMES.has(name)) {\n throw new DynamicRegistryError(\n `Cannot define type \"${name}\": this name is reserved for the meta-registry.`,\n );\n }\n\n const uid = generateDeterministicUid(META_NODE_TYPE, name);\n const data: Record<string, unknown> = { name, jsonSchema };\n if (description !== undefined) data.description = description;\n if (options?.titleField !== undefined) data.titleField = options.titleField;\n if (options?.subtitleField !== undefined) data.subtitleField = options.subtitleField;\n if (options?.viewTemplate !== undefined) data.viewTemplate = options.viewTemplate;\n if (options?.viewCss !== undefined) data.viewCss = options.viewCss;\n if (options?.allowedIn !== undefined) data.allowedIn = options.allowedIn;\n\n await this.putNode(META_NODE_TYPE, uid, data);\n }\n\n async defineEdgeType(\n name: string,\n topology: EdgeTopology,\n jsonSchema?: object,\n description?: string,\n options?: DefineTypeOptions,\n ): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'defineEdgeType() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n if (RESERVED_TYPE_NAMES.has(name)) {\n throw new DynamicRegistryError(\n `Cannot define type \"${name}\": this name is reserved for the meta-registry.`,\n );\n }\n\n const uid = generateDeterministicUid(META_EDGE_TYPE, name);\n const data: Record<string, unknown> = {\n name,\n from: topology.from,\n to: topology.to,\n };\n if (jsonSchema !== undefined) data.jsonSchema = jsonSchema;\n if (topology.inverseLabel !== undefined) data.inverseLabel = topology.inverseLabel;\n if (topology.targetGraph !== undefined) data.targetGraph = topology.targetGraph;\n if (description !== undefined) data.description = description;\n if (options?.titleField !== undefined) data.titleField = options.titleField;\n if (options?.subtitleField !== undefined) data.subtitleField = options.subtitleField;\n if (options?.viewTemplate !== undefined) data.viewTemplate = options.viewTemplate;\n if (options?.viewCss !== undefined) data.viewCss = options.viewCss;\n if (options?.allowedIn !== undefined) data.allowedIn = options.allowedIn;\n\n await this.putNode(META_EDGE_TYPE, uid, data);\n }\n\n async reloadRegistry(): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'reloadRegistry() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n const reader = this.createMetaReader();\n this.dynamicRegistry = await createRegistryFromGraph(reader);\n }\n\n /**\n * Create a GraphReader for the meta-collection.\n * If meta-collection is the same as main collection, returns `this`.\n * If separate, creates a lightweight reader wrapping the meta adapter.\n */\n private createMetaReader(): GraphReader {\n if (!this.metaAdapter) return this;\n\n const adapter = this.metaAdapter;\n const pipelineAdapter = this.metaPipelineAdapter;\n\n const executeMetaQuery = (\n filters: QueryFilter[],\n options?: QueryOptions,\n ): Promise<StoredGraphRecord[]> => {\n if (pipelineAdapter) return pipelineAdapter.query(filters, options);\n return adapter.query(filters, options);\n };\n\n return {\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n return adapter.getDoc(computeNodeDocId(uid));\n },\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n return adapter.getDoc(computeEdgeDocId(aUid, axbType, bUid));\n },\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await adapter.getDoc(computeEdgeDocId(aUid, axbType, bUid));\n return record !== null;\n },\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n return executeMetaQuery(plan.filters, plan.options);\n },\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n return executeMetaQuery(plan.filters, plan.options);\n },\n };\n }\n}\n\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options: GraphClientOptions & { registryMode: DynamicRegistryConfig },\n): DynamicGraphClient;\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n): GraphClient;\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n): GraphClient | DynamicGraphClient {\n return new GraphClientImpl(db, collectionPath, options);\n}\n","import { createHash } from 'node:crypto';\nimport { SHARD_SEPARATOR } from './internal/constants.js';\n\nexport function computeNodeDocId(uid: string): string {\n return uid;\n}\n\nexport function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string {\n const composite = `${aUid}${SHARD_SEPARATOR}${axbType}${SHARD_SEPARATOR}${bUid}`;\n const hash = createHash('sha256').update(composite).digest('hex');\n const shard = hash[0];\n return `${shard}${SHARD_SEPARATOR}${aUid}${SHARD_SEPARATOR}${axbType}${SHARD_SEPARATOR}${bUid}`;\n}\n","export const NODE_RELATION = 'is';\n\n/**\n * Default result limit applied to findEdges/findNodes queries\n * when no explicit limit is provided. Prevents unbounded result sets\n * that could be expensive on Enterprise Firestore.\n */\nexport const DEFAULT_QUERY_LIMIT = 500;\n\n/**\n * Fields that are part of the firegraph record structure (not user data).\n * Used by the query planner and safety analysis to distinguish builtin\n * fields from data.* fields.\n */\nexport const BUILTIN_FIELDS = new Set([\n 'aType', 'aUid', 'axbType', 'bType', 'bUid', 'createdAt', 'updatedAt',\n]);\n\nexport const SHARD_ALGORITHM = 'sha256';\nexport const SHARD_SEPARATOR = ':';\nexport const SHARD_BUCKETS = 16;\n","import { FieldValue } from '@google-cloud/firestore';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { GraphRecord } from './types.js';\n\nexport function buildNodeRecord(\n aType: string,\n uid: string,\n data: Record<string, unknown>,\n): GraphRecord {\n const now = FieldValue.serverTimestamp();\n return {\n aType,\n aUid: uid,\n axbType: NODE_RELATION,\n bType: aType,\n bUid: uid,\n data,\n createdAt: now,\n updatedAt: now,\n };\n}\n\nexport function buildEdgeRecord(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n): GraphRecord {\n const now = FieldValue.serverTimestamp();\n return {\n aType,\n aUid,\n axbType,\n bType,\n bUid,\n data,\n createdAt: now,\n updatedAt: now,\n };\n}\n","export class FiregraphError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'FiregraphError';\n }\n}\n\nexport class NodeNotFoundError extends FiregraphError {\n constructor(uid: string) {\n super(`Node not found: ${uid}`, 'NODE_NOT_FOUND');\n this.name = 'NodeNotFoundError';\n }\n}\n\nexport class EdgeNotFoundError extends FiregraphError {\n constructor(aUid: string, axbType: string, bUid: string) {\n super(`Edge not found: ${aUid} -[${axbType}]-> ${bUid}`, 'EDGE_NOT_FOUND');\n this.name = 'EdgeNotFoundError';\n }\n}\n\nexport class ValidationError extends FiregraphError {\n constructor(\n message: string,\n public readonly details?: unknown,\n ) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class RegistryViolationError extends FiregraphError {\n constructor(aType: string, axbType: string, bType: string) {\n super(\n `Unregistered triple: (${aType}) -[${axbType}]-> (${bType})`,\n 'REGISTRY_VIOLATION',\n );\n this.name = 'RegistryViolationError';\n }\n}\n\nexport class InvalidQueryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'INVALID_QUERY');\n this.name = 'InvalidQueryError';\n }\n}\n\nexport class TraversalError extends FiregraphError {\n constructor(message: string) {\n super(message, 'TRAVERSAL_ERROR');\n this.name = 'TraversalError';\n }\n}\n\nexport class DynamicRegistryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'DYNAMIC_REGISTRY_ERROR');\n this.name = 'DynamicRegistryError';\n }\n}\n\nexport class QuerySafetyError extends FiregraphError {\n constructor(message: string) {\n super(message, 'QUERY_SAFETY');\n this.name = 'QuerySafetyError';\n }\n}\n\nexport class RegistryScopeError extends FiregraphError {\n constructor(aType: string, axbType: string, bType: string, scopePath: string, allowedIn: string[]) {\n super(\n `Type (${aType}) -[${axbType}]-> (${bType}) is not allowed at scope \"${scopePath || 'root'}\". ` +\n `Allowed in: [${allowedIn.join(', ')}]`,\n 'REGISTRY_SCOPE',\n );\n this.name = 'RegistryScopeError';\n }\n}\n","import { NODE_RELATION, DEFAULT_QUERY_LIMIT, BUILTIN_FIELDS } from './internal/constants.js';\nimport { computeEdgeDocId } from './docid.js';\nimport { InvalidQueryError } from './errors.js';\nimport type { FindEdgesParams, FindNodesParams, QueryPlan, QueryFilter } from './types.js';\n\nexport function buildEdgeQueryPlan(params: FindEdgesParams): QueryPlan {\n const { aType, aUid, axbType, bType, bUid, limit, orderBy } = params;\n\n if (aUid && axbType && bUid && !params.where?.length) {\n return { strategy: 'get', docId: computeEdgeDocId(aUid, axbType, bUid) };\n }\n\n const filters: QueryFilter[] = [];\n\n if (aType) filters.push({ field: 'aType', op: '==', value: aType });\n if (aUid) filters.push({ field: 'aUid', op: '==', value: aUid });\n if (axbType) filters.push({ field: 'axbType', op: '==', value: axbType });\n if (bType) filters.push({ field: 'bType', op: '==', value: bType });\n if (bUid) filters.push({ field: 'bUid', op: '==', value: bUid });\n\n if (params.where) {\n for (const clause of params.where) {\n const field = BUILTIN_FIELDS.has(clause.field) ? clause.field\n : clause.field.startsWith('data.') ? clause.field : `data.${clause.field}`;\n filters.push({ field, op: clause.op, value: clause.value });\n }\n }\n\n if (filters.length === 0) {\n throw new InvalidQueryError('findEdges requires at least one filter parameter');\n }\n\n // limit: undefined → apply DEFAULT_QUERY_LIMIT\n // limit: 0 → no limit (unlimited, used by internal bulk operations)\n // limit: N → use N\n const effectiveLimit = limit === undefined ? DEFAULT_QUERY_LIMIT : (limit || undefined);\n return { strategy: 'query', filters, options: { limit: effectiveLimit, orderBy } };\n}\n\nexport function buildNodeQueryPlan(params: FindNodesParams): QueryPlan {\n const { aType, limit, orderBy } = params;\n\n const filters: QueryFilter[] = [\n { field: 'aType', op: '==', value: aType },\n { field: 'axbType', op: '==', value: NODE_RELATION },\n ];\n\n if (params.where) {\n for (const clause of params.where) {\n const field = BUILTIN_FIELDS.has(clause.field) ? clause.field\n : clause.field.startsWith('data.') ? clause.field : `data.${clause.field}`;\n filters.push({ field, op: clause.op, value: clause.value });\n }\n }\n\n const effectiveLimit = limit === undefined ? DEFAULT_QUERY_LIMIT : (limit || undefined);\n return { strategy: 'query', filters, options: { limit: effectiveLimit, orderBy } };\n}\n","import type { Firestore, Query, Transaction } from '@google-cloud/firestore';\nimport type { StoredGraphRecord, QueryFilter, QueryOptions } from '../types.js';\n\nexport interface FirestoreAdapter {\n collectionPath: string;\n getDoc(docId: string): Promise<StoredGraphRecord | null>;\n setDoc(docId: string, data: Record<string, unknown>): Promise<void>;\n updateDoc(docId: string, data: Record<string, unknown>): Promise<void>;\n deleteDoc(docId: string): Promise<void>;\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\nexport function createFirestoreAdapter(\n db: Firestore,\n collectionPath: string,\n): FirestoreAdapter {\n const collectionRef = db.collection(collectionPath);\n\n return {\n collectionPath,\n\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n const snap = await collectionRef.doc(docId).get();\n if (!snap.exists) return null;\n return snap.data() as StoredGraphRecord;\n },\n\n async setDoc(docId: string, data: Record<string, unknown>): Promise<void> {\n await collectionRef.doc(docId).set(data);\n },\n\n async updateDoc(docId: string, data: Record<string, unknown>): Promise<void> {\n await collectionRef.doc(docId).update(data);\n },\n\n async deleteDoc(docId: string): Promise<void> {\n await collectionRef.doc(docId).delete();\n },\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n let q: Query = collectionRef;\n for (const f of filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (options?.orderBy) {\n q = q.orderBy(options.orderBy.field, options.orderBy.direction ?? 'asc');\n }\n if (options?.limit !== undefined) {\n q = q.limit(options.limit);\n }\n const snap = await q.get();\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n },\n };\n}\n\nexport interface TransactionAdapter {\n getDoc(docId: string): Promise<StoredGraphRecord | null>;\n setDoc(docId: string, data: Record<string, unknown>): void;\n updateDoc(docId: string, data: Record<string, unknown>): void;\n deleteDoc(docId: string): void;\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\nexport function createTransactionAdapter(\n db: Firestore,\n collectionPath: string,\n tx: Transaction,\n): TransactionAdapter {\n const collectionRef = db.collection(collectionPath);\n\n return {\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n const snap = await tx.get(collectionRef.doc(docId));\n if (!snap.exists) return null;\n return snap.data() as StoredGraphRecord;\n },\n\n setDoc(docId: string, data: Record<string, unknown>): void {\n tx.set(collectionRef.doc(docId), data);\n },\n\n updateDoc(docId: string, data: Record<string, unknown>): void {\n tx.update(collectionRef.doc(docId), data);\n },\n\n deleteDoc(docId: string): void {\n tx.delete(collectionRef.doc(docId));\n },\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n let q: Query = collectionRef;\n for (const f of filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (options?.orderBy) {\n q = q.orderBy(options.orderBy.field, options.orderBy.direction ?? 'asc');\n }\n if (options?.limit !== undefined) {\n q = q.limit(options.limit);\n }\n const snap = await tx.get(q);\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n },\n };\n}\n\nexport interface BatchAdapter {\n setDoc(docId: string, data: Record<string, unknown>): void;\n updateDoc(docId: string, data: Record<string, unknown>): void;\n deleteDoc(docId: string): void;\n commit(): Promise<void>;\n}\n\nexport function createBatchAdapter(\n db: Firestore,\n collectionPath: string,\n): BatchAdapter {\n const collectionRef = db.collection(collectionPath);\n const batch = db.batch();\n\n return {\n setDoc(docId: string, data: Record<string, unknown>): void {\n batch.set(collectionRef.doc(docId), data);\n },\n\n updateDoc(docId: string, data: Record<string, unknown>): void {\n batch.update(collectionRef.doc(docId), data);\n },\n\n deleteDoc(docId: string): void {\n batch.delete(collectionRef.doc(docId));\n },\n\n async commit(): Promise<void> {\n await batch.commit();\n },\n };\n}\n","/**\n * Pipeline query adapter — translates QueryFilter[] to Firestore Pipeline\n * expressions and executes them via db.pipeline().\n *\n * Only handles query() — doc-level operations (get/set/update/delete) stay\n * on the standard FirestoreAdapter.\n */\nimport type { Firestore } from '@google-cloud/firestore';\nimport type { StoredGraphRecord, QueryFilter, QueryOptions } from '../types.js';\n\n/**\n * Minimal interface for the Pipeline query adapter.\n * Only implements the query path — doc operations are handled by FirestoreAdapter.\n */\nexport interface PipelineQueryAdapter {\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\n/**\n * Lazily loaded Pipelines module. We use dynamic import so that standard-mode\n * users (and the emulator) don't pull in pipeline-related code at module load.\n */\nlet _Pipelines: typeof import('@google-cloud/firestore').Pipelines | null = null;\n\nasync function getPipelines(): Promise<typeof import('@google-cloud/firestore').Pipelines> {\n if (!_Pipelines) {\n const mod = await import('@google-cloud/firestore');\n _Pipelines = mod.Pipelines;\n }\n return _Pipelines;\n}\n\ntype PipelinesType = typeof import('@google-cloud/firestore').Pipelines;\ntype BooleanExpr = import('@google-cloud/firestore').Pipelines.BooleanExpression;\n\n/**\n * Maps a QueryFilter to a Pipeline BooleanExpression.\n *\n * Uses the string-based overloads (e.g. `equal(fieldName, value)`) which\n * accept `unknown` values, avoiding type issues with `constant()` overloads.\n */\nfunction buildFilterExpression(\n P: PipelinesType,\n filter: QueryFilter,\n): BooleanExpr {\n const { field: fieldName, op, value } = filter;\n\n switch (op) {\n case '==':\n return P.equal(fieldName, value);\n case '!=':\n return P.notEqual(fieldName, value);\n case '<':\n return P.lessThan(fieldName, value);\n case '<=':\n return P.lessThanOrEqual(fieldName, value);\n case '>':\n return P.greaterThan(fieldName, value);\n case '>=':\n return P.greaterThanOrEqual(fieldName, value);\n case 'in':\n return P.equalAny(fieldName, value as Array<unknown>);\n case 'not-in':\n return P.notEqualAny(fieldName, value as Array<unknown>);\n case 'array-contains':\n return P.arrayContains(fieldName, value);\n case 'array-contains-any':\n return P.arrayContainsAny(fieldName, value as Array<unknown>);\n default:\n throw new Error(`Unsupported filter op for pipeline mode: ${op}`);\n }\n}\n\nexport function createPipelineQueryAdapter(\n db: Firestore,\n collectionPath: string,\n): PipelineQueryAdapter {\n return {\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n const P = await getPipelines();\n\n // Build pipeline\n let pipeline = db.pipeline().collection(collectionPath);\n\n // Apply filters\n if (filters.length === 1) {\n pipeline = pipeline.where(buildFilterExpression(P, filters[0]));\n } else if (filters.length > 1) {\n const [first, second, ...rest] = filters.map(f => buildFilterExpression(P, f));\n pipeline = pipeline.where(P.and(first, second, ...rest));\n }\n\n // Apply sort\n if (options?.orderBy) {\n const f = P.field(options.orderBy.field);\n const ordering = options.orderBy.direction === 'desc'\n ? f.descending()\n : f.ascending();\n pipeline = pipeline.sort(ordering);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n pipeline = pipeline.limit(options.limit);\n }\n\n const snap = await pipeline.execute();\n return snap.results.map(r => r.data() as StoredGraphRecord);\n },\n };\n}\n","import { FieldValue } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport { QuerySafetyError } from './errors.js';\nimport { analyzeQuerySafety } from './query-safety.js';\nimport type { TransactionAdapter } from './internal/firestore-adapter.js';\nimport type {\n GraphTransaction,\n GraphRegistry,\n StoredGraphRecord,\n FindEdgesParams,\n FindNodesParams,\n ScanProtection,\n QueryFilter,\n} from './types.js';\n\nexport class GraphTransactionImpl implements GraphTransaction {\n constructor(\n private readonly adapter: TransactionAdapter,\n private readonly registry?: GraphRegistry,\n private readonly scanProtection: ScanProtection = 'error',\n private readonly scopePath: string = '',\n ) {}\n\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n const docId = computeNodeDocId(uid);\n return this.adapter.getDoc(docId);\n }\n\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n return this.adapter.getDoc(docId);\n }\n\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await this.getEdge(aUid, axbType, bUid);\n return record !== null;\n }\n\n private checkQuerySafety(filters: QueryFilter[], allowCollectionScan?: boolean): void {\n if (allowCollectionScan || this.scanProtection === 'off') return;\n\n const result = analyzeQuerySafety(filters);\n if (result.safe) return;\n\n if (this.scanProtection === 'error') {\n throw new QuerySafetyError(result.reason!);\n }\n\n // scanProtection === 'warn'\n console.warn(`[firegraph] Query safety warning: ${result.reason}`);\n }\n\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.adapter.query(plan.filters, plan.options);\n }\n\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.adapter.query(plan.filters, plan.options);\n }\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n this.adapter.deleteDoc(docId);\n }\n}\n","import { BUILTIN_FIELDS } from './internal/constants.js';\nimport type { QueryFilter } from './types.js';\n\n/**\n * Result of analyzing a query for collection scan risk.\n */\nexport interface QuerySafetyResult {\n /** Whether the query matches a known indexed pattern. */\n safe: boolean;\n /** Human-readable explanation when the query is unsafe. */\n reason?: string;\n}\n\n/**\n * Known composite index patterns that prevent full collection scans.\n * Each pattern is a set of field names that must ALL be present in the\n * query filters. Order within the set doesn't matter — what matters is\n * that the Firestore composite index covers the combination.\n *\n * These correspond to the indexes in firestore.indexes.json:\n * (aUid, axbType) — forward edge lookup\n * (axbType, bUid) — reverse edge lookup\n * (aType, axbType) — type-scoped queries + findNodes\n * (axbType, bType) — edge type + target type\n */\nconst SAFE_INDEX_PATTERNS: ReadonlyArray<ReadonlySet<string>> = [\n new Set(['aUid', 'axbType']),\n new Set(['axbType', 'bUid']),\n new Set(['aType', 'axbType']),\n new Set(['axbType', 'bType']),\n];\n\n/**\n * Analyzes a set of query filters to determine whether the query would\n * likely cause a full collection scan on Firestore Enterprise.\n *\n * A query is considered \"safe\" if the builtin fields present in the filters\n * match at least one known composite index pattern. Queries that only use\n * `data.*` fields without a safe base pattern are flagged as unsafe.\n */\nexport function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult {\n // Extract the set of builtin fields being filtered on (equality checks are\n // the primary index-usable operations, but we're generous here and count\n // any filter on a builtin field as potentially index-backed).\n const builtinFieldsPresent = new Set<string>();\n let hasDataFilters = false;\n\n for (const f of filters) {\n if (BUILTIN_FIELDS.has(f.field)) {\n builtinFieldsPresent.add(f.field);\n } else {\n // data.* or other non-builtin fields\n hasDataFilters = true;\n }\n }\n\n // Check if the builtin fields match any known safe index pattern.\n // A pattern is \"matched\" if all fields in the pattern are present in the query.\n for (const pattern of SAFE_INDEX_PATTERNS) {\n let matched = true;\n for (const field of pattern) {\n if (!builtinFieldsPresent.has(field)) {\n matched = false;\n break;\n }\n }\n if (matched) {\n // Even with data.* filters, the base index narrows the scan significantly.\n // The data.* filters are applied as post-filters on the index results.\n return { safe: true };\n }\n }\n\n // No safe pattern matched — build an explanation.\n const presentFields = [...builtinFieldsPresent];\n if (presentFields.length === 0 && hasDataFilters) {\n return {\n safe: false,\n reason:\n 'Query filters only use data.* fields with no builtin field constraints. ' +\n 'This requires a full collection scan. Add aType, aUid, axbType, bType, or bUid filters, ' +\n 'or set allowCollectionScan: true.',\n };\n }\n\n if (hasDataFilters) {\n return {\n safe: false,\n reason:\n `Query filters on [${presentFields.join(', ')}] do not match any indexed pattern. ` +\n 'data.* filters without an indexed base require a full collection scan. ' +\n `Safe patterns: (aUid + axbType), (axbType + bUid), (aType + axbType), (axbType + bType). ` +\n 'Set allowCollectionScan: true to override.',\n };\n }\n\n return {\n safe: false,\n reason:\n `Query filters on [${presentFields.join(', ')}] do not match any indexed pattern. ` +\n 'This may cause a full collection scan on Firestore Enterprise. ' +\n `Safe patterns: (aUid + axbType), (axbType + bUid), (aType + axbType), (axbType + bType). ` +\n 'Set allowCollectionScan: true to override.',\n };\n}\n","import { FieldValue } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { BatchAdapter } from './internal/firestore-adapter.js';\nimport type { GraphBatch, GraphRegistry } from './types.js';\n\nexport class GraphBatchImpl implements GraphBatch {\n constructor(\n private readonly adapter: BatchAdapter,\n private readonly registry?: GraphRegistry,\n private readonly scopePath: string = '',\n ) {}\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n this.adapter.deleteDoc(docId);\n }\n\n async commit(): Promise<void> {\n await this.adapter.commit();\n }\n}\n","import type { Firestore } from '@google-cloud/firestore';\nimport { computeEdgeDocId, computeNodeDocId } from './docid.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type {\n StoredGraphRecord,\n FindEdgesParams,\n BulkOptions,\n BulkResult,\n BulkBatchError,\n CascadeResult,\n GraphReader,\n} from './types.js';\n\nconst MAX_BATCH_SIZE = 500;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 200;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Splits an array into chunks of at most `size` elements.\n */\nfunction chunk<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size));\n }\n return chunks;\n}\n\n/**\n * Deletes a list of document IDs in chunked Firestore batches with retries.\n */\nexport async function bulkDeleteDocIds(\n db: Firestore,\n collectionPath: string,\n docIds: string[],\n options?: BulkOptions,\n): Promise<BulkResult> {\n if (docIds.length === 0) {\n return { deleted: 0, batches: 0, errors: [] };\n }\n\n const batchSize = Math.min(options?.batchSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const onProgress = options?.onProgress;\n\n const chunks = chunk(docIds, batchSize);\n const errors: BulkBatchError[] = [];\n let deleted = 0;\n let completedBatches = 0;\n\n for (let i = 0; i < chunks.length; i++) {\n const ids = chunks[i];\n let committed = false;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const batch = db.batch();\n const collectionRef = db.collection(collectionPath);\n for (const id of ids) {\n batch.delete(collectionRef.doc(id));\n }\n await batch.commit();\n committed = true;\n deleted += ids.length;\n break;\n } catch (err) {\n if (attempt < maxRetries) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n await sleep(delay);\n } else {\n errors.push({\n batchIndex: i,\n error: err instanceof Error ? err : new Error(String(err)),\n operationCount: ids.length,\n });\n }\n }\n }\n\n if (committed) {\n completedBatches++;\n }\n\n if (onProgress) {\n onProgress({\n completedBatches,\n totalBatches: chunks.length,\n deletedSoFar: deleted,\n });\n }\n }\n\n return { deleted, batches: completedBatches, errors };\n}\n\n/**\n * Finds all edges matching `params`, then deletes them in chunked batches.\n */\nexport async function bulkRemoveEdges(\n db: Firestore,\n collectionPath: string,\n reader: GraphReader,\n params: FindEdgesParams,\n options?: BulkOptions,\n): Promise<BulkResult> {\n // Override default query limit for bulk deletion — we need all matching edges.\n // limit: 0 bypasses DEFAULT_QUERY_LIMIT; an explicit user limit is preserved.\n // allowCollectionScan: true — bulk deletion inherently implies scanning.\n const effectiveParams = params.limit !== undefined\n ? { ...params, allowCollectionScan: params.allowCollectionScan ?? true }\n : { ...params, limit: 0, allowCollectionScan: params.allowCollectionScan ?? true };\n const edges = await reader.findEdges(effectiveParams);\n const docIds = edges.map((e) => computeEdgeDocId(e.aUid, e.axbType, e.bUid));\n return bulkDeleteDocIds(db, collectionPath, docIds, options);\n}\n\n/** Result from recursive subcollection deletion. */\ninterface SubcollectionDeleteResult {\n deleted: number;\n errors: BulkBatchError[];\n}\n\n/**\n * Recursively delete all documents in all subcollections under a given document.\n * Uses `listCollections()` (Admin SDK) to discover subcollections, then for each\n * subcollection: recurse into each document's subcollections first (depth-first),\n * then bulk delete all documents in the subcollection.\n *\n * The `onProgress` callback is intentionally NOT forwarded to subcollection\n * deletes to avoid confusing callers with interleaved progress from different\n * collection depths.\n */\nasync function deleteSubcollectionsRecursive(\n db: Firestore,\n collectionPath: string,\n docId: string,\n options?: BulkOptions,\n): Promise<SubcollectionDeleteResult> {\n const docRef = db.collection(collectionPath).doc(docId);\n const subcollections = await docRef.listCollections();\n\n if (subcollections.length === 0) return { deleted: 0, errors: [] };\n\n let totalDeleted = 0;\n const allErrors: BulkBatchError[] = [];\n\n // Strip onProgress for subcollection deletes — callers should only see\n // top-level progress, not interleaved reports from nested depths.\n const subOptions: BulkOptions | undefined = options\n ? { batchSize: options.batchSize, maxRetries: options.maxRetries }\n : undefined;\n\n for (const subCollRef of subcollections) {\n const subCollPath = subCollRef.path;\n // List all documents in this subcollection\n const snapshot = await subCollRef.select().get();\n const subDocIds = snapshot.docs.map((d) => d.id);\n\n // Depth-first: recurse into each document's subcollections\n for (const subDocId of subDocIds) {\n const subResult = await deleteSubcollectionsRecursive(db, subCollPath, subDocId, subOptions);\n totalDeleted += subResult.deleted;\n allErrors.push(...subResult.errors);\n }\n\n // Now delete all documents in this subcollection\n if (subDocIds.length > 0) {\n const result = await bulkDeleteDocIds(db, subCollPath, subDocIds, subOptions);\n totalDeleted += result.deleted;\n allErrors.push(...result.errors);\n }\n }\n\n return { deleted: totalDeleted, errors: allErrors };\n}\n\n/**\n * Deletes a node and all of its outgoing and incoming edges.\n *\n * Edges are deleted first in chunked batches, then the node document\n * is deleted in the final batch. This is NOT atomic across batches —\n * if a batch fails after retries, remaining batches still execute.\n *\n * By default, subcollections (subgraphs) under the node's document are\n * recursively deleted. Set `options.deleteSubcollections` to `false` to skip.\n */\nexport async function removeNodeCascade(\n db: Firestore,\n collectionPath: string,\n reader: GraphReader,\n uid: string,\n options?: BulkOptions,\n): Promise<CascadeResult> {\n // Find all edges touching this node (outgoing + incoming).\n // Filter out the node's own self-loop record (axbType === 'is').\n // These queries intentionally scan broadly — allowCollectionScan bypasses safety checks.\n // limit: 0 bypasses the DEFAULT_QUERY_LIMIT to ensure we find all edges.\n const [outgoingRaw, incomingRaw] = await Promise.all([\n reader.findEdges({ aUid: uid, allowCollectionScan: true, limit: 0 }),\n reader.findEdges({ bUid: uid, allowCollectionScan: true, limit: 0 }),\n ]);\n const outgoing = outgoingRaw.filter((e) => e.axbType !== NODE_RELATION);\n const incoming = incomingRaw.filter((e) => e.axbType !== NODE_RELATION);\n\n // Deduplicate: a self-referencing edge could appear in both lists.\n const edgeDocIdSet = new Set<string>();\n const allEdges: StoredGraphRecord[] = [];\n for (const edge of [...outgoing, ...incoming]) {\n const docId = computeEdgeDocId(edge.aUid, edge.axbType, edge.bUid);\n if (!edgeDocIdSet.has(docId)) {\n edgeDocIdSet.add(docId);\n allEdges.push(edge);\n }\n }\n\n // Delete subcollections (subgraphs) under this node's document (depth-first).\n const shouldDeleteSubcollections = options?.deleteSubcollections !== false;\n const nodeDocId = computeNodeDocId(uid);\n let subcollectionResult: SubcollectionDeleteResult = { deleted: 0, errors: [] };\n\n if (shouldDeleteSubcollections) {\n subcollectionResult = await deleteSubcollectionsRecursive(\n db, collectionPath, nodeDocId, options,\n );\n }\n\n // Build doc IDs: edges first, then the node last.\n const edgeDocIds = allEdges.map((e) => computeEdgeDocId(e.aUid, e.axbType, e.bUid));\n const allDocIds = [...edgeDocIds, nodeDocId];\n\n // Wrap the progress callback to track overall progress.\n const batchSize = Math.min(options?.batchSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const result = await bulkDeleteDocIds(db, collectionPath, allDocIds, {\n ...options,\n batchSize,\n });\n\n // Determine if the node doc was in a failed batch.\n // The node is always in the last doc ID. If the last batch errored, node wasn't deleted.\n const totalChunks = Math.ceil(allDocIds.length / batchSize);\n const nodeChunkIndex = totalChunks - 1;\n const nodeDeleted = !result.errors.some((e) => e.batchIndex === nodeChunkIndex);\n\n // edgesDeleted counts only top-level edges (not subcollection docs).\n // deleted includes everything: top-level edges + node + subcollection docs.\n const topLevelEdgesDeleted = nodeDeleted ? result.deleted - 1 : result.deleted;\n\n return {\n deleted: result.deleted + subcollectionResult.deleted,\n batches: result.batches,\n errors: [...result.errors, ...subcollectionResult.errors],\n edgesDeleted: topLevelEdgesDeleted,\n nodeDeleted,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { createRegistry } from './registry.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type {\n GraphReader,\n GraphRegistry,\n RegistryEntry,\n NodeTypeData,\n EdgeTypeData,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// Meta-type constants\n// ---------------------------------------------------------------------------\n\n/** The aType used for node type definition meta-nodes. */\nexport const META_NODE_TYPE = 'nodeType';\n\n/** The aType used for edge type definition meta-nodes. */\nexport const META_EDGE_TYPE = 'edgeType';\n\n// ---------------------------------------------------------------------------\n// JSON Schemas for meta-type data payloads\n// ---------------------------------------------------------------------------\n\n/** JSON Schema for the `data` payload of a `nodeType` meta-node. */\nexport const NODE_TYPE_SCHEMA: object = {\n type: 'object',\n required: ['name', 'jsonSchema'],\n properties: {\n name: { type: 'string', minLength: 1 },\n jsonSchema: { type: 'object' },\n description: { type: 'string' },\n titleField: { type: 'string' },\n subtitleField: { type: 'string' },\n viewTemplate: { type: 'string' },\n viewCss: { type: 'string' },\n allowedIn: { type: 'array', items: { type: 'string', minLength: 1 } },\n },\n additionalProperties: false,\n};\n\n/** JSON Schema for the `data` payload of an `edgeType` meta-node. */\nexport const EDGE_TYPE_SCHEMA: object = {\n type: 'object',\n required: ['name', 'from', 'to'],\n properties: {\n name: { type: 'string', minLength: 1 },\n from: {\n oneOf: [\n { type: 'string', minLength: 1 },\n { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1 },\n ],\n },\n to: {\n oneOf: [\n { type: 'string', minLength: 1 },\n { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1 },\n ],\n },\n jsonSchema: { type: 'object' },\n inverseLabel: { type: 'string' },\n description: { type: 'string' },\n titleField: { type: 'string' },\n subtitleField: { type: 'string' },\n viewTemplate: { type: 'string' },\n viewCss: { type: 'string' },\n allowedIn: { type: 'array', items: { type: 'string', minLength: 1 } },\n targetGraph: { type: 'string', minLength: 1, pattern: '^[^/]+$' },\n },\n additionalProperties: false,\n};\n\n// ---------------------------------------------------------------------------\n// Bootstrap registry\n// ---------------------------------------------------------------------------\n\n/** Registry entries for the two meta-types (always present). */\nexport const BOOTSTRAP_ENTRIES: readonly RegistryEntry[] = [\n {\n aType: META_NODE_TYPE,\n axbType: NODE_RELATION,\n bType: META_NODE_TYPE,\n jsonSchema: NODE_TYPE_SCHEMA,\n description: 'Meta-type: defines a node type',\n },\n {\n aType: META_EDGE_TYPE,\n axbType: NODE_RELATION,\n bType: META_EDGE_TYPE,\n jsonSchema: EDGE_TYPE_SCHEMA,\n description: 'Meta-type: defines an edge type',\n },\n];\n\n/**\n * Build the bootstrap registry that validates meta-type writes.\n * This is always available, even before any dynamic types are loaded.\n */\nexport function createBootstrapRegistry(): GraphRegistry {\n return createRegistry([...BOOTSTRAP_ENTRIES]);\n}\n\n// ---------------------------------------------------------------------------\n// Deterministic UID generation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a deterministic UID for a meta-type definition.\n * This ensures that defining the same type name always targets the same\n * Firestore document, enabling upsert semantics.\n *\n * Format: 21-char base64url substring of SHA-256(`metaType:name`).\n */\nexport function generateDeterministicUid(metaType: string, name: string): string {\n const hash = createHash('sha256')\n .update(`${metaType}:${name}`)\n .digest('base64url');\n return hash.slice(0, 21);\n}\n\n// ---------------------------------------------------------------------------\n// createRegistryFromGraph\n// ---------------------------------------------------------------------------\n\n/**\n * Read meta-type nodes from the graph and compile them into a GraphRegistry.\n *\n * The returned registry includes both the dynamic entries AND the bootstrap\n * meta-type entries, so meta-type writes remain validateable after a reload.\n *\n * @param reader - A GraphReader pointed at the collection containing meta-nodes.\n */\nexport async function createRegistryFromGraph(\n reader: GraphReader,\n): Promise<GraphRegistry> {\n const [nodeTypes, edgeTypes] = await Promise.all([\n reader.findNodes({ aType: META_NODE_TYPE }),\n reader.findNodes({ aType: META_EDGE_TYPE }),\n ]);\n\n const entries: RegistryEntry[] = [...BOOTSTRAP_ENTRIES];\n\n // Convert nodeType records → self-loop RegistryEntries\n for (const record of nodeTypes) {\n const data = record.data as unknown as NodeTypeData;\n entries.push({\n aType: data.name,\n axbType: NODE_RELATION,\n bType: data.name,\n jsonSchema: data.jsonSchema,\n description: data.description,\n titleField: data.titleField,\n subtitleField: data.subtitleField,\n allowedIn: data.allowedIn,\n });\n }\n\n // Convert edgeType records → RegistryEntries (expand from/to arrays)\n for (const record of edgeTypes) {\n const data = record.data as unknown as EdgeTypeData;\n const fromTypes = Array.isArray(data.from) ? data.from : [data.from];\n const toTypes = Array.isArray(data.to) ? data.to : [data.to];\n\n for (const aType of fromTypes) {\n for (const bType of toTypes) {\n entries.push({\n aType,\n axbType: data.name,\n bType,\n jsonSchema: data.jsonSchema,\n description: data.description,\n inverseLabel: data.inverseLabel,\n titleField: data.titleField,\n subtitleField: data.subtitleField,\n allowedIn: data.allowedIn,\n targetGraph: data.targetGraph,\n });\n }\n }\n }\n\n return createRegistry(entries);\n}\n","/**\n * JSON Schema validation and introspection utilities.\n *\n * Standard JSON Schema validation and introspection\n * processing. Uses ajv for validation and a recursive walker for converting\n * JSON Schema properties into FieldMeta objects for editor form generation.\n */\n\nimport Ajv from 'ajv';\nimport { ValidationError } from './errors.js';\n\n// ---------------------------------------------------------------------------\n// FieldMeta types (previously in editor/server/schema-introspect.ts)\n// ---------------------------------------------------------------------------\n\nexport interface FieldMeta {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'unknown';\n required: boolean;\n description?: string;\n enumValues?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n min?: number;\n max?: number;\n isInt?: boolean;\n itemMeta?: FieldMeta;\n fields?: FieldMeta[];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\n\n/**\n * Compile a JSON Schema into a validation function.\n * The returned function throws `ValidationError` if data is invalid.\n */\nexport function compileSchema(\n schema: object,\n label?: string,\n): (data: unknown) => void {\n const validate = ajv.compile(schema);\n return (data: unknown) => {\n if (!validate(data)) {\n const errors = validate.errors ?? [];\n const messages = errors\n .map((err) => `${err.instancePath || '/'}${err.message ? ': ' + err.message : ''}`)\n .join('; ');\n throw new ValidationError(\n `Data validation failed${label ? ' for ' + label : ''}: ${messages}`,\n errors,\n );\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema → FieldMeta introspection\n// ---------------------------------------------------------------------------\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Convert a JSON Schema (expected to be `type: \"object\"`) into `FieldMeta[]`\n * suitable for the editor's SchemaForm component.\n */\nexport function jsonSchemaToFieldMeta(schema: any): FieldMeta[] {\n if (!schema || schema.type !== 'object' || !schema.properties) return [];\n\n const requiredSet = new Set<string>(\n Array.isArray(schema.required) ? schema.required : [],\n );\n\n return Object.entries(schema.properties).map(([name, prop]) =>\n propertyToFieldMeta(name, prop as any, requiredSet.has(name)),\n );\n}\n\n/**\n * Convert a single JSON Schema property into a `FieldMeta`.\n */\nfunction propertyToFieldMeta(\n name: string,\n prop: any,\n required: boolean,\n): FieldMeta {\n if (!prop) return { name, type: 'unknown', required };\n\n // Handle enum (can appear with or without type)\n if (Array.isArray(prop.enum)) {\n return {\n name,\n type: 'enum',\n required,\n enumValues: prop.enum as string[],\n description: prop.description,\n };\n }\n\n // Handle oneOf/anyOf for nullable patterns like { oneOf: [{type:'string'}, {type:'null'}] }\n if (Array.isArray(prop.oneOf) || Array.isArray(prop.anyOf)) {\n const variants = (prop.oneOf ?? prop.anyOf) as any[];\n const nonNull = variants.filter((v: any) => v.type !== 'null');\n if (nonNull.length === 1) {\n // Nullable wrapper — unwrap and mark as optional\n return propertyToFieldMeta(name, nonNull[0], false);\n }\n return { name, type: 'unknown', required, description: prop.description };\n }\n\n const type = prop.type;\n\n if (type === 'string') {\n return {\n name,\n type: 'string',\n required,\n minLength: prop.minLength,\n maxLength: prop.maxLength,\n pattern: prop.pattern,\n description: prop.description,\n };\n }\n\n if (type === 'number' || type === 'integer') {\n return {\n name,\n type: 'number',\n required,\n min: prop.minimum,\n max: prop.maximum,\n isInt: type === 'integer' ? true : undefined,\n description: prop.description,\n };\n }\n\n if (type === 'boolean') {\n return { name, type: 'boolean', required, description: prop.description };\n }\n\n if (type === 'array') {\n const itemMeta = prop.items\n ? propertyToFieldMeta('item', prop.items, true)\n : undefined;\n return {\n name,\n type: 'array',\n required,\n itemMeta,\n description: prop.description,\n };\n }\n\n if (type === 'object') {\n return {\n name,\n type: 'object',\n required,\n fields: jsonSchemaToFieldMeta(prop),\n description: prop.description,\n };\n }\n\n return { name, type: 'unknown', required, description: prop.description };\n}\n\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","/**\n * Scope path matching for subgraph-level registry constraints.\n *\n * Scope paths are slash-separated names derived from the chain of\n * `subgraph()` calls (e.g., `'agents'`, `'agents/memories'`).\n * The root graph has an empty scope path (`''`).\n *\n * Patterns:\n * - `'root'` — matches only the root graph (empty scope path)\n * - `'agents'` — matches exactly `'agents'`\n * - `'agents/memories'` — matches exactly `'agents/memories'`\n * - `'*​/agents'` — `*` matches one segment: `'foo/agents'` but not `'a/b/agents'`\n * - `'**​/memories'` — `**` matches zero or more segments\n * - `'**'` — matches everything including root\n */\n\n/**\n * Test whether a scope path matches a single pattern.\n *\n * @param scopePath - The current scope path (empty string for root)\n * @param pattern - The pattern to match against\n */\nexport function matchScope(scopePath: string, pattern: string): boolean {\n // Special case: 'root' matches only the root graph\n if (pattern === 'root') return scopePath === '';\n\n // Special case: '**' matches everything\n if (pattern === '**') return true;\n\n const pathSegments = scopePath === '' ? [] : scopePath.split('/');\n const patternSegments = pattern.split('/');\n\n return matchSegments(pathSegments, 0, patternSegments, 0);\n}\n\n/**\n * Test whether a scope path matches any pattern in a list.\n * Returns `true` if the list is empty or undefined (allowed everywhere).\n *\n * @param scopePath - The current scope path (empty string for root)\n * @param patterns - Array of patterns to match against\n */\nexport function matchScopeAny(scopePath: string, patterns: string[]): boolean {\n if (!patterns || patterns.length === 0) return true;\n return patterns.some((p) => matchScope(scopePath, p));\n}\n\n/**\n * Recursive segment matcher with support for `*` (one segment) and\n * `**` (zero or more segments).\n */\nfunction matchSegments(\n path: string[],\n pi: number,\n pattern: string[],\n qi: number,\n): boolean {\n // Both exhausted — match\n if (pi === path.length && qi === pattern.length) return true;\n\n // Pattern exhausted but path remains — no match\n if (qi === pattern.length) return false;\n\n const seg = pattern[qi];\n\n if (seg === '**') {\n // '**' at the end of pattern — matches everything remaining\n if (qi === pattern.length - 1) return true;\n\n // Try consuming 0, 1, 2, ... path segments\n for (let skip = 0; skip <= path.length - pi; skip++) {\n if (matchSegments(path, pi + skip, pattern, qi + 1)) return true;\n }\n return false;\n }\n\n // Path exhausted but pattern has non-** segments remaining — no match\n if (pi === path.length) return false;\n\n if (seg === '*') {\n // '*' matches exactly one segment\n return matchSegments(path, pi + 1, pattern, qi + 1);\n }\n\n // Literal match\n if (path[pi] === seg) {\n return matchSegments(path, pi + 1, pattern, qi + 1);\n }\n\n return false;\n}\n","import { RegistryViolationError, RegistryScopeError, ValidationError } from './errors.js';\nimport { compileSchema } from './json-schema.js';\nimport { matchScopeAny } from './scope.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { GraphRegistry, RegistryEntry, DiscoveryResult } from './types.js';\n\nfunction tripleKey(aType: string, axbType: string, bType: string): string {\n return `${aType}:${axbType}:${bType}`;\n}\n\n/**\n * Build a registry from either explicit entries or a DiscoveryResult.\n *\n * @example\n * ```ts\n * // From explicit entries (programmatic)\n * const registry = createRegistry([\n * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },\n * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },\n * ]);\n *\n * // From discovery result (folder convention)\n * const discovered = await discoverEntities('./entities');\n * const registry = createRegistry(discovered);\n * ```\n */\nexport function createRegistry(\n input: RegistryEntry[] | DiscoveryResult,\n): GraphRegistry {\n const map = new Map<string, { entry: RegistryEntry; validate?: (data: unknown) => void }>();\n\n let entries: RegistryEntry[];\n\n if (Array.isArray(input)) {\n entries = input;\n } else {\n entries = discoveryToEntries(input);\n }\n\n const entryList: ReadonlyArray<RegistryEntry> = Object.freeze([...entries]);\n\n for (const entry of entries) {\n if (entry.targetGraph && entry.targetGraph.includes('/')) {\n throw new ValidationError(\n `Entry (${entry.aType}) -[${entry.axbType}]-> (${entry.bType}) has invalid targetGraph \"${entry.targetGraph}\" — must be a single segment (no \"/\")`,\n );\n }\n const key = tripleKey(entry.aType, entry.axbType, entry.bType);\n const validator = entry.jsonSchema\n ? compileSchema(entry.jsonSchema, `(${entry.aType}) -[${entry.axbType}]-> (${entry.bType})`)\n : undefined;\n map.set(key, { entry, validate: validator });\n }\n\n // Build axbType index for lookupByAxbType\n const axbIndex = new Map<string, ReadonlyArray<RegistryEntry>>();\n const axbBuild = new Map<string, RegistryEntry[]>();\n for (const entry of entries) {\n const existing = axbBuild.get(entry.axbType);\n if (existing) {\n existing.push(entry);\n } else {\n axbBuild.set(entry.axbType, [entry]);\n }\n }\n for (const [key, arr] of axbBuild) {\n axbIndex.set(key, Object.freeze(arr));\n }\n\n return {\n lookup(aType: string, axbType: string, bType: string): RegistryEntry | undefined {\n return map.get(tripleKey(aType, axbType, bType))?.entry;\n },\n\n lookupByAxbType(axbType: string): ReadonlyArray<RegistryEntry> {\n return axbIndex.get(axbType) ?? [];\n },\n\n validate(aType: string, axbType: string, bType: string, data: unknown, scopePath?: string): void {\n const rec = map.get(tripleKey(aType, axbType, bType));\n\n if (!rec) {\n throw new RegistryViolationError(aType, axbType, bType);\n }\n\n // Scope validation: check allowedIn patterns when a scope context is provided\n if (scopePath !== undefined && rec.entry.allowedIn && rec.entry.allowedIn.length > 0) {\n if (!matchScopeAny(scopePath, rec.entry.allowedIn)) {\n throw new RegistryScopeError(aType, axbType, bType, scopePath, rec.entry.allowedIn);\n }\n }\n\n if (rec.validate) {\n try {\n rec.validate(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) throw err;\n throw new ValidationError(\n `Data validation failed for (${aType}) -[${axbType}]-> (${bType})`,\n err,\n );\n }\n }\n },\n\n entries(): ReadonlyArray<RegistryEntry> {\n return entryList;\n },\n };\n}\n\n/**\n * Convert a DiscoveryResult into flat RegistryEntry[].\n * Nodes become self-loop triples `(name, 'is', name)`.\n * Edges expand `from`/`to` arrays into one triple per combination.\n */\nfunction discoveryToEntries(discovery: DiscoveryResult): RegistryEntry[] {\n const entries: RegistryEntry[] = [];\n\n // Nodes → self-loop triples\n for (const [name, entity] of discovery.nodes) {\n entries.push({\n aType: name,\n axbType: NODE_RELATION,\n bType: name,\n jsonSchema: entity.schema,\n description: entity.description,\n titleField: entity.titleField,\n subtitleField: entity.subtitleField,\n allowedIn: entity.allowedIn,\n });\n }\n\n // Edges → expand from/to into one triple per combination\n for (const [axbType, entity] of discovery.edges) {\n const topology = entity.topology;\n if (!topology) continue;\n\n const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];\n const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];\n\n const resolvedTargetGraph = entity.targetGraph ?? topology.targetGraph;\n if (resolvedTargetGraph && resolvedTargetGraph.includes('/')) {\n throw new ValidationError(\n `Edge \"${axbType}\" has invalid targetGraph \"${resolvedTargetGraph}\" — must be a single segment (no \"/\")`,\n );\n }\n\n for (const aType of fromTypes) {\n for (const bType of toTypes) {\n entries.push({\n aType,\n axbType,\n bType,\n jsonSchema: entity.schema,\n description: entity.description,\n inverseLabel: topology.inverseLabel,\n titleField: entity.titleField,\n subtitleField: entity.subtitleField,\n allowedIn: entity.allowedIn,\n targetGraph: resolvedTargetGraph,\n });\n }\n }\n }\n\n return entries;\n}\n","import { nanoid } from 'nanoid';\n\nexport function generateId(): string {\n return nanoid();\n}\n","import { TraversalError } from './errors.js';\nimport type {\n GraphReader,\n GraphClient,\n GraphRegistry,\n StoredGraphRecord,\n FindEdgesParams,\n HopDefinition,\n TraversalOptions,\n HopResult,\n TraversalResult,\n TraversalBuilder,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_MAX_READS = 100;\nconst DEFAULT_CONCURRENCY = 5;\n\n/** One-time warning flag: emitted when cross-graph hop is silently skipped. */\nlet _crossGraphWarned = false;\n\n/** Type guard to check if a reader is a GraphClient (has subgraph method). */\nfunction isGraphClient(reader: GraphReader): reader is GraphClient {\n return 'subgraph' in reader && typeof (reader as GraphClient).subgraph === 'function';\n}\n\nclass Semaphore {\n private queue: Array<() => void> = [];\n private active = 0;\n\n constructor(private readonly slots: number) {}\n\n async acquire(): Promise<void> {\n if (this.active < this.slots) {\n this.active++;\n return;\n }\n return new Promise<void>((resolve) => {\n this.queue.push(resolve);\n });\n }\n\n release(): void {\n this.active--;\n const next = this.queue.shift();\n if (next) {\n this.active++;\n next();\n }\n }\n}\n\nclass TraversalBuilderImpl implements TraversalBuilder {\n private readonly hops: HopDefinition[] = [];\n\n constructor(\n private readonly reader: GraphReader,\n private readonly startUid: string,\n private readonly registry?: GraphRegistry,\n ) {}\n\n follow(axbType: string, options?: Omit<HopDefinition, 'axbType'>): TraversalBuilder {\n this.hops.push({ axbType, ...options });\n return this;\n }\n\n async run(options?: TraversalOptions): Promise<TraversalResult> {\n if (this.hops.length === 0) {\n throw new TraversalError('Traversal requires at least one follow() hop');\n }\n\n const maxReads = options?.maxReads ?? DEFAULT_MAX_READS;\n const concurrency = options?.concurrency ?? DEFAULT_CONCURRENCY;\n const returnIntermediates = options?.returnIntermediates ?? false;\n const semaphore = new Semaphore(concurrency);\n\n let totalReads = 0;\n let truncated = false;\n // Track (uid, reader) pairs to support context carry-forward across hops.\n // When a hop crosses into a subgraph, the resulting UIDs carry the subgraph\n // reader so subsequent hops without targetGraph stay in that subgraph.\n let sources: Array<{ uid: string; reader: GraphReader }> = [\n { uid: this.startUid, reader: this.reader },\n ];\n const hopResults: HopResult[] = [];\n\n for (let depth = 0; depth < this.hops.length; depth++) {\n const hop = this.hops[depth];\n\n if (sources.length === 0) {\n hopResults.push({\n axbType: hop.axbType,\n depth,\n edges: [],\n sourceCount: 0,\n truncated: false,\n });\n continue;\n }\n\n const hopEdges: Array<{ edge: StoredGraphRecord; reader: GraphReader }> = [];\n const sourceCount = sources.length;\n let hopTruncated = false;\n\n // Resolve targetGraph for this hop:\n // 1. Explicit on the hop definition takes precedence\n // 2. Otherwise check the registry for the axbType\n const resolvedTargetGraph = this.resolveTargetGraph(hop);\n const direction = hop.direction ?? 'forward';\n const isCrossGraph = direction === 'forward' && !!resolvedTargetGraph;\n\n const tasks = sources.map(({ uid, reader: sourceReader }) => async () => {\n if (totalReads >= maxReads) {\n hopTruncated = true;\n return;\n }\n\n await semaphore.acquire();\n try {\n if (totalReads >= maxReads) {\n hopTruncated = true;\n return;\n }\n\n totalReads++;\n\n const params: FindEdgesParams = { axbType: hop.axbType };\n\n if (direction === 'forward') {\n params.aUid = uid;\n if (hop.bType) params.bType = hop.bType;\n } else {\n params.bUid = uid;\n if (hop.aType) params.aType = hop.aType;\n }\n\n if (direction === 'forward' && hop.aType) {\n params.aType = hop.aType;\n }\n if (direction === 'reverse' && hop.bType) {\n params.bType = hop.bType;\n }\n\n if (hop.orderBy) params.orderBy = hop.orderBy;\n\n const limit = hop.limit ?? DEFAULT_LIMIT;\n if (hop.filter) {\n params.limit = 0;\n } else {\n params.limit = limit;\n }\n\n // Choose the reader for this hop:\n // - Cross-graph hop: create a subgraph reader from the ROOT client\n // (targetGraph is always relative to root)\n // - No cross-graph: use the carried-forward reader from previous hop\n // (context tracking — stay in whatever subgraph we're already in)\n let hopReader: GraphReader;\n let nextReader: GraphReader;\n if (isCrossGraph) {\n if (isGraphClient(this.reader)) {\n hopReader = this.reader.subgraph(uid, resolvedTargetGraph!);\n nextReader = hopReader;\n } else {\n hopReader = sourceReader;\n nextReader = sourceReader;\n if (!_crossGraphWarned) {\n _crossGraphWarned = true;\n console.warn(\n `[firegraph] Traversal hop \"${hop.axbType}\" has targetGraph \"${resolvedTargetGraph}\" ` +\n 'but the reader does not support subgraph(). Cross-graph hop will query the current ' +\n 'collection instead. Pass a GraphClient to createTraversal() to enable cross-graph traversal.',\n );\n }\n }\n } else {\n // No targetGraph — carry forward context from previous hop\n hopReader = sourceReader;\n nextReader = sourceReader;\n }\n\n let edges = await hopReader.findEdges(params);\n\n if (hop.filter) {\n edges = edges.filter(hop.filter);\n edges = edges.slice(0, limit);\n }\n\n for (const edge of edges) {\n hopEdges.push({ edge, reader: nextReader });\n }\n } finally {\n semaphore.release();\n }\n });\n\n await Promise.all(tasks.map((task) => task()));\n\n const edges = hopEdges.map((h) => h.edge);\n\n hopResults.push({\n axbType: hop.axbType,\n depth,\n edges: returnIntermediates ? [...edges] : edges,\n sourceCount,\n truncated: hopTruncated,\n });\n\n if (hopTruncated) {\n truncated = true;\n }\n\n // Build next sources with deduplication by UID.\n // When the same UID appears from multiple source readers, the first one wins.\n const seen = new Map<string, GraphReader>();\n for (const { edge, reader: edgeReader } of hopEdges) {\n const nextUid = direction === 'forward' ? edge.bUid : edge.aUid;\n if (!seen.has(nextUid)) {\n seen.set(nextUid, edgeReader);\n }\n }\n sources = [...seen.entries()].map(([uid, reader]) => ({ uid, reader }));\n }\n\n const lastHop = hopResults[hopResults.length - 1];\n\n return {\n nodes: lastHop.edges,\n hops: hopResults,\n totalReads,\n truncated,\n };\n }\n\n /**\n * Resolve the targetGraph for a hop. Priority:\n * 1. Explicit `hop.targetGraph` (user override)\n * 2. Registry `targetGraph` for the axbType (if registry available)\n * 3. undefined (no cross-graph)\n */\n private resolveTargetGraph(hop: HopDefinition): string | undefined {\n if (hop.targetGraph) return hop.targetGraph;\n\n if (this.registry) {\n const entries = this.registry.lookupByAxbType(hop.axbType);\n // All entries for the same axbType should share targetGraph; use the first non-undefined\n for (const entry of entries) {\n if (entry.targetGraph) return entry.targetGraph;\n }\n }\n\n return undefined;\n }\n}\n\n/** @internal Reset the one-time cross-graph warning flag (for testing). */\nexport function _resetCrossGraphWarning(): void {\n _crossGraphWarned = false;\n}\n\n/**\n * Create a traversal builder for multi-hop graph traversal.\n *\n * Accepts either a `GraphReader` (backwards compatible) or a `GraphClient`.\n * When a `GraphClient` is provided, cross-graph traversal via `targetGraph`\n * is supported — the traversal can follow edges into subgraphs.\n *\n * @param reader - A `GraphClient` or `GraphReader` to execute queries against\n * @param startUid - UID of the starting node\n * @param registry - Optional registry for automatic `targetGraph` resolution\n */\nexport function createTraversal(\n reader: GraphClient | GraphReader,\n startUid: string,\n registry?: GraphRegistry,\n): TraversalBuilder {\n return new TraversalBuilderImpl(reader, startUid, registry);\n}\n","/**\n * Model Views — framework-agnostic view definitions for graph entities.\n *\n * Projects define Web Components that render entity data in purpose-driven\n * ways. Each view class declares a static `viewName`, and receives the\n * entity's `data` payload via a `data` property setter.\n *\n * @example\n * ```ts\n * import { defineViews } from 'firegraph';\n *\n * class UserCard extends HTMLElement {\n * static viewName = 'card';\n * static description = 'Compact user card';\n * private _data: Record<string, unknown> = {};\n * set data(v: Record<string, unknown>) { this._data = v; this.render(); }\n * connectedCallback() { this.render(); }\n * private render() {\n * this.innerHTML = `<strong>${this._data.displayName ?? ''}</strong>`;\n * }\n * }\n *\n * export default defineViews({\n * nodes: { user: { views: [UserCard] } },\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A Web Component class used as a view. The class must have a static\n * `viewName` and must be constructable. It will be registered as a custom\n * element via `customElements.define()` in browser environments.\n *\n * Note: this interface avoids referencing `HTMLElement` directly so the\n * library can compile without DOM lib types. Consumer code (which has DOM)\n * will satisfy this constraint naturally.\n */\nexport interface ViewComponentClass {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (...args: any[]): { data: Record<string, unknown> };\n /** Short identifier for this view (e.g. 'card', 'profile'). */\n viewName: string;\n /** Optional human-readable description. */\n description?: string;\n}\n\n/** Configuration for all views of a single entity type. */\nexport interface EntityViewConfig {\n /** View component classes to register. */\n views: ViewComponentClass[];\n /**\n * Optional sample data for the gallery. A single object matching\n * the entity's JSON Schema — shared across all views.\n */\n sampleData?: Record<string, unknown>;\n}\n\n/** Input shape accepted by `defineViews()`. */\nexport interface ViewRegistryInput {\n /** Node views keyed by aType (e.g. 'user', 'tour'). */\n nodes?: Record<string, EntityViewConfig>;\n /** Edge views keyed by axbType (e.g. 'hasDeparture'). */\n edges?: Record<string, EntityViewConfig>;\n}\n\n/** Serialisable metadata for a single view. */\nexport interface ViewMeta {\n /** Custom element tag name (e.g. 'fg-user-card'). */\n tagName: string;\n /** Short identifier matching the component's static viewName. */\n viewName: string;\n /** Optional human-readable description. */\n description?: string;\n}\n\n/** Serialisable metadata for all views of a single entity type. */\nexport interface EntityViewMeta {\n views: ViewMeta[];\n sampleData?: Record<string, unknown>;\n}\n\n/** The resolved view registry returned by `defineViews()`. */\nexport interface ViewRegistry {\n nodes: Record<string, EntityViewMeta>;\n edges: Record<string, EntityViewMeta>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Sanitise a string for use as part of a custom element tag name. */\nfunction sanitizeTagPart(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/** Minimal interface for CustomElementRegistry (avoids depending on DOM lib). */\ninterface CustomElementRegistryLike {\n get(name: string): unknown;\n define(name: string, constructor: unknown): void;\n}\n\n/**\n * Try to access the browser's `customElements` registry.\n * Returns `null` in Node.js or environments without Web Components support.\n */\nfunction getCustomElements(): CustomElementRegistryLike | null {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = globalThis as any;\n if (g.customElements && typeof g.customElements.define === 'function') {\n return g.customElements as CustomElementRegistryLike;\n }\n return null;\n}\n\n/**\n * Wrap a view class so that errors in connectedCallback, disconnectedCallback,\n * and the data setter are caught and logged rather than crashing the page.\n * Shows an inline error message when the view fails to render.\n */\nfunction resilientView(ViewClass: ViewComponentClass, tagName: string): ViewComponentClass {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = globalThis as any;\n if (!g.HTMLElement) return ViewClass; // Node.js — no wrapping needed\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const Base = g.HTMLElement as any;\n\n const Wrapped = class extends (ViewClass as unknown as typeof Base) {\n connectedCallback() {\n try {\n super.connectedCallback?.();\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> connectedCallback error:`, err);\n this._showError(err);\n }\n }\n\n disconnectedCallback() {\n try {\n super.disconnectedCallback?.();\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> disconnectedCallback error:`, err);\n }\n }\n\n set data(v: Record<string, unknown>) {\n try {\n super.data = v;\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> data setter error:`, err);\n this._showError(err);\n }\n }\n\n get data(): Record<string, unknown> {\n try {\n return super.data;\n } catch {\n return {};\n }\n }\n\n _showError(err: unknown) {\n try {\n this.innerHTML = `<div style=\"padding:6px;color:#f87171;font-size:11px;font-family:monospace;\">` +\n `View error in &lt;${tagName}&gt;: ${err instanceof Error ? err.message : String(err)}</div>`;\n } catch { /* last resort — don't throw from error handler */ }\n }\n };\n\n // Preserve static metadata\n (Wrapped as unknown as ViewComponentClass).viewName = ViewClass.viewName;\n (Wrapped as unknown as ViewComponentClass).description = ViewClass.description;\n\n return Wrapped as unknown as ViewComponentClass;\n}\n\n// ---------------------------------------------------------------------------\n// defineViews()\n// ---------------------------------------------------------------------------\n\n/**\n * Build a `ViewRegistry` from component classes.\n *\n * In the browser the components are registered as custom elements with\n * deterministic tag names (`fg-{entityType}-{viewName}`). On the server\n * (Node.js) only metadata is returned — no custom element registration.\n */\nexport function defineViews(input: ViewRegistryInput): ViewRegistry {\n const nodes: Record<string, EntityViewMeta> = {};\n const edges: Record<string, EntityViewMeta> = {};\n const registry = getCustomElements();\n\n // --- nodes ---\n for (const [entityType, config] of Object.entries(input.nodes ?? {})) {\n const viewMetas: ViewMeta[] = [];\n for (const ViewClass of config.views) {\n const tagName = `fg-${sanitizeTagPart(entityType)}-${sanitizeTagPart(ViewClass.viewName)}`;\n viewMetas.push({\n tagName,\n viewName: ViewClass.viewName,\n description: ViewClass.description,\n });\n if (registry && !registry.get(tagName)) {\n registry.define(tagName, resilientView(ViewClass, tagName));\n }\n }\n nodes[entityType] = {\n views: viewMetas,\n sampleData: config.sampleData,\n };\n }\n\n // --- edges ---\n for (const [axbType, config] of Object.entries(input.edges ?? {})) {\n const viewMetas: ViewMeta[] = [];\n for (const ViewClass of config.views) {\n const tagName = `fg-edge-${sanitizeTagPart(axbType)}-${sanitizeTagPart(ViewClass.viewName)}`;\n viewMetas.push({\n tagName,\n viewName: ViewClass.viewName,\n description: ViewClass.description,\n });\n if (registry && !registry.get(tagName)) {\n registry.define(tagName, resilientView(ViewClass, tagName));\n }\n }\n edges[axbType] = {\n views: viewMetas,\n sampleData: config.sampleData,\n };\n }\n\n return { nodes, edges };\n}\n","/**\n * Firegraph Configuration — project-level config file support.\n *\n * Projects create a `firegraph.config.ts` (or `.js`/`.mjs`) in their root:\n *\n * @example\n * ```ts\n * import { defineConfig } from 'firegraph';\n *\n * export default defineConfig({\n * entities: './entities',\n * project: 'my-project',\n * collection: 'graph',\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// View Resolution Types\n// ---------------------------------------------------------------------------\n\n/** Display contexts where views can appear. */\nexport type ViewContext = 'listing' | 'detail' | 'inline';\n\n/** View resolution configuration for a single entity type. */\nexport interface ViewResolverConfig {\n /** Default view name (e.g. 'card'). Falls back to 'json' if unset. */\n default?: string;\n /** View to use in NodeBrowser listing rows. */\n listing?: string;\n /** View to use on the NodeDetail page. */\n detail?: string;\n /** View to use for inline/embedded previews (edge rows, traversal). */\n inline?: string;\n}\n\n/** Declarative view defaults, keyed by entity type. */\nexport interface ViewDefaultsConfig {\n /** Node view defaults keyed by aType (e.g. 'user', 'task'). */\n nodes?: Record<string, ViewResolverConfig>;\n /** Edge view defaults keyed by axbType (e.g. 'hasDeparture'). */\n edges?: Record<string, ViewResolverConfig>;\n}\n\n// ---------------------------------------------------------------------------\n// Config Shape\n// ---------------------------------------------------------------------------\n\n/** Project-level firegraph configuration. */\nexport interface FiregraphConfig {\n /** Path to entities directory (per-entity folder convention). */\n entities?: string;\n /** GCP project ID. */\n project?: string;\n /** Firestore collection path (default: 'graph'). */\n collection?: string;\n /** Firestore emulator address (e.g. '127.0.0.1:8080'). */\n emulator?: string;\n /**\n * Query execution backend.\n *\n * - `'pipeline'` (default) — Uses Firestore Pipeline API. Requires Enterprise\n * Firestore. Enables indexless queries on `data.*` fields.\n * - `'standard'` — Uses standard Firestore `.where().get()` queries. Not\n * recommended for production. See README for risk details.\n *\n * When the emulator is active, always falls back to `'standard'`.\n */\n queryMode?: import('./types.js').QueryMode;\n\n /**\n * AI chat configuration. Auto-detects `claude` CLI on PATH by default.\n * Set to `false` to disable chat even if claude is available.\n */\n chat?: false | {\n /** Claude model to use (default: 'sonnet'). */\n model?: string;\n /** Maximum concurrent claude processes (default: 2). */\n maxConcurrency?: number;\n };\n\n /** Editor-specific settings. */\n editor?: {\n /** Server port (default: 3883). */\n port?: number;\n /** Force read-only mode. */\n readonly?: boolean;\n };\n\n /** Declarative view defaults per entity type (overrides per-entity meta.json). */\n viewDefaults?: ViewDefaultsConfig;\n\n /**\n * Dynamic registry mode. When set, the editor loads type definitions\n * from Firestore meta-nodes in addition to filesystem entities.\n * Filesystem types take precedence on name conflicts.\n */\n registryMode?: import('./types.js').DynamicRegistryConfig;\n}\n\n// ---------------------------------------------------------------------------\n// defineConfig()\n// ---------------------------------------------------------------------------\n\n/**\n * Identity function providing type-checking and autocomplete for config files.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'firegraph';\n * export default defineConfig({ entities: './entities' });\n * ```\n */\nexport function defineConfig(config: FiregraphConfig): FiregraphConfig {\n return config;\n}\n\n// ---------------------------------------------------------------------------\n// View Resolution (pure — works client-side and server-side)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve which view to show for a given entity.\n *\n * 1. If `context` is provided and a context-specific default exists, use it.\n * 2. Falls back to `resolverConfig.default`.\n * 3. Ultimate fallback: `'json'`.\n *\n * Only returns view names that exist in `availableViewNames`.\n */\nexport function resolveView(\n resolverConfig: ViewResolverConfig | undefined,\n availableViewNames: string[],\n context?: ViewContext,\n): string {\n if (!resolverConfig) return 'json';\n\n const available = new Set(availableViewNames);\n\n if (context) {\n const contextDefault = resolverConfig[context];\n if (contextDefault && available.has(contextDefault)) {\n return contextDefault;\n }\n }\n\n if (resolverConfig.default && available.has(resolverConfig.default)) {\n return resolverConfig.default;\n }\n\n return 'json';\n}\n","/**\n * Entity Discovery — convention-based auto-discovery of entities from\n * a per-entity folder structure.\n *\n * Scans `entitiesDir/nodes/` and `entitiesDir/edges/` subdirectories.\n * Each subfolder is treated as an entity type.\n *\n * Schema files can be either `schema.json` (plain JSON Schema) or\n * `schema.ts` / `schema.js` (a module whose default export is a JSON Schema\n * object). When both exist, the TS/JS file takes precedence so that authors\n * can compose schemas programmatically while keeping a JSON fallback.\n *\n * @example\n * ```\n * entities/\n * nodes/\n * task/\n * schema.json | schema.ts (required — one or both)\n * views.ts (optional)\n * sample.json (optional)\n * meta.json (optional)\n * edges/\n * hasStep/\n * schema.json | schema.ts (required — one or both)\n * edge.json (required — topology)\n * views.ts (optional)\n * sample.json (optional)\n * meta.json (optional)\n * ```\n */\n\nimport { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join, resolve } from 'node:path';\nimport type { DiscoveredEntity, DiscoveryResult, EdgeTopology } from './types.js';\nimport type { ViewResolverConfig } from './config.js';\nimport { FiregraphError } from './errors.js';\n\nexport class DiscoveryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'DISCOVERY_ERROR');\n this.name = 'DiscoveryError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON parsing helpers\n// ---------------------------------------------------------------------------\n\nfunction readJson(filePath: string): unknown {\n try {\n const raw = readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch (err: unknown) {\n const msg = err instanceof SyntaxError\n ? `Invalid JSON in ${filePath}: ${err.message}`\n : `Cannot read ${filePath}: ${(err as Error).message}`;\n throw new DiscoveryError(msg);\n }\n}\n\nfunction readJsonIfExists(filePath: string): unknown | undefined {\n if (!existsSync(filePath)) return undefined;\n return readJson(filePath);\n}\n\n// ---------------------------------------------------------------------------\n// Schema file loading (JSON or TS/JS via jiti)\n// ---------------------------------------------------------------------------\n\nconst SCHEMA_SCRIPT_EXTENSIONS = ['.ts', '.js', '.mts', '.mjs'];\n\n/**\n * Attempt to load a schema from a TS/JS module (default export) or fall back\n * to schema.json. Returns the parsed schema object or throws.\n */\nfunction loadSchema(dir: string, entityLabel: string): object {\n // Prefer TS/JS schema — allows programmatic composition & shared definitions\n for (const ext of SCHEMA_SCRIPT_EXTENSIONS) {\n const candidate = join(dir, `schema${ext}`);\n if (existsSync(candidate)) {\n return loadSchemaModule(candidate, entityLabel);\n }\n }\n\n // Fall back to schema.json\n const jsonPath = join(dir, 'schema.json');\n if (existsSync(jsonPath)) {\n return readJson(jsonPath) as object;\n }\n\n throw new DiscoveryError(\n `Missing schema for ${entityLabel} in ${dir}. ` +\n 'Provide a schema.ts (or .js/.mts/.mjs) or schema.json file.',\n );\n}\n\nlet _jiti: ((id: string) => unknown) | undefined;\n\nfunction getJiti(): (id: string) => unknown {\n if (!_jiti) {\n const base = typeof __filename !== 'undefined' ? __filename : import.meta.url;\n const esmRequire = createRequire(base);\n const { createJiti } = esmRequire('jiti') as typeof import('jiti');\n _jiti = createJiti(base, { interopDefault: true });\n }\n return _jiti;\n}\n\nfunction loadSchemaModule(filePath: string, entityLabel: string): object {\n try {\n const jiti = getJiti();\n const mod = jiti(filePath) as { default?: unknown } | unknown;\n const schema = (mod && typeof mod === 'object' && 'default' in mod)\n ? (mod as { default: unknown }).default\n : mod;\n\n if (!schema || typeof schema !== 'object') {\n throw new DiscoveryError(\n `Schema file ${filePath} for ${entityLabel} must default-export a JSON Schema object.`,\n );\n }\n return schema as object;\n } catch (err: unknown) {\n if (err instanceof DiscoveryError) throw err;\n throw new DiscoveryError(\n `Failed to load schema module ${filePath} for ${entityLabel}: ${(err as Error).message}`,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// View file detection\n// ---------------------------------------------------------------------------\n\nconst VIEW_EXTENSIONS = ['.ts', '.js', '.mts', '.mjs'];\n\nfunction findViewsFile(dir: string): string | undefined {\n for (const ext of VIEW_EXTENSIONS) {\n const candidate = join(dir, `views${ext}`);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Entity loaders\n// ---------------------------------------------------------------------------\n\nfunction loadNodeEntity(dir: string, name: string): DiscoveredEntity {\n const schema = loadSchema(dir, `node type \"${name}\"`);\n const meta = readJsonIfExists(join(dir, 'meta.json')) as\n | { description?: string; titleField?: string; subtitleField?: string; viewDefaults?: ViewResolverConfig; allowedIn?: string[] }\n | undefined;\n const sampleData = readJsonIfExists(join(dir, 'sample.json')) as\n | Record<string, unknown>\n | undefined;\n const viewsPath = findViewsFile(dir);\n\n return {\n kind: 'node',\n name,\n schema,\n description: meta?.description,\n titleField: meta?.titleField,\n subtitleField: meta?.subtitleField,\n viewDefaults: meta?.viewDefaults,\n viewsPath,\n sampleData,\n allowedIn: meta?.allowedIn,\n };\n}\n\nfunction loadEdgeEntity(dir: string, name: string): DiscoveredEntity {\n const schema = loadSchema(dir, `edge type \"${name}\"`);\n\n const edgePath = join(dir, 'edge.json');\n if (!existsSync(edgePath)) {\n throw new DiscoveryError(\n `Missing edge.json for edge type \"${name}\" in ${dir}. ` +\n 'Edge entities must declare topology (from/to node types).',\n );\n }\n const topology = readJson(edgePath) as EdgeTopology;\n\n // Validate topology shape\n if (!topology.from) {\n throw new DiscoveryError(\n `edge.json for \"${name}\" is missing required \"from\" field`,\n );\n }\n if (!topology.to) {\n throw new DiscoveryError(\n `edge.json for \"${name}\" is missing required \"to\" field`,\n );\n }\n\n const meta = readJsonIfExists(join(dir, 'meta.json')) as\n | { description?: string; titleField?: string; subtitleField?: string; viewDefaults?: ViewResolverConfig; allowedIn?: string[]; targetGraph?: string }\n | undefined;\n const sampleData = readJsonIfExists(join(dir, 'sample.json')) as\n | Record<string, unknown>\n | undefined;\n const viewsPath = findViewsFile(dir);\n\n return {\n kind: 'edge',\n name,\n schema,\n topology,\n description: meta?.description,\n titleField: meta?.titleField,\n subtitleField: meta?.subtitleField,\n viewDefaults: meta?.viewDefaults,\n viewsPath,\n sampleData,\n allowedIn: meta?.allowedIn,\n targetGraph: topology.targetGraph ?? (meta as { targetGraph?: string } | undefined)?.targetGraph,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Directory scanner\n// ---------------------------------------------------------------------------\n\nfunction getSubdirectories(dir: string): string[] {\n if (!existsSync(dir)) return [];\n return readdirSync(dir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface DiscoveryWarning {\n code: 'DANGLING_TOPOLOGY_REF';\n message: string;\n}\n\nexport interface DiscoverResult {\n result: DiscoveryResult;\n warnings: DiscoveryWarning[];\n}\n\n/**\n * Scan an entities directory and return all discovered nodes and edges.\n *\n * @param entitiesDir - Path to the entities directory (absolute or relative to cwd)\n * @returns Discovery result with nodes and edges maps, plus any warnings\n */\nexport function discoverEntities(entitiesDir: string): DiscoverResult {\n const absDir = resolve(entitiesDir);\n\n if (!existsSync(absDir) || !statSync(absDir).isDirectory()) {\n throw new DiscoveryError(`Entities directory not found: ${entitiesDir}`);\n }\n\n const nodes = new Map<string, DiscoveredEntity>();\n const edges = new Map<string, DiscoveredEntity>();\n const warnings: DiscoveryWarning[] = [];\n\n // Discover nodes\n const nodesDir = join(absDir, 'nodes');\n for (const name of getSubdirectories(nodesDir)) {\n nodes.set(name, loadNodeEntity(join(nodesDir, name), name));\n }\n\n // Discover edges\n const edgesDir = join(absDir, 'edges');\n for (const name of getSubdirectories(edgesDir)) {\n edges.set(name, loadEdgeEntity(join(edgesDir, name), name));\n }\n\n // Validate topology references\n const nodeNames = new Set(nodes.keys());\n for (const [axbType, entity] of edges) {\n const topology = entity.topology!;\n const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];\n const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];\n\n for (const ref of [...fromTypes, ...toTypes]) {\n if (!nodeNames.has(ref)) {\n warnings.push({\n code: 'DANGLING_TOPOLOGY_REF',\n message: `Edge \"${axbType}\" references node type \"${ref}\" which was not found in the nodes directory`,\n });\n }\n }\n }\n\n return {\n result: { nodes, edges },\n warnings,\n };\n}\n","/**\n * Cross-graph edge resolution utilities.\n *\n * Provides path-scanning resolution for determining whether an edge's source\n * (aUid) is an ancestor node by checking if the UID appears in the Firestore\n * collection path.\n *\n * Firestore paths have a rigid alternating structure:\n * collection / docId / collection / docId / collection\n *\n * Given a path like `graph/A/workspace/B/context`, segments at even indices\n * are collection names and odd indices are document IDs. When we find a UID\n * at an odd index, the collection containing that document is the path up to\n * (and including) the preceding even-index segment.\n */\n\n/**\n * Parse a Firestore collection path and determine the collection path\n * where a given UID's document lives, if that UID is an ancestor in the path.\n *\n * @param collectionPath - The full Firestore collection path of the current client\n * @param uid - The UID to search for in the path\n * @returns The collection path containing the UID, or `null` if not found in the path\n *\n * @example\n * ```ts\n * // Path: graph/A/workspace/B/context\n * resolveAncestorCollection('graph/A/workspace/B/context', 'A')\n * // → 'graph'\n *\n * resolveAncestorCollection('graph/A/workspace/B/context', 'B')\n * // → 'graph/A/workspace'\n *\n * resolveAncestorCollection('graph/A/workspace/B/context', 'unknown')\n * // → null\n * ```\n */\nexport function resolveAncestorCollection(\n collectionPath: string,\n uid: string,\n): string | null {\n const segments = collectionPath.split('/');\n\n // Walk odd-indexed segments (document IDs in Firestore's alternating path structure)\n for (let i = 1; i < segments.length; i += 2) {\n if (segments[i] === uid) {\n // The collection containing this doc is everything up to index i-1\n return segments.slice(0, i).join('/');\n }\n }\n\n return null;\n}\n\n/**\n * Check whether a UID belongs to an ancestor node by scanning the collection path.\n *\n * @param collectionPath - The full Firestore collection path of the current client\n * @param uid - The UID to check\n * @returns `true` if the UID appears as a document segment in the path\n */\nexport function isAncestorUid(\n collectionPath: string,\n uid: string,\n): boolean {\n return resolveAncestorCollection(collectionPath, uid) !== null;\n}\n","/**\n * Code generation — produces TypeScript type definitions from JSON Schema\n * files discovered via the entity folder convention.\n *\n * Uses `json-schema-to-typescript` to compile each entity's `schema.json`\n * into a TypeScript interface.\n *\n * Naming convention:\n * - Nodes: `{PascalName}Data` (e.g. `TaskData`)\n * - Edges: `{PascalName}EdgeData` (e.g. `HasStepEdgeData`)\n */\n\nimport type { DiscoveryResult } from '../types.js';\n\nfunction pascalCase(s: string): string {\n return s.replace(/(^|[^a-zA-Z0-9])([a-zA-Z])/g, (_, _sep, ch) =>\n ch.toUpperCase(),\n );\n}\n\nexport interface CodegenOptions {\n /** Add banner comment at top of output. Defaults to true. */\n banner?: boolean;\n}\n\n/**\n * Generate TypeScript type definitions from a DiscoveryResult.\n * Returns the full file content as a string.\n */\nexport async function generateTypes(\n discovery: DiscoveryResult,\n options: CodegenOptions = {},\n): Promise<string> {\n // Lazy-load to avoid requiring this dep at runtime for non-codegen usage\n const { compile } = await import('json-schema-to-typescript');\n\n const { banner = true } = options;\n const chunks: string[] = [];\n\n if (banner) {\n chunks.push(\n '// Auto-generated by firegraph codegen — do not edit manually\\n',\n );\n }\n\n // Sort for deterministic output\n const sortedNodes = [...discovery.nodes.entries()].sort(([a], [b]) =>\n a.localeCompare(b),\n );\n const sortedEdges = [...discovery.edges.entries()].sort(([a], [b]) =>\n a.localeCompare(b),\n );\n\n for (const [name, entity] of sortedNodes) {\n const typeName = `${pascalCase(name)}Data`;\n const ts = await compile(entity.schema as any, typeName, {\n bannerComment: '',\n additionalProperties: false,\n });\n chunks.push(ts.trim());\n chunks.push('');\n }\n\n for (const [name, entity] of sortedEdges) {\n const typeName = `${pascalCase(name)}EdgeData`;\n const ts = await compile(entity.schema as any, typeName, {\n bannerComment: '',\n additionalProperties: false,\n });\n chunks.push(ts.trim());\n chunks.push('');\n }\n\n return chunks.join('\\n').trimEnd() + '\\n';\n}\n","import type { DiscoveryResult, RegistryEntry } from './types.js';\n\nexport interface FirestoreIndexField {\n fieldPath: string;\n order: 'ASCENDING' | 'DESCENDING';\n}\n\nexport interface FirestoreIndex {\n collectionGroup: string;\n queryScope: 'COLLECTION' | 'COLLECTION_GROUP';\n fields: FirestoreIndexField[];\n}\n\nexport interface FirestoreIndexConfig {\n indexes: FirestoreIndex[];\n fieldOverrides: unknown[];\n}\n\n/**\n * Base composite indexes required for all firegraph collections.\n * These cover the standard query patterns:\n * - Forward edge lookup: (aUid, axbType)\n * - Reverse edge lookup: (axbType, bUid)\n * - Type-scoped queries: (aType, axbType) — also covers findNodes\n * - Edge type + target: (axbType, bType)\n */\nfunction baseIndexes(collection: string): FirestoreIndex[] {\n return [\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bUid', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bType', order: 'ASCENDING' },\n ],\n },\n ];\n}\n\n/**\n * Extracts top-level field names from a JSON Schema object.\n * Only returns fields from schemas with type: \"object\" and properties.\n */\nfunction extractSchemaFields(schema: object): string[] {\n const s = schema as Record<string, unknown>;\n if (s.type !== 'object' || !s.properties) return [];\n return Object.keys(s.properties as Record<string, unknown>);\n}\n\n/**\n * Collection group indexes for `findEdgesGlobal()` queries.\n *\n * These mirror the base collection indexes but with `COLLECTION_GROUP` scope,\n * which allows querying across all subcollections with the given name.\n * Only generated when the registry has edge types with `targetGraph` set,\n * indicating cross-graph edges exist and global queries are likely.\n */\nfunction collectionGroupIndexes(collectionName: string): FirestoreIndex[] {\n return [\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bUid', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bType', order: 'ASCENDING' },\n ],\n },\n ];\n}\n\n/**\n * Generates a Firestore index configuration for a firegraph collection.\n *\n * Always includes the 4 base composite indexes. If an entity discovery result\n * is provided, generates additional data-field indexes for common query\n * patterns on node data fields:\n * (aType, axbType, data.{field})\n *\n * When registry entries with `targetGraph` are provided, also generates\n * collection group indexes for `findEdgesGlobal()` queries. The collection\n * group name defaults to `'graph'` (the standard subgraph name) but can be\n * overridden per `targetGraph` value.\n *\n * @param collection - Firestore collection name (e.g. 'graph')\n * @param entities - Optional discovery result for per-entity data field indexes\n * @param registryEntries - Optional registry entries; when any have `targetGraph`,\n * collection group indexes are generated for the distinct subgraph names\n */\nexport function generateIndexConfig(\n collection: string,\n entities?: DiscoveryResult,\n registryEntries?: ReadonlyArray<RegistryEntry>,\n): FirestoreIndexConfig {\n const indexes = baseIndexes(collection);\n\n if (entities) {\n // Generate data-field indexes for node types.\n // Pattern: (aType, axbType, data.{field}) — covers findNodes with where clauses\n // and findEdges scoped by aType + axbType + data filter.\n for (const [, entity] of entities.nodes) {\n const fields = extractSchemaFields(entity.schema);\n for (const field of fields) {\n indexes.push({\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: `data.${field}`, order: 'ASCENDING' },\n ],\n });\n }\n }\n\n // Generate data-field indexes for edge types.\n // Pattern: (aUid, axbType, data.{field}) — covers forward edge lookups with data filters.\n for (const [, entity] of entities.edges) {\n const fields = extractSchemaFields(entity.schema);\n for (const field of fields) {\n indexes.push({\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: `data.${field}`, order: 'ASCENDING' },\n ],\n });\n }\n }\n }\n\n // Generate collection group indexes when cross-graph edges exist.\n // Each distinct targetGraph value gets its own set of collection group indexes.\n if (registryEntries) {\n const targetGraphNames = new Set<string>();\n for (const entry of registryEntries) {\n if (entry.targetGraph) {\n targetGraphNames.add(entry.targetGraph);\n }\n }\n for (const name of targetGraphNames) {\n indexes.push(...collectionGroupIndexes(name));\n }\n }\n\n return { indexes, fieldOverrides: [] };\n}\n","import http from 'node:http';\nimport type {\n QueryClientOptions,\n SchemaResult,\n GetNodeDetailInput,\n NodeDetailResult,\n GetNodesInput,\n GetNodesResult,\n GetEdgesInput,\n GetEdgesResult,\n TraverseInput,\n TraverseResult,\n TraverseHopResult,\n SearchInput,\n SearchResult,\n SummarizedRecord,\n SummarizedEdge,\n} from './types.js';\nimport { summarizeRecord, summarizeEdge } from './shaping.js';\nimport { readEditorPort } from './config.js';\n\n// --- Error ---\n\nexport type QueryClientErrorCode = 'VALIDATION_ERROR' | 'CONNECTION_FAILED' | 'SERVER_ERROR';\n\nexport class QueryClientError extends Error {\n constructor(\n message: string,\n public readonly code: QueryClientErrorCode,\n ) {\n super(message);\n this.name = 'QueryClientError';\n }\n}\n\n// --- Validation helpers ---\n\nfunction requireString(value: unknown, name: string): asserts value is string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new QueryClientError(`${name} must be a non-empty string`, 'VALIDATION_ERROR');\n }\n}\n\nfunction clampInt(value: number | undefined, min: number, max: number, fallback: number): number {\n if (value == null) return fallback;\n if (!Number.isInteger(value)) {\n throw new QueryClientError(`limit must be an integer`, 'VALIDATION_ERROR');\n }\n return Math.max(min, Math.min(max, value));\n}\n\nfunction validateSortDir(dir: string | undefined): void {\n if (dir != null && dir !== 'asc' && dir !== 'desc') {\n throw new QueryClientError(`sortDir must be 'asc' or 'desc'`, 'VALIDATION_ERROR');\n }\n}\n\n// --- HTTP helpers ---\n\nfunction httpGet(url: string): Promise<string> {\n return new Promise((resolve, reject) => {\n http\n .get(url, (res) => {\n let body = '';\n res.on('data', (c: string) => (body += c));\n res.on('end', () => resolve(body));\n })\n .on('error', (err) => {\n reject(new QueryClientError(`Connection failed: ${err.message}`, 'CONNECTION_FAILED'));\n });\n });\n}\n\nfunction httpPost(url: string, payload: string): Promise<string> {\n const parsed = new URL(url);\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n hostname: parsed.hostname,\n port: parsed.port,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(payload),\n },\n },\n (res) => {\n let body = '';\n res.on('data', (c: string) => (body += c));\n res.on('end', () => resolve(body));\n },\n );\n req.on('error', (err) => {\n reject(new QueryClientError(`Connection failed: ${err.message}`, 'CONNECTION_FAILED'));\n });\n req.write(payload);\n req.end();\n });\n}\n\nfunction parseTrpcResponse(raw: string, procedure: string): unknown {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new QueryClientError(\n `Invalid JSON from ${procedure}: ${raw.slice(0, 200)}`,\n 'SERVER_ERROR',\n );\n }\n if (parsed.error) {\n const msg =\n typeof parsed.error === 'object' && parsed.error !== null\n ? (parsed.error as Record<string, unknown>).message ?? JSON.stringify(parsed.error)\n : String(parsed.error);\n throw new QueryClientError(`Server error from ${procedure}: ${msg}`, 'SERVER_ERROR');\n }\n return (parsed.result as Record<string, unknown>)?.data ?? parsed;\n}\n\n// --- Client ---\n\nexport class QueryClient {\n private readonly baseUrl: string;\n\n constructor(options?: QueryClientOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? readEditorPort();\n this.baseUrl = `http://${host}:${port}/api/trpc`;\n }\n\n private async query(procedure: string, input?: unknown): Promise<unknown> {\n const qs =\n input != null ? `?input=${encodeURIComponent(JSON.stringify(input))}` : '';\n const url = `${this.baseUrl}/${procedure}${qs}`;\n const raw = await httpGet(url);\n return parseTrpcResponse(raw, procedure);\n }\n\n private async mutate(procedure: string, input: unknown): Promise<unknown> {\n const url = `${this.baseUrl}/${procedure}`;\n const raw = await httpPost(url, JSON.stringify(input));\n return parseTrpcResponse(raw, procedure);\n }\n\n // --- Public API ---\n\n async getSchema(): Promise<SchemaResult> {\n const data = (await this.query('getSchema')) as Record<string, unknown>;\n return {\n nodeTypes: ((data.nodeTypes as unknown[]) ?? []).map(\n (t) => (typeof t === 'object' && t !== null ? (t as Record<string, unknown>).type : t) as string,\n ),\n edgeTypes: ((data.edgeTypes as unknown[]) ?? []).map((t) => {\n const e = t as Record<string, unknown>;\n return {\n relation: e.axbType as string,\n from: e.aType as string,\n to: e.bType as string,\n inverseLabel: (e.inverseLabel as string) ?? null,\n };\n }),\n };\n }\n\n async getNodeDetail(input: GetNodeDetailInput): Promise<NodeDetailResult> {\n requireString(input.uid, 'uid');\n const data = (await this.query('getNodeDetail', { uid: input.uid })) as Record<string, unknown>;\n return {\n node: summarizeRecord(data.node as Record<string, unknown> | null),\n outEdges: ((data.outEdges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n inEdges: ((data.inEdges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n };\n }\n\n async getNodes(input: GetNodesInput): Promise<GetNodesResult> {\n const limit = clampInt(input.limit, 1, 200, 25);\n validateSortDir(input.sortDir);\n const data = (await this.query('getNodes', {\n type: input.type,\n limit,\n startAfter: input.startAfter,\n sortBy: input.sortBy,\n sortDir: input.sortDir,\n where: input.where,\n })) as Record<string, unknown>;\n return {\n nodes: ((data.nodes as Record<string, unknown>[]) ?? []).map(summarizeRecord).filter(Boolean) as SummarizedRecord[],\n hasMore: (data.hasMore as boolean) ?? false,\n nextCursor: data.nextCursor as string | null | undefined,\n };\n }\n\n async getEdges(input: GetEdgesInput): Promise<GetEdgesResult> {\n const hasFilter = input.aType || input.aUid || input.axbType || input.bType || input.bUid || (input.where && input.where.length > 0);\n if (!hasFilter) {\n throw new QueryClientError(\n 'getEdges requires at least one filter field (aType, aUid, axbType, bType, bUid, or where)',\n 'VALIDATION_ERROR',\n );\n }\n const limit = clampInt(input.limit, 1, 200, 25);\n validateSortDir(input.sortDir);\n const data = (await this.query('getEdges', {\n aType: input.aType,\n aUid: input.aUid,\n axbType: input.axbType,\n bType: input.bType,\n bUid: input.bUid,\n limit,\n startAfter: input.startAfter,\n sortBy: input.sortBy,\n sortDir: input.sortDir,\n where: input.where,\n })) as Record<string, unknown>;\n return {\n edges: ((data.edges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n hasMore: (data.hasMore as boolean) ?? false,\n nextCursor: data.nextCursor as string | null | undefined,\n };\n }\n\n async traverse(input: TraverseInput): Promise<TraverseResult> {\n requireString(input.startUid, 'startUid');\n if (!input.hops || input.hops.length === 0) {\n throw new QueryClientError('traverse requires at least one hop', 'VALIDATION_ERROR');\n }\n for (let i = 0; i < input.hops.length; i++) {\n const hop = input.hops[i];\n requireString(hop.axbType, `hops[${i}].axbType`);\n if (hop.direction != null && hop.direction !== 'forward' && hop.direction !== 'reverse') {\n throw new QueryClientError(\n `hops[${i}].direction must be 'forward' or 'reverse'`,\n 'VALIDATION_ERROR',\n );\n }\n if (hop.limit != null && (!Number.isInteger(hop.limit) || hop.limit < 1)) {\n throw new QueryClientError(\n `hops[${i}].limit must be a positive integer`,\n 'VALIDATION_ERROR',\n );\n }\n }\n if (input.maxReads != null && (!Number.isInteger(input.maxReads) || input.maxReads < 1)) {\n throw new QueryClientError('maxReads must be a positive integer', 'VALIDATION_ERROR');\n }\n if (input.concurrency != null && (!Number.isInteger(input.concurrency) || input.concurrency < 1)) {\n throw new QueryClientError('concurrency must be a positive integer', 'VALIDATION_ERROR');\n }\n\n const data = (await this.mutate('traverse', input)) as Record<string, unknown>;\n return {\n hops: ((data.hops as Record<string, unknown>[]) ?? []).map((h): TraverseHopResult => ({\n relation: h.axbType as string,\n direction: h.direction as string,\n depth: h.depth as number,\n edgeCount: ((h.edges as unknown[]) ?? []).length,\n edges: ((h.edges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n truncated: (h.truncated as boolean) ?? false,\n })),\n totalReads: (data.totalReads as number) ?? 0,\n truncated: (data.truncated as boolean) ?? false,\n };\n }\n\n async search(input: SearchInput): Promise<SearchResult> {\n requireString(input.q, 'q');\n const limit = clampInt(input.limit, 1, 50, 20);\n const data = (await this.query('search', { q: input.q, limit })) as Record<string, unknown>;\n return {\n results: ((data.results as Record<string, unknown>[]) ?? []).map((r) => {\n const base = summarizeRecord(r);\n if (!base) return null;\n return {\n ...base,\n matchType: (r._matchType as string) ?? null,\n };\n }).filter(Boolean) as (SummarizedRecord & { matchType: string | null })[],\n };\n }\n}\n","import type { SummarizedRecord, SummarizedEdge } from './types.js';\n\nexport function summarizeRecord(r: Record<string, unknown> | null): SummarizedRecord | null {\n if (!r) return null;\n const out: SummarizedRecord = { type: r.aType as string, uid: r.aUid as string };\n const data = r.data as Record<string, unknown> | undefined;\n if (data && typeof data === 'object' && Object.keys(data).length > 0) {\n out.data = data;\n }\n return out;\n}\n\nexport function summarizeEdge(r: Record<string, unknown> | null): SummarizedEdge | null {\n if (!r) return null;\n const out: SummarizedEdge = {\n fromType: r.aType as string,\n fromUid: r.aUid as string,\n relation: r.axbType as string,\n toType: r.bType as string,\n toUid: r.bUid as string,\n };\n const data = r.data as Record<string, unknown> | undefined;\n if (data && typeof data === 'object' && Object.keys(data).length > 0) {\n out.data = data;\n }\n return out;\n}\n","import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst CONFIG_FILES = ['firegraph.config.ts', 'firegraph.config.js', 'firegraph.config.mjs'];\nconst DEFAULT_PORT = 3884;\n\n/**\n * Read the editor port from firegraph config files using regex.\n * Zero-dependency — no jiti needed.\n */\nexport function readEditorPort(cwd?: string): number {\n const dir = cwd ?? process.cwd();\n for (const name of CONFIG_FILES) {\n try {\n const content = readFileSync(join(dir, name), 'utf8');\n const editorBlock = content.match(/editor\\s*:\\s*\\{[^}]*\\}/s)?.[0] ?? '';\n const portMatch = editorBlock.match(/port\\s*:\\s*(\\d+)/);\n if (portMatch) return parseInt(portMatch[1], 10);\n } catch {\n continue;\n }\n }\n return DEFAULT_PORT;\n}\n"],"mappings":"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","names":["import_firestore","import_firestore","import_firestore","resolve","import_node_crypto","Ajv","resolve","edges","import_node_fs","import_node_path","resolve","http"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/docid.ts","../src/internal/constants.ts","../src/record.ts","../src/errors.ts","../src/query.ts","../src/internal/firestore-adapter.ts","../src/internal/pipeline-adapter.ts","../src/transaction.ts","../src/query-safety.ts","../src/batch.ts","../src/bulk.ts","../src/dynamic-registry.ts","../src/json-schema.ts","../src/scope.ts","../src/registry.ts","../src/id.ts","../src/traverse.ts","../src/views.ts","../src/config.ts","../src/discover.ts","../src/cross-graph.ts","../src/codegen/index.ts","../src/indexes.ts","../src/query-client/client.ts","../src/query-client/shaping.ts","../src/query-client/config.ts"],"sourcesContent":["export { createGraphClient } from './client.js';\nexport { createRegistry, createMergedRegistry } from './registry.js';\nexport {\n createRegistryFromGraph,\n createBootstrapRegistry,\n generateDeterministicUid,\n META_NODE_TYPE,\n META_EDGE_TYPE,\n NODE_TYPE_SCHEMA,\n EDGE_TYPE_SCHEMA,\n BOOTSTRAP_ENTRIES,\n} from './dynamic-registry.js';\nexport { generateId } from './id.js';\nexport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nexport { buildNodeRecord, buildEdgeRecord } from './record.js';\nexport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nexport { createTraversal } from './traverse.js';\nexport { defineViews } from './views.js';\nexport { defineConfig, resolveView } from './config.js';\nexport { discoverEntities } from './discover.js';\nexport { matchScope, matchScopeAny } from './scope.js';\nexport { resolveAncestorCollection, isAncestorUid } from './cross-graph.js';\nexport { compileSchema, jsonSchemaToFieldMeta } from './json-schema.js';\n\nexport {\n FiregraphError,\n NodeNotFoundError,\n EdgeNotFoundError,\n ValidationError,\n RegistryViolationError,\n InvalidQueryError,\n TraversalError,\n DynamicRegistryError,\n QuerySafetyError,\n RegistryScopeError,\n} from './errors.js';\n\nexport { DiscoveryError } from './discover.js';\n\nexport type {\n GraphRecord,\n StoredGraphRecord,\n WhereClause,\n FindEdgesParams,\n FindNodesParams,\n QueryPlan,\n QueryFilter,\n QueryOptions,\n RegistryEntry,\n GraphClientOptions,\n GraphRegistry,\n GraphReader,\n GraphWriter,\n GraphClient,\n GraphTransaction,\n GraphBatch,\n DynamicGraphClient,\n DynamicRegistryConfig,\n DefineTypeOptions,\n NodeTypeData,\n EdgeTypeData,\n HopDefinition,\n TraversalOptions,\n HopResult,\n TraversalResult,\n TraversalBuilder,\n EdgeTopology,\n DiscoveredEntity,\n DiscoveryResult,\n BulkOptions,\n BulkProgress,\n BulkResult,\n BulkBatchError,\n CascadeResult,\n QueryMode,\n ScanProtection,\n} from './types.js';\n\nexport type {\n ViewComponentClass,\n EntityViewConfig,\n ViewRegistryInput,\n ViewMeta,\n EntityViewMeta,\n ViewRegistry,\n} from './views.js';\n\nexport type {\n FiregraphConfig,\n ViewContext,\n ViewResolverConfig,\n ViewDefaultsConfig,\n} from './config.js';\n\nexport type { FieldMeta } from './json-schema.js';\n\nexport type { DiscoveryWarning, DiscoverResult } from './discover.js';\n\nexport { generateTypes } from './codegen/index.js';\nexport type { CodegenOptions } from './codegen/index.js';\n\nexport { generateIndexConfig } from './indexes.js';\nexport type { FirestoreIndexConfig, FirestoreIndex, FirestoreIndexField } from './indexes.js';\n\nexport { analyzeQuerySafety } from './query-safety.js';\nexport type { QuerySafetyResult } from './query-safety.js';\n\nexport { DEFAULT_QUERY_LIMIT } from './internal/constants.js';\n\nexport { QueryClient, QueryClientError } from './query-client/index.js';\nexport type { QueryClientErrorCode, QueryClientOptions } from './query-client/index.js';\n","import { FieldValue } from '@google-cloud/firestore';\nimport type { Firestore } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport {\n createFirestoreAdapter,\n createTransactionAdapter,\n createBatchAdapter,\n} from './internal/firestore-adapter.js';\nimport type { FirestoreAdapter } from './internal/firestore-adapter.js';\nimport { createPipelineQueryAdapter } from './internal/pipeline-adapter.js';\nimport type { PipelineQueryAdapter } from './internal/pipeline-adapter.js';\nimport { GraphTransactionImpl } from './transaction.js';\nimport { GraphBatchImpl } from './batch.js';\nimport {\n removeNodeCascade as removeNodeCascadeImpl,\n bulkRemoveEdges as bulkRemoveEdgesImpl,\n} from './bulk.js';\nimport { DynamicRegistryError, FiregraphError, QuerySafetyError } from './errors.js';\nimport { analyzeQuerySafety } from './query-safety.js';\nimport {\n createBootstrapRegistry,\n createRegistryFromGraph,\n generateDeterministicUid,\n META_NODE_TYPE,\n META_EDGE_TYPE,\n} from './dynamic-registry.js';\nimport { createMergedRegistry } from './registry.js';\nimport type {\n DefineTypeOptions,\n DynamicGraphClient,\n DynamicRegistryConfig,\n GraphClient,\n GraphClientOptions,\n GraphReader,\n GraphRegistry,\n GraphTransaction,\n GraphBatch,\n StoredGraphRecord,\n FindEdgesParams,\n FindNodesParams,\n EdgeTopology,\n QueryFilter,\n QueryOptions,\n QueryMode,\n ScanProtection,\n BulkOptions,\n BulkResult,\n CascadeResult,\n} from './types.js';\n\nlet _standardModeWarned = false;\n\nconst RESERVED_TYPE_NAMES = new Set([META_NODE_TYPE, META_EDGE_TYPE]);\n\nclass GraphClientImpl implements DynamicGraphClient {\n private readonly adapter: FirestoreAdapter;\n private readonly pipelineAdapter?: PipelineQueryAdapter;\n private readonly queryMode: QueryMode;\n readonly scanProtection: ScanProtection;\n\n // Static mode\n private readonly staticRegistry?: GraphRegistry;\n\n // Dynamic mode\n private readonly dynamicConfig?: DynamicRegistryConfig;\n private readonly bootstrapRegistry?: GraphRegistry;\n private dynamicRegistry?: GraphRegistry;\n private readonly metaAdapter?: FirestoreAdapter;\n private readonly metaPipelineAdapter?: PipelineQueryAdapter;\n\n // Subgraph scope tracking\n private readonly scopePath: string;\n\n constructor(\n private readonly db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n /** @internal Scope path for subgraph clients (empty string = root). */\n scopePath: string = '',\n ) {\n this.scopePath = scopePath;\n this.adapter = createFirestoreAdapter(db, collectionPath);\n\n if (options?.registryMode) {\n this.dynamicConfig = options.registryMode;\n this.bootstrapRegistry = createBootstrapRegistry();\n\n // Merged mode: static registry provided alongside dynamic config.\n // Static entries take priority; dynamic can only add new types.\n if (options.registry) {\n this.staticRegistry = options.registry;\n }\n\n // If meta-collection differs from main, create separate adapter\n const metaCollectionPath = options.registryMode.collection;\n if (metaCollectionPath && metaCollectionPath !== collectionPath) {\n this.metaAdapter = createFirestoreAdapter(db, metaCollectionPath);\n }\n } else {\n this.staticRegistry = options?.registry;\n }\n\n // Resolve effective query mode\n const requestedMode = options?.queryMode ?? 'pipeline';\n const isEmulator = !!process.env.FIRESTORE_EMULATOR_HOST;\n\n if (isEmulator) {\n // Emulator doesn't support Pipeline operations — silently fall back\n this.queryMode = 'standard';\n } else {\n this.queryMode = requestedMode;\n }\n\n // Warn once when standard mode is explicitly chosen outside the emulator\n if (\n this.queryMode === 'standard' &&\n !isEmulator &&\n requestedMode === 'standard' &&\n !_standardModeWarned\n ) {\n _standardModeWarned = true;\n console.warn(\n '[firegraph] Standard query mode enabled. This is NOT recommended for production:\\n' +\n ' - Enterprise Firestore: data.* filters cause full collection scans (high billing)\\n' +\n ' - Standard Firestore: data.* filters without composite indexes will fail\\n' +\n ' See: https://github.com/typicalday/firegraph#query-modes',\n );\n }\n\n // Scan protection\n this.scanProtection = options?.scanProtection ?? 'error';\n\n // Create pipeline adapter when in pipeline mode\n if (this.queryMode === 'pipeline') {\n this.pipelineAdapter = createPipelineQueryAdapter(db, collectionPath);\n\n // Also create pipeline adapter for meta-collection if separate\n if (this.metaAdapter) {\n this.metaPipelineAdapter = createPipelineQueryAdapter(\n db,\n options!.registryMode!.collection!,\n );\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Registry routing\n // ---------------------------------------------------------------------------\n\n /**\n * Get the appropriate registry for validating a write to the given type.\n *\n * - Static-only mode: returns staticRegistry (or undefined if none set)\n * - Dynamic mode (pure or merged):\n * - Meta-types (nodeType, edgeType): validated against bootstrapRegistry\n * - Domain types: validated against dynamicRegistry (falls back to\n * bootstrapRegistry which rejects unknown types)\n * - Merged mode: dynamicRegistry is a merged wrapper (static + dynamic\n * extension), so static entries take priority automatically.\n */\n private getRegistryForType(aType: string): GraphRegistry | undefined {\n if (!this.dynamicConfig) return this.staticRegistry;\n\n if (aType === META_NODE_TYPE || aType === META_EDGE_TYPE) {\n return this.bootstrapRegistry;\n }\n\n return this.dynamicRegistry ?? this.staticRegistry ?? this.bootstrapRegistry;\n }\n\n /**\n * Get the Firestore adapter for writing the given type.\n * Meta-types route to metaAdapter if a separate collection is configured.\n */\n private getAdapterForType(aType: string): FirestoreAdapter {\n if (\n this.metaAdapter &&\n (aType === META_NODE_TYPE || aType === META_EDGE_TYPE)\n ) {\n return this.metaAdapter;\n }\n return this.adapter;\n }\n\n /**\n * Get the combined registry for transaction/batch context.\n * In static-only mode, returns staticRegistry.\n * In dynamic mode, returns dynamicRegistry (which includes bootstrap entries)\n * or falls back to staticRegistry (merged mode) or bootstrapRegistry.\n */\n private getCombinedRegistry(): GraphRegistry | undefined {\n if (!this.dynamicConfig) return this.staticRegistry;\n return this.dynamicRegistry ?? this.staticRegistry ?? this.bootstrapRegistry;\n }\n\n // ---------------------------------------------------------------------------\n // Query dispatch\n // ---------------------------------------------------------------------------\n\n /**\n * Dispatch a query to the appropriate adapter based on queryMode.\n * Pipeline queries use the PipelineQueryAdapter; standard queries\n * use the FirestoreAdapter.\n */\n private executeQuery(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n if (this.pipelineAdapter) {\n return this.pipelineAdapter.query(filters, options);\n }\n return this.adapter.query(filters, options);\n }\n\n /**\n * Check whether a query's filter set is safe (matches a known index pattern).\n * Throws QuerySafetyError or logs a warning depending on scanProtection config.\n */\n private checkQuerySafety(filters: QueryFilter[], allowCollectionScan?: boolean): void {\n if (allowCollectionScan || this.scanProtection === 'off') return;\n\n const result = analyzeQuerySafety(filters);\n if (result.safe) return;\n\n if (this.scanProtection === 'error') {\n throw new QuerySafetyError(result.reason!);\n }\n\n // scanProtection === 'warn'\n console.warn(`[firegraph] Query safety warning: ${result.reason}`);\n }\n\n // ---------------------------------------------------------------------------\n // GraphReader\n // ---------------------------------------------------------------------------\n\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n const docId = computeNodeDocId(uid);\n return this.adapter.getDoc(docId);\n }\n\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n return this.adapter.getDoc(docId);\n }\n\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await this.getEdge(aUid, axbType, bUid);\n return record !== null;\n }\n\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.executeQuery(plan.filters, plan.options);\n }\n\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.executeQuery(plan.filters, plan.options);\n }\n\n // ---------------------------------------------------------------------------\n // GraphWriter\n // ---------------------------------------------------------------------------\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n const registry = this.getRegistryForType(aType);\n if (registry) {\n registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const adapter = this.getAdapterForType(aType);\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n await adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const registry = this.getRegistryForType(aType);\n if (registry) {\n registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const adapter = this.getAdapterForType(aType);\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n await adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n await this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n await this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n await this.adapter.deleteDoc(docId);\n }\n\n // ---------------------------------------------------------------------------\n // Transactions & Batches\n // ---------------------------------------------------------------------------\n\n async runTransaction<T>(fn: (tx: GraphTransaction) => Promise<T>): Promise<T> {\n return this.db.runTransaction(async (firestoreTx) => {\n const adapter = createTransactionAdapter(\n this.db,\n this.adapter.collectionPath,\n firestoreTx,\n );\n // Transactions always use standard queries — Pipeline is not transactionally bound\n const graphTx = new GraphTransactionImpl(adapter, this.getCombinedRegistry(), this.scanProtection, this.scopePath);\n return fn(graphTx);\n });\n }\n\n batch(): GraphBatch {\n const adapter = createBatchAdapter(this.db, this.adapter.collectionPath);\n return new GraphBatchImpl(adapter, this.getCombinedRegistry(), this.scopePath);\n }\n\n // ---------------------------------------------------------------------------\n // Subgraph\n // ---------------------------------------------------------------------------\n\n subgraph(parentNodeUid: string, name: string = 'graph'): GraphClient {\n if (!parentNodeUid || parentNodeUid.includes('/')) {\n throw new FiregraphError(\n `Invalid parentNodeUid for subgraph: \"${parentNodeUid}\". ` +\n 'Must be a non-empty string without \"/\".',\n 'INVALID_SUBGRAPH',\n );\n }\n if (name.includes('/')) {\n throw new FiregraphError(\n `Subgraph name must not contain \"/\": got \"${name}\". ` +\n 'Use chained .subgraph() calls for nested subgraphs.',\n 'INVALID_SUBGRAPH',\n );\n }\n const subCollectionPath = `${this.adapter.collectionPath}/${parentNodeUid}/${name}`;\n const newScopePath = this.scopePath ? `${this.scopePath}/${name}` : name;\n\n return new GraphClientImpl(\n this.db,\n subCollectionPath,\n {\n registry: this.getCombinedRegistry(),\n queryMode: this.queryMode === 'pipeline' ? 'pipeline' : 'standard',\n scanProtection: this.scanProtection,\n },\n newScopePath,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Collection group query\n // ---------------------------------------------------------------------------\n\n async findEdgesGlobal(\n params: FindEdgesParams,\n collectionName?: string,\n ): Promise<StoredGraphRecord[]> {\n const name = collectionName ?? this.adapter.collectionPath.split('/').pop()!;\n const plan = buildEdgeQueryPlan(params);\n\n if (plan.strategy === 'get') {\n throw new FiregraphError(\n 'findEdgesGlobal() requires a query, not a direct document lookup. ' +\n 'Omit one of aUid/axbType/bUid to force a query strategy.',\n 'INVALID_QUERY',\n );\n }\n\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n\n // Use Firestore collection group query\n const collectionGroupRef = this.db.collectionGroup(name);\n let q: import('@google-cloud/firestore').Query = collectionGroupRef;\n for (const f of plan.filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (plan.options?.orderBy) {\n q = q.orderBy(plan.options.orderBy.field, plan.options.orderBy.direction ?? 'asc');\n }\n if (plan.options?.limit !== undefined) {\n q = q.limit(plan.options.limit);\n }\n\n const snap = await q.get();\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n }\n\n // ---------------------------------------------------------------------------\n // Bulk operations\n // ---------------------------------------------------------------------------\n\n async removeNodeCascade(uid: string, options?: BulkOptions): Promise<CascadeResult> {\n return removeNodeCascadeImpl(this.db, this.adapter.collectionPath, this, uid, options);\n }\n\n async bulkRemoveEdges(params: FindEdgesParams, options?: BulkOptions): Promise<BulkResult> {\n return bulkRemoveEdgesImpl(this.db, this.adapter.collectionPath, this, params, options);\n }\n\n // ---------------------------------------------------------------------------\n // Dynamic registry methods\n // ---------------------------------------------------------------------------\n\n async defineNodeType(\n name: string,\n jsonSchema: object,\n description?: string,\n options?: DefineTypeOptions,\n ): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'defineNodeType() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n if (RESERVED_TYPE_NAMES.has(name)) {\n throw new DynamicRegistryError(\n `Cannot define type \"${name}\": this name is reserved for the meta-registry.`,\n );\n }\n\n // Merged mode: reject if static registry already defines this node type\n if (this.staticRegistry?.lookup(name, NODE_RELATION, name)) {\n throw new DynamicRegistryError(\n `Cannot define node type \"${name}\": already defined in the static registry.`,\n );\n }\n\n const uid = generateDeterministicUid(META_NODE_TYPE, name);\n const data: Record<string, unknown> = { name, jsonSchema };\n if (description !== undefined) data.description = description;\n if (options?.titleField !== undefined) data.titleField = options.titleField;\n if (options?.subtitleField !== undefined) data.subtitleField = options.subtitleField;\n if (options?.viewTemplate !== undefined) data.viewTemplate = options.viewTemplate;\n if (options?.viewCss !== undefined) data.viewCss = options.viewCss;\n if (options?.allowedIn !== undefined) data.allowedIn = options.allowedIn;\n\n await this.putNode(META_NODE_TYPE, uid, data);\n }\n\n async defineEdgeType(\n name: string,\n topology: EdgeTopology,\n jsonSchema?: object,\n description?: string,\n options?: DefineTypeOptions,\n ): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'defineEdgeType() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n if (RESERVED_TYPE_NAMES.has(name)) {\n throw new DynamicRegistryError(\n `Cannot define type \"${name}\": this name is reserved for the meta-registry.`,\n );\n }\n\n // Merged mode: reject if static registry already defines any triple for this edge\n if (this.staticRegistry) {\n const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];\n const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];\n for (const aType of fromTypes) {\n for (const bType of toTypes) {\n if (this.staticRegistry.lookup(aType, name, bType)) {\n throw new DynamicRegistryError(\n `Cannot define edge type \"${name}\" for (${aType}) -> (${bType}): already defined in the static registry.`,\n );\n }\n }\n }\n }\n\n const uid = generateDeterministicUid(META_EDGE_TYPE, name);\n const data: Record<string, unknown> = {\n name,\n from: topology.from,\n to: topology.to,\n };\n if (jsonSchema !== undefined) data.jsonSchema = jsonSchema;\n if (topology.inverseLabel !== undefined) data.inverseLabel = topology.inverseLabel;\n if (topology.targetGraph !== undefined) data.targetGraph = topology.targetGraph;\n if (description !== undefined) data.description = description;\n if (options?.titleField !== undefined) data.titleField = options.titleField;\n if (options?.subtitleField !== undefined) data.subtitleField = options.subtitleField;\n if (options?.viewTemplate !== undefined) data.viewTemplate = options.viewTemplate;\n if (options?.viewCss !== undefined) data.viewCss = options.viewCss;\n if (options?.allowedIn !== undefined) data.allowedIn = options.allowedIn;\n\n await this.putNode(META_EDGE_TYPE, uid, data);\n }\n\n async reloadRegistry(): Promise<void> {\n if (!this.dynamicConfig) {\n throw new DynamicRegistryError(\n 'reloadRegistry() is only available in dynamic registry mode. ' +\n 'Pass registryMode: { mode: \"dynamic\" } to createGraphClient().',\n );\n }\n\n const reader = this.createMetaReader();\n const dynamicOnly = await createRegistryFromGraph(reader);\n\n if (this.staticRegistry) {\n // Merged mode: static entries take priority over dynamic ones\n this.dynamicRegistry = createMergedRegistry(this.staticRegistry, dynamicOnly);\n } else {\n this.dynamicRegistry = dynamicOnly;\n }\n }\n\n /**\n * Create a GraphReader for the meta-collection.\n * If meta-collection is the same as main collection, returns `this`.\n * If separate, creates a lightweight reader wrapping the meta adapter.\n */\n private createMetaReader(): GraphReader {\n if (!this.metaAdapter) return this;\n\n const adapter = this.metaAdapter;\n const pipelineAdapter = this.metaPipelineAdapter;\n\n const executeMetaQuery = (\n filters: QueryFilter[],\n options?: QueryOptions,\n ): Promise<StoredGraphRecord[]> => {\n if (pipelineAdapter) return pipelineAdapter.query(filters, options);\n return adapter.query(filters, options);\n };\n\n return {\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n return adapter.getDoc(computeNodeDocId(uid));\n },\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n return adapter.getDoc(computeEdgeDocId(aUid, axbType, bUid));\n },\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await adapter.getDoc(computeEdgeDocId(aUid, axbType, bUid));\n return record !== null;\n },\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n return executeMetaQuery(plan.filters, plan.options);\n },\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n return executeMetaQuery(plan.filters, plan.options);\n },\n };\n }\n}\n\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options: GraphClientOptions & { registryMode: DynamicRegistryConfig },\n): DynamicGraphClient;\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n): GraphClient;\nexport function createGraphClient(\n db: Firestore,\n collectionPath: string,\n options?: GraphClientOptions,\n): GraphClient | DynamicGraphClient {\n return new GraphClientImpl(db, collectionPath, options) as GraphClient | DynamicGraphClient;\n}\n","import { createHash } from 'node:crypto';\nimport { SHARD_SEPARATOR } from './internal/constants.js';\n\nexport function computeNodeDocId(uid: string): string {\n return uid;\n}\n\nexport function computeEdgeDocId(aUid: string, axbType: string, bUid: string): string {\n const composite = `${aUid}${SHARD_SEPARATOR}${axbType}${SHARD_SEPARATOR}${bUid}`;\n const hash = createHash('sha256').update(composite).digest('hex');\n const shard = hash[0];\n return `${shard}${SHARD_SEPARATOR}${aUid}${SHARD_SEPARATOR}${axbType}${SHARD_SEPARATOR}${bUid}`;\n}\n","export const NODE_RELATION = 'is';\n\n/**\n * Default result limit applied to findEdges/findNodes queries\n * when no explicit limit is provided. Prevents unbounded result sets\n * that could be expensive on Enterprise Firestore.\n */\nexport const DEFAULT_QUERY_LIMIT = 500;\n\n/**\n * Fields that are part of the firegraph record structure (not user data).\n * Used by the query planner and safety analysis to distinguish builtin\n * fields from data.* fields.\n */\nexport const BUILTIN_FIELDS = new Set([\n 'aType', 'aUid', 'axbType', 'bType', 'bUid', 'createdAt', 'updatedAt',\n]);\n\nexport const SHARD_ALGORITHM = 'sha256';\nexport const SHARD_SEPARATOR = ':';\nexport const SHARD_BUCKETS = 16;\n","import { FieldValue } from '@google-cloud/firestore';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { GraphRecord } from './types.js';\n\nexport function buildNodeRecord(\n aType: string,\n uid: string,\n data: Record<string, unknown>,\n): GraphRecord {\n const now = FieldValue.serverTimestamp();\n return {\n aType,\n aUid: uid,\n axbType: NODE_RELATION,\n bType: aType,\n bUid: uid,\n data,\n createdAt: now,\n updatedAt: now,\n };\n}\n\nexport function buildEdgeRecord(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n): GraphRecord {\n const now = FieldValue.serverTimestamp();\n return {\n aType,\n aUid,\n axbType,\n bType,\n bUid,\n data,\n createdAt: now,\n updatedAt: now,\n };\n}\n","export class FiregraphError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'FiregraphError';\n }\n}\n\nexport class NodeNotFoundError extends FiregraphError {\n constructor(uid: string) {\n super(`Node not found: ${uid}`, 'NODE_NOT_FOUND');\n this.name = 'NodeNotFoundError';\n }\n}\n\nexport class EdgeNotFoundError extends FiregraphError {\n constructor(aUid: string, axbType: string, bUid: string) {\n super(`Edge not found: ${aUid} -[${axbType}]-> ${bUid}`, 'EDGE_NOT_FOUND');\n this.name = 'EdgeNotFoundError';\n }\n}\n\nexport class ValidationError extends FiregraphError {\n constructor(\n message: string,\n public readonly details?: unknown,\n ) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class RegistryViolationError extends FiregraphError {\n constructor(aType: string, axbType: string, bType: string) {\n super(\n `Unregistered triple: (${aType}) -[${axbType}]-> (${bType})`,\n 'REGISTRY_VIOLATION',\n );\n this.name = 'RegistryViolationError';\n }\n}\n\nexport class InvalidQueryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'INVALID_QUERY');\n this.name = 'InvalidQueryError';\n }\n}\n\nexport class TraversalError extends FiregraphError {\n constructor(message: string) {\n super(message, 'TRAVERSAL_ERROR');\n this.name = 'TraversalError';\n }\n}\n\nexport class DynamicRegistryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'DYNAMIC_REGISTRY_ERROR');\n this.name = 'DynamicRegistryError';\n }\n}\n\nexport class QuerySafetyError extends FiregraphError {\n constructor(message: string) {\n super(message, 'QUERY_SAFETY');\n this.name = 'QuerySafetyError';\n }\n}\n\nexport class RegistryScopeError extends FiregraphError {\n constructor(aType: string, axbType: string, bType: string, scopePath: string, allowedIn: string[]) {\n super(\n `Type (${aType}) -[${axbType}]-> (${bType}) is not allowed at scope \"${scopePath || 'root'}\". ` +\n `Allowed in: [${allowedIn.join(', ')}]`,\n 'REGISTRY_SCOPE',\n );\n this.name = 'RegistryScopeError';\n }\n}\n","import { NODE_RELATION, DEFAULT_QUERY_LIMIT, BUILTIN_FIELDS } from './internal/constants.js';\nimport { computeEdgeDocId } from './docid.js';\nimport { InvalidQueryError } from './errors.js';\nimport type { FindEdgesParams, FindNodesParams, QueryPlan, QueryFilter } from './types.js';\n\nexport function buildEdgeQueryPlan(params: FindEdgesParams): QueryPlan {\n const { aType, aUid, axbType, bType, bUid, limit, orderBy } = params;\n\n if (aUid && axbType && bUid && !params.where?.length) {\n return { strategy: 'get', docId: computeEdgeDocId(aUid, axbType, bUid) };\n }\n\n const filters: QueryFilter[] = [];\n\n if (aType) filters.push({ field: 'aType', op: '==', value: aType });\n if (aUid) filters.push({ field: 'aUid', op: '==', value: aUid });\n if (axbType) filters.push({ field: 'axbType', op: '==', value: axbType });\n if (bType) filters.push({ field: 'bType', op: '==', value: bType });\n if (bUid) filters.push({ field: 'bUid', op: '==', value: bUid });\n\n if (params.where) {\n for (const clause of params.where) {\n const field = BUILTIN_FIELDS.has(clause.field) ? clause.field\n : clause.field.startsWith('data.') ? clause.field : `data.${clause.field}`;\n filters.push({ field, op: clause.op, value: clause.value });\n }\n }\n\n if (filters.length === 0) {\n throw new InvalidQueryError('findEdges requires at least one filter parameter');\n }\n\n // limit: undefined → apply DEFAULT_QUERY_LIMIT\n // limit: 0 → no limit (unlimited, used by internal bulk operations)\n // limit: N → use N\n const effectiveLimit = limit === undefined ? DEFAULT_QUERY_LIMIT : (limit || undefined);\n return { strategy: 'query', filters, options: { limit: effectiveLimit, orderBy } };\n}\n\nexport function buildNodeQueryPlan(params: FindNodesParams): QueryPlan {\n const { aType, limit, orderBy } = params;\n\n const filters: QueryFilter[] = [\n { field: 'aType', op: '==', value: aType },\n { field: 'axbType', op: '==', value: NODE_RELATION },\n ];\n\n if (params.where) {\n for (const clause of params.where) {\n const field = BUILTIN_FIELDS.has(clause.field) ? clause.field\n : clause.field.startsWith('data.') ? clause.field : `data.${clause.field}`;\n filters.push({ field, op: clause.op, value: clause.value });\n }\n }\n\n const effectiveLimit = limit === undefined ? DEFAULT_QUERY_LIMIT : (limit || undefined);\n return { strategy: 'query', filters, options: { limit: effectiveLimit, orderBy } };\n}\n","import type { Firestore, Query, Transaction } from '@google-cloud/firestore';\nimport type { StoredGraphRecord, QueryFilter, QueryOptions } from '../types.js';\n\nexport interface FirestoreAdapter {\n collectionPath: string;\n getDoc(docId: string): Promise<StoredGraphRecord | null>;\n setDoc(docId: string, data: Record<string, unknown>): Promise<void>;\n updateDoc(docId: string, data: Record<string, unknown>): Promise<void>;\n deleteDoc(docId: string): Promise<void>;\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\nexport function createFirestoreAdapter(\n db: Firestore,\n collectionPath: string,\n): FirestoreAdapter {\n const collectionRef = db.collection(collectionPath);\n\n return {\n collectionPath,\n\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n const snap = await collectionRef.doc(docId).get();\n if (!snap.exists) return null;\n return snap.data() as StoredGraphRecord;\n },\n\n async setDoc(docId: string, data: Record<string, unknown>): Promise<void> {\n await collectionRef.doc(docId).set(data);\n },\n\n async updateDoc(docId: string, data: Record<string, unknown>): Promise<void> {\n await collectionRef.doc(docId).update(data);\n },\n\n async deleteDoc(docId: string): Promise<void> {\n await collectionRef.doc(docId).delete();\n },\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n let q: Query = collectionRef;\n for (const f of filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (options?.orderBy) {\n q = q.orderBy(options.orderBy.field, options.orderBy.direction ?? 'asc');\n }\n if (options?.limit !== undefined) {\n q = q.limit(options.limit);\n }\n const snap = await q.get();\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n },\n };\n}\n\nexport interface TransactionAdapter {\n getDoc(docId: string): Promise<StoredGraphRecord | null>;\n setDoc(docId: string, data: Record<string, unknown>): void;\n updateDoc(docId: string, data: Record<string, unknown>): void;\n deleteDoc(docId: string): void;\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\nexport function createTransactionAdapter(\n db: Firestore,\n collectionPath: string,\n tx: Transaction,\n): TransactionAdapter {\n const collectionRef = db.collection(collectionPath);\n\n return {\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n const snap = await tx.get(collectionRef.doc(docId));\n if (!snap.exists) return null;\n return snap.data() as StoredGraphRecord;\n },\n\n setDoc(docId: string, data: Record<string, unknown>): void {\n tx.set(collectionRef.doc(docId), data);\n },\n\n updateDoc(docId: string, data: Record<string, unknown>): void {\n tx.update(collectionRef.doc(docId), data);\n },\n\n deleteDoc(docId: string): void {\n tx.delete(collectionRef.doc(docId));\n },\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n let q: Query = collectionRef;\n for (const f of filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (options?.orderBy) {\n q = q.orderBy(options.orderBy.field, options.orderBy.direction ?? 'asc');\n }\n if (options?.limit !== undefined) {\n q = q.limit(options.limit);\n }\n const snap = await tx.get(q);\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n },\n };\n}\n\nexport interface BatchAdapter {\n setDoc(docId: string, data: Record<string, unknown>): void;\n updateDoc(docId: string, data: Record<string, unknown>): void;\n deleteDoc(docId: string): void;\n commit(): Promise<void>;\n}\n\nexport function createBatchAdapter(\n db: Firestore,\n collectionPath: string,\n): BatchAdapter {\n const collectionRef = db.collection(collectionPath);\n const batch = db.batch();\n\n return {\n setDoc(docId: string, data: Record<string, unknown>): void {\n batch.set(collectionRef.doc(docId), data);\n },\n\n updateDoc(docId: string, data: Record<string, unknown>): void {\n batch.update(collectionRef.doc(docId), data);\n },\n\n deleteDoc(docId: string): void {\n batch.delete(collectionRef.doc(docId));\n },\n\n async commit(): Promise<void> {\n await batch.commit();\n },\n };\n}\n","/**\n * Pipeline query adapter — translates QueryFilter[] to Firestore Pipeline\n * expressions and executes them via db.pipeline().\n *\n * Only handles query() — doc-level operations (get/set/update/delete) stay\n * on the standard FirestoreAdapter.\n */\nimport type { Firestore } from '@google-cloud/firestore';\nimport type { StoredGraphRecord, QueryFilter, QueryOptions } from '../types.js';\n\n/**\n * Minimal interface for the Pipeline query adapter.\n * Only implements the query path — doc operations are handled by FirestoreAdapter.\n */\nexport interface PipelineQueryAdapter {\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;\n}\n\n/**\n * Lazily loaded Pipelines module. We use dynamic import so that standard-mode\n * users (and the emulator) don't pull in pipeline-related code at module load.\n */\nlet _Pipelines: typeof import('@google-cloud/firestore').Pipelines | null = null;\n\nasync function getPipelines(): Promise<typeof import('@google-cloud/firestore').Pipelines> {\n if (!_Pipelines) {\n const mod = await import('@google-cloud/firestore');\n _Pipelines = mod.Pipelines;\n }\n return _Pipelines;\n}\n\ntype PipelinesType = typeof import('@google-cloud/firestore').Pipelines;\ntype BooleanExpr = import('@google-cloud/firestore').Pipelines.BooleanExpression;\n\n/**\n * Maps a QueryFilter to a Pipeline BooleanExpression.\n *\n * Uses the string-based overloads (e.g. `equal(fieldName, value)`) which\n * accept `unknown` values, avoiding type issues with `constant()` overloads.\n */\nfunction buildFilterExpression(\n P: PipelinesType,\n filter: QueryFilter,\n): BooleanExpr {\n const { field: fieldName, op, value } = filter;\n\n switch (op) {\n case '==':\n return P.equal(fieldName, value);\n case '!=':\n return P.notEqual(fieldName, value);\n case '<':\n return P.lessThan(fieldName, value);\n case '<=':\n return P.lessThanOrEqual(fieldName, value);\n case '>':\n return P.greaterThan(fieldName, value);\n case '>=':\n return P.greaterThanOrEqual(fieldName, value);\n case 'in':\n return P.equalAny(fieldName, value as Array<unknown>);\n case 'not-in':\n return P.notEqualAny(fieldName, value as Array<unknown>);\n case 'array-contains':\n return P.arrayContains(fieldName, value);\n case 'array-contains-any':\n return P.arrayContainsAny(fieldName, value as Array<unknown>);\n default:\n throw new Error(`Unsupported filter op for pipeline mode: ${op}`);\n }\n}\n\nexport function createPipelineQueryAdapter(\n db: Firestore,\n collectionPath: string,\n): PipelineQueryAdapter {\n return {\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n const P = await getPipelines();\n\n // Build pipeline\n let pipeline = db.pipeline().collection(collectionPath);\n\n // Apply filters\n if (filters.length === 1) {\n pipeline = pipeline.where(buildFilterExpression(P, filters[0]));\n } else if (filters.length > 1) {\n const [first, second, ...rest] = filters.map(f => buildFilterExpression(P, f));\n pipeline = pipeline.where(P.and(first, second, ...rest));\n }\n\n // Apply sort\n if (options?.orderBy) {\n const f = P.field(options.orderBy.field);\n const ordering = options.orderBy.direction === 'desc'\n ? f.descending()\n : f.ascending();\n pipeline = pipeline.sort(ordering);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n pipeline = pipeline.limit(options.limit);\n }\n\n const snap = await pipeline.execute();\n return snap.results.map(r => r.data() as StoredGraphRecord);\n },\n };\n}\n","import { FieldValue } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { buildEdgeQueryPlan, buildNodeQueryPlan } from './query.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport { QuerySafetyError } from './errors.js';\nimport { analyzeQuerySafety } from './query-safety.js';\nimport type { TransactionAdapter } from './internal/firestore-adapter.js';\nimport type {\n GraphTransaction,\n GraphRegistry,\n StoredGraphRecord,\n FindEdgesParams,\n FindNodesParams,\n ScanProtection,\n QueryFilter,\n} from './types.js';\n\nexport class GraphTransactionImpl implements GraphTransaction {\n constructor(\n private readonly adapter: TransactionAdapter,\n private readonly registry?: GraphRegistry,\n private readonly scanProtection: ScanProtection = 'error',\n private readonly scopePath: string = '',\n ) {}\n\n async getNode(uid: string): Promise<StoredGraphRecord | null> {\n const docId = computeNodeDocId(uid);\n return this.adapter.getDoc(docId);\n }\n\n async getEdge(aUid: string, axbType: string, bUid: string): Promise<StoredGraphRecord | null> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n return this.adapter.getDoc(docId);\n }\n\n async edgeExists(aUid: string, axbType: string, bUid: string): Promise<boolean> {\n const record = await this.getEdge(aUid, axbType, bUid);\n return record !== null;\n }\n\n private checkQuerySafety(filters: QueryFilter[], allowCollectionScan?: boolean): void {\n if (allowCollectionScan || this.scanProtection === 'off') return;\n\n const result = analyzeQuerySafety(filters);\n if (result.safe) return;\n\n if (this.scanProtection === 'error') {\n throw new QuerySafetyError(result.reason!);\n }\n\n // scanProtection === 'warn'\n console.warn(`[firegraph] Query safety warning: ${result.reason}`);\n }\n\n async findEdges(params: FindEdgesParams): Promise<StoredGraphRecord[]> {\n const plan = buildEdgeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.adapter.query(plan.filters, plan.options);\n }\n\n async findNodes(params: FindNodesParams): Promise<StoredGraphRecord[]> {\n const plan = buildNodeQueryPlan(params);\n if (plan.strategy === 'get') {\n const record = await this.adapter.getDoc(plan.docId);\n return record ? [record] : [];\n }\n this.checkQuerySafety(plan.filters, params.allowCollectionScan);\n return this.adapter.query(plan.filters, plan.options);\n }\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n this.adapter.deleteDoc(docId);\n }\n}\n","import { BUILTIN_FIELDS } from './internal/constants.js';\nimport type { QueryFilter } from './types.js';\n\n/**\n * Result of analyzing a query for collection scan risk.\n */\nexport interface QuerySafetyResult {\n /** Whether the query matches a known indexed pattern. */\n safe: boolean;\n /** Human-readable explanation when the query is unsafe. */\n reason?: string;\n}\n\n/**\n * Known composite index patterns that prevent full collection scans.\n * Each pattern is a set of field names that must ALL be present in the\n * query filters. Order within the set doesn't matter — what matters is\n * that the Firestore composite index covers the combination.\n *\n * These correspond to the indexes in firestore.indexes.json:\n * (aUid, axbType) — forward edge lookup\n * (axbType, bUid) — reverse edge lookup\n * (aType, axbType) — type-scoped queries + findNodes\n * (axbType, bType) — edge type + target type\n */\nconst SAFE_INDEX_PATTERNS: ReadonlyArray<ReadonlySet<string>> = [\n new Set(['aUid', 'axbType']),\n new Set(['axbType', 'bUid']),\n new Set(['aType', 'axbType']),\n new Set(['axbType', 'bType']),\n];\n\n/**\n * Analyzes a set of query filters to determine whether the query would\n * likely cause a full collection scan on Firestore Enterprise.\n *\n * A query is considered \"safe\" if the builtin fields present in the filters\n * match at least one known composite index pattern. Queries that only use\n * `data.*` fields without a safe base pattern are flagged as unsafe.\n */\nexport function analyzeQuerySafety(filters: QueryFilter[]): QuerySafetyResult {\n // Extract the set of builtin fields being filtered on (equality checks are\n // the primary index-usable operations, but we're generous here and count\n // any filter on a builtin field as potentially index-backed).\n const builtinFieldsPresent = new Set<string>();\n let hasDataFilters = false;\n\n for (const f of filters) {\n if (BUILTIN_FIELDS.has(f.field)) {\n builtinFieldsPresent.add(f.field);\n } else {\n // data.* or other non-builtin fields\n hasDataFilters = true;\n }\n }\n\n // Check if the builtin fields match any known safe index pattern.\n // A pattern is \"matched\" if all fields in the pattern are present in the query.\n for (const pattern of SAFE_INDEX_PATTERNS) {\n let matched = true;\n for (const field of pattern) {\n if (!builtinFieldsPresent.has(field)) {\n matched = false;\n break;\n }\n }\n if (matched) {\n // Even with data.* filters, the base index narrows the scan significantly.\n // The data.* filters are applied as post-filters on the index results.\n return { safe: true };\n }\n }\n\n // No safe pattern matched — build an explanation.\n const presentFields = [...builtinFieldsPresent];\n if (presentFields.length === 0 && hasDataFilters) {\n return {\n safe: false,\n reason:\n 'Query filters only use data.* fields with no builtin field constraints. ' +\n 'This requires a full collection scan. Add aType, aUid, axbType, bType, or bUid filters, ' +\n 'or set allowCollectionScan: true.',\n };\n }\n\n if (hasDataFilters) {\n return {\n safe: false,\n reason:\n `Query filters on [${presentFields.join(', ')}] do not match any indexed pattern. ` +\n 'data.* filters without an indexed base require a full collection scan. ' +\n `Safe patterns: (aUid + axbType), (axbType + bUid), (aType + axbType), (axbType + bType). ` +\n 'Set allowCollectionScan: true to override.',\n };\n }\n\n return {\n safe: false,\n reason:\n `Query filters on [${presentFields.join(', ')}] do not match any indexed pattern. ` +\n 'This may cause a full collection scan on Firestore Enterprise. ' +\n `Safe patterns: (aUid + axbType), (axbType + bUid), (aType + axbType), (axbType + bType). ` +\n 'Set allowCollectionScan: true to override.',\n };\n}\n","import { FieldValue } from '@google-cloud/firestore';\nimport { computeNodeDocId, computeEdgeDocId } from './docid.js';\nimport { buildNodeRecord, buildEdgeRecord } from './record.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { BatchAdapter } from './internal/firestore-adapter.js';\nimport type { GraphBatch, GraphRegistry } from './types.js';\n\nexport class GraphBatchImpl implements GraphBatch {\n constructor(\n private readonly adapter: BatchAdapter,\n private readonly registry?: GraphRegistry,\n private readonly scopePath: string = '',\n ) {}\n\n async putNode(aType: string, uid: string, data: Record<string, unknown>): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);\n }\n const docId = computeNodeDocId(uid);\n const record = buildNodeRecord(aType, uid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async putEdge(\n aType: string,\n aUid: string,\n axbType: string,\n bType: string,\n bUid: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n if (this.registry) {\n this.registry.validate(aType, axbType, bType, data, this.scopePath);\n }\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n const record = buildEdgeRecord(aType, aUid, axbType, bType, bUid, data);\n this.adapter.setDoc(docId, record as unknown as Record<string, unknown>);\n }\n\n async updateNode(uid: string, data: Record<string, unknown>): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.updateDoc(docId, {\n ...data,\n updatedAt: FieldValue.serverTimestamp(),\n });\n }\n\n async removeNode(uid: string): Promise<void> {\n const docId = computeNodeDocId(uid);\n this.adapter.deleteDoc(docId);\n }\n\n async removeEdge(aUid: string, axbType: string, bUid: string): Promise<void> {\n const docId = computeEdgeDocId(aUid, axbType, bUid);\n this.adapter.deleteDoc(docId);\n }\n\n async commit(): Promise<void> {\n await this.adapter.commit();\n }\n}\n","import type { Firestore } from '@google-cloud/firestore';\nimport { computeEdgeDocId, computeNodeDocId } from './docid.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type {\n StoredGraphRecord,\n FindEdgesParams,\n BulkOptions,\n BulkResult,\n BulkBatchError,\n CascadeResult,\n GraphReader,\n} from './types.js';\n\nconst MAX_BATCH_SIZE = 500;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 200;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Splits an array into chunks of at most `size` elements.\n */\nfunction chunk<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size));\n }\n return chunks;\n}\n\n/**\n * Deletes a list of document IDs in chunked Firestore batches with retries.\n */\nexport async function bulkDeleteDocIds(\n db: Firestore,\n collectionPath: string,\n docIds: string[],\n options?: BulkOptions,\n): Promise<BulkResult> {\n if (docIds.length === 0) {\n return { deleted: 0, batches: 0, errors: [] };\n }\n\n const batchSize = Math.min(options?.batchSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const onProgress = options?.onProgress;\n\n const chunks = chunk(docIds, batchSize);\n const errors: BulkBatchError[] = [];\n let deleted = 0;\n let completedBatches = 0;\n\n for (let i = 0; i < chunks.length; i++) {\n const ids = chunks[i];\n let committed = false;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const batch = db.batch();\n const collectionRef = db.collection(collectionPath);\n for (const id of ids) {\n batch.delete(collectionRef.doc(id));\n }\n await batch.commit();\n committed = true;\n deleted += ids.length;\n break;\n } catch (err) {\n if (attempt < maxRetries) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n await sleep(delay);\n } else {\n errors.push({\n batchIndex: i,\n error: err instanceof Error ? err : new Error(String(err)),\n operationCount: ids.length,\n });\n }\n }\n }\n\n if (committed) {\n completedBatches++;\n }\n\n if (onProgress) {\n onProgress({\n completedBatches,\n totalBatches: chunks.length,\n deletedSoFar: deleted,\n });\n }\n }\n\n return { deleted, batches: completedBatches, errors };\n}\n\n/**\n * Finds all edges matching `params`, then deletes them in chunked batches.\n */\nexport async function bulkRemoveEdges(\n db: Firestore,\n collectionPath: string,\n reader: GraphReader,\n params: FindEdgesParams,\n options?: BulkOptions,\n): Promise<BulkResult> {\n // Override default query limit for bulk deletion — we need all matching edges.\n // limit: 0 bypasses DEFAULT_QUERY_LIMIT; an explicit user limit is preserved.\n // allowCollectionScan: true — bulk deletion inherently implies scanning.\n const effectiveParams = params.limit !== undefined\n ? { ...params, allowCollectionScan: params.allowCollectionScan ?? true }\n : { ...params, limit: 0, allowCollectionScan: params.allowCollectionScan ?? true };\n const edges = await reader.findEdges(effectiveParams);\n const docIds = edges.map((e) => computeEdgeDocId(e.aUid, e.axbType, e.bUid));\n return bulkDeleteDocIds(db, collectionPath, docIds, options);\n}\n\n/** Result from recursive subcollection deletion. */\ninterface SubcollectionDeleteResult {\n deleted: number;\n errors: BulkBatchError[];\n}\n\n/**\n * Recursively delete all documents in all subcollections under a given document.\n * Uses `listCollections()` (Admin SDK) to discover subcollections, then for each\n * subcollection: recurse into each document's subcollections first (depth-first),\n * then bulk delete all documents in the subcollection.\n *\n * The `onProgress` callback is intentionally NOT forwarded to subcollection\n * deletes to avoid confusing callers with interleaved progress from different\n * collection depths.\n */\nasync function deleteSubcollectionsRecursive(\n db: Firestore,\n collectionPath: string,\n docId: string,\n options?: BulkOptions,\n): Promise<SubcollectionDeleteResult> {\n const docRef = db.collection(collectionPath).doc(docId);\n const subcollections = await docRef.listCollections();\n\n if (subcollections.length === 0) return { deleted: 0, errors: [] };\n\n let totalDeleted = 0;\n const allErrors: BulkBatchError[] = [];\n\n // Strip onProgress for subcollection deletes — callers should only see\n // top-level progress, not interleaved reports from nested depths.\n const subOptions: BulkOptions | undefined = options\n ? { batchSize: options.batchSize, maxRetries: options.maxRetries }\n : undefined;\n\n for (const subCollRef of subcollections) {\n const subCollPath = subCollRef.path;\n // List all documents in this subcollection\n const snapshot = await subCollRef.select().get();\n const subDocIds = snapshot.docs.map((d) => d.id);\n\n // Depth-first: recurse into each document's subcollections\n for (const subDocId of subDocIds) {\n const subResult = await deleteSubcollectionsRecursive(db, subCollPath, subDocId, subOptions);\n totalDeleted += subResult.deleted;\n allErrors.push(...subResult.errors);\n }\n\n // Now delete all documents in this subcollection\n if (subDocIds.length > 0) {\n const result = await bulkDeleteDocIds(db, subCollPath, subDocIds, subOptions);\n totalDeleted += result.deleted;\n allErrors.push(...result.errors);\n }\n }\n\n return { deleted: totalDeleted, errors: allErrors };\n}\n\n/**\n * Deletes a node and all of its outgoing and incoming edges.\n *\n * Edges are deleted first in chunked batches, then the node document\n * is deleted in the final batch. This is NOT atomic across batches —\n * if a batch fails after retries, remaining batches still execute.\n *\n * By default, subcollections (subgraphs) under the node's document are\n * recursively deleted. Set `options.deleteSubcollections` to `false` to skip.\n */\nexport async function removeNodeCascade(\n db: Firestore,\n collectionPath: string,\n reader: GraphReader,\n uid: string,\n options?: BulkOptions,\n): Promise<CascadeResult> {\n // Find all edges touching this node (outgoing + incoming).\n // Filter out the node's own self-loop record (axbType === 'is').\n // These queries intentionally scan broadly — allowCollectionScan bypasses safety checks.\n // limit: 0 bypasses the DEFAULT_QUERY_LIMIT to ensure we find all edges.\n const [outgoingRaw, incomingRaw] = await Promise.all([\n reader.findEdges({ aUid: uid, allowCollectionScan: true, limit: 0 }),\n reader.findEdges({ bUid: uid, allowCollectionScan: true, limit: 0 }),\n ]);\n const outgoing = outgoingRaw.filter((e) => e.axbType !== NODE_RELATION);\n const incoming = incomingRaw.filter((e) => e.axbType !== NODE_RELATION);\n\n // Deduplicate: a self-referencing edge could appear in both lists.\n const edgeDocIdSet = new Set<string>();\n const allEdges: StoredGraphRecord[] = [];\n for (const edge of [...outgoing, ...incoming]) {\n const docId = computeEdgeDocId(edge.aUid, edge.axbType, edge.bUid);\n if (!edgeDocIdSet.has(docId)) {\n edgeDocIdSet.add(docId);\n allEdges.push(edge);\n }\n }\n\n // Delete subcollections (subgraphs) under this node's document (depth-first).\n const shouldDeleteSubcollections = options?.deleteSubcollections !== false;\n const nodeDocId = computeNodeDocId(uid);\n let subcollectionResult: SubcollectionDeleteResult = { deleted: 0, errors: [] };\n\n if (shouldDeleteSubcollections) {\n subcollectionResult = await deleteSubcollectionsRecursive(\n db, collectionPath, nodeDocId, options,\n );\n }\n\n // Build doc IDs: edges first, then the node last.\n const edgeDocIds = allEdges.map((e) => computeEdgeDocId(e.aUid, e.axbType, e.bUid));\n const allDocIds = [...edgeDocIds, nodeDocId];\n\n // Wrap the progress callback to track overall progress.\n const batchSize = Math.min(options?.batchSize ?? MAX_BATCH_SIZE, MAX_BATCH_SIZE);\n const result = await bulkDeleteDocIds(db, collectionPath, allDocIds, {\n ...options,\n batchSize,\n });\n\n // Determine if the node doc was in a failed batch.\n // The node is always in the last doc ID. If the last batch errored, node wasn't deleted.\n const totalChunks = Math.ceil(allDocIds.length / batchSize);\n const nodeChunkIndex = totalChunks - 1;\n const nodeDeleted = !result.errors.some((e) => e.batchIndex === nodeChunkIndex);\n\n // edgesDeleted counts only top-level edges (not subcollection docs).\n // deleted includes everything: top-level edges + node + subcollection docs.\n const topLevelEdgesDeleted = nodeDeleted ? result.deleted - 1 : result.deleted;\n\n return {\n deleted: result.deleted + subcollectionResult.deleted,\n batches: result.batches,\n errors: [...result.errors, ...subcollectionResult.errors],\n edgesDeleted: topLevelEdgesDeleted,\n nodeDeleted,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { createRegistry } from './registry.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type {\n GraphReader,\n GraphRegistry,\n RegistryEntry,\n NodeTypeData,\n EdgeTypeData,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// Meta-type constants\n// ---------------------------------------------------------------------------\n\n/** The aType used for node type definition meta-nodes. */\nexport const META_NODE_TYPE = 'nodeType';\n\n/** The aType used for edge type definition meta-nodes. */\nexport const META_EDGE_TYPE = 'edgeType';\n\n// ---------------------------------------------------------------------------\n// JSON Schemas for meta-type data payloads\n// ---------------------------------------------------------------------------\n\n/** JSON Schema for the `data` payload of a `nodeType` meta-node. */\nexport const NODE_TYPE_SCHEMA: object = {\n type: 'object',\n required: ['name', 'jsonSchema'],\n properties: {\n name: { type: 'string', minLength: 1 },\n jsonSchema: { type: 'object' },\n description: { type: 'string' },\n titleField: { type: 'string' },\n subtitleField: { type: 'string' },\n viewTemplate: { type: 'string' },\n viewCss: { type: 'string' },\n allowedIn: { type: 'array', items: { type: 'string', minLength: 1 } },\n },\n additionalProperties: false,\n};\n\n/** JSON Schema for the `data` payload of an `edgeType` meta-node. */\nexport const EDGE_TYPE_SCHEMA: object = {\n type: 'object',\n required: ['name', 'from', 'to'],\n properties: {\n name: { type: 'string', minLength: 1 },\n from: {\n oneOf: [\n { type: 'string', minLength: 1 },\n { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1 },\n ],\n },\n to: {\n oneOf: [\n { type: 'string', minLength: 1 },\n { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1 },\n ],\n },\n jsonSchema: { type: 'object' },\n inverseLabel: { type: 'string' },\n description: { type: 'string' },\n titleField: { type: 'string' },\n subtitleField: { type: 'string' },\n viewTemplate: { type: 'string' },\n viewCss: { type: 'string' },\n allowedIn: { type: 'array', items: { type: 'string', minLength: 1 } },\n targetGraph: { type: 'string', minLength: 1, pattern: '^[^/]+$' },\n },\n additionalProperties: false,\n};\n\n// ---------------------------------------------------------------------------\n// Bootstrap registry\n// ---------------------------------------------------------------------------\n\n/** Registry entries for the two meta-types (always present). */\nexport const BOOTSTRAP_ENTRIES: readonly RegistryEntry[] = [\n {\n aType: META_NODE_TYPE,\n axbType: NODE_RELATION,\n bType: META_NODE_TYPE,\n jsonSchema: NODE_TYPE_SCHEMA,\n description: 'Meta-type: defines a node type',\n },\n {\n aType: META_EDGE_TYPE,\n axbType: NODE_RELATION,\n bType: META_EDGE_TYPE,\n jsonSchema: EDGE_TYPE_SCHEMA,\n description: 'Meta-type: defines an edge type',\n },\n];\n\n/**\n * Build the bootstrap registry that validates meta-type writes.\n * This is always available, even before any dynamic types are loaded.\n */\nexport function createBootstrapRegistry(): GraphRegistry {\n return createRegistry([...BOOTSTRAP_ENTRIES]);\n}\n\n// ---------------------------------------------------------------------------\n// Deterministic UID generation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a deterministic UID for a meta-type definition.\n * This ensures that defining the same type name always targets the same\n * Firestore document, enabling upsert semantics.\n *\n * Format: 21-char base64url substring of SHA-256(`metaType:name`).\n */\nexport function generateDeterministicUid(metaType: string, name: string): string {\n const hash = createHash('sha256')\n .update(`${metaType}:${name}`)\n .digest('base64url');\n return hash.slice(0, 21);\n}\n\n// ---------------------------------------------------------------------------\n// createRegistryFromGraph\n// ---------------------------------------------------------------------------\n\n/**\n * Read meta-type nodes from the graph and compile them into a GraphRegistry.\n *\n * The returned registry includes both the dynamic entries AND the bootstrap\n * meta-type entries, so meta-type writes remain validateable after a reload.\n *\n * @param reader - A GraphReader pointed at the collection containing meta-nodes.\n */\nexport async function createRegistryFromGraph(\n reader: GraphReader,\n): Promise<GraphRegistry> {\n const [nodeTypes, edgeTypes] = await Promise.all([\n reader.findNodes({ aType: META_NODE_TYPE }),\n reader.findNodes({ aType: META_EDGE_TYPE }),\n ]);\n\n const entries: RegistryEntry[] = [...BOOTSTRAP_ENTRIES];\n\n // Convert nodeType records → self-loop RegistryEntries\n for (const record of nodeTypes) {\n const data = record.data as unknown as NodeTypeData;\n entries.push({\n aType: data.name,\n axbType: NODE_RELATION,\n bType: data.name,\n jsonSchema: data.jsonSchema,\n description: data.description,\n titleField: data.titleField,\n subtitleField: data.subtitleField,\n allowedIn: data.allowedIn,\n });\n }\n\n // Convert edgeType records → RegistryEntries (expand from/to arrays)\n for (const record of edgeTypes) {\n const data = record.data as unknown as EdgeTypeData;\n const fromTypes = Array.isArray(data.from) ? data.from : [data.from];\n const toTypes = Array.isArray(data.to) ? data.to : [data.to];\n\n for (const aType of fromTypes) {\n for (const bType of toTypes) {\n entries.push({\n aType,\n axbType: data.name,\n bType,\n jsonSchema: data.jsonSchema,\n description: data.description,\n inverseLabel: data.inverseLabel,\n titleField: data.titleField,\n subtitleField: data.subtitleField,\n allowedIn: data.allowedIn,\n targetGraph: data.targetGraph,\n });\n }\n }\n }\n\n return createRegistry(entries);\n}\n","/**\n * JSON Schema validation and introspection utilities.\n *\n * Standard JSON Schema validation and introspection\n * processing. Uses ajv for validation and a recursive walker for converting\n * JSON Schema properties into FieldMeta objects for editor form generation.\n */\n\nimport Ajv from 'ajv';\nimport { ValidationError } from './errors.js';\n\n// ---------------------------------------------------------------------------\n// FieldMeta types (previously in editor/server/schema-introspect.ts)\n// ---------------------------------------------------------------------------\n\nexport interface FieldMeta {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'unknown';\n required: boolean;\n description?: string;\n enumValues?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n min?: number;\n max?: number;\n isInt?: boolean;\n itemMeta?: FieldMeta;\n fields?: FieldMeta[];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\n\n/**\n * Compile a JSON Schema into a validation function.\n * The returned function throws `ValidationError` if data is invalid.\n */\nexport function compileSchema(\n schema: object,\n label?: string,\n): (data: unknown) => void {\n const validate = ajv.compile(schema);\n return (data: unknown) => {\n if (!validate(data)) {\n const errors = validate.errors ?? [];\n const messages = errors\n .map((err) => `${err.instancePath || '/'}${err.message ? ': ' + err.message : ''}`)\n .join('; ');\n throw new ValidationError(\n `Data validation failed${label ? ' for ' + label : ''}: ${messages}`,\n errors,\n );\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema → FieldMeta introspection\n// ---------------------------------------------------------------------------\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Convert a JSON Schema (expected to be `type: \"object\"`) into `FieldMeta[]`\n * suitable for the editor's SchemaForm component.\n */\nexport function jsonSchemaToFieldMeta(schema: any): FieldMeta[] {\n if (!schema || schema.type !== 'object' || !schema.properties) return [];\n\n const requiredSet = new Set<string>(\n Array.isArray(schema.required) ? schema.required : [],\n );\n\n return Object.entries(schema.properties).map(([name, prop]) =>\n propertyToFieldMeta(name, prop as any, requiredSet.has(name)),\n );\n}\n\n/**\n * Convert a single JSON Schema property into a `FieldMeta`.\n */\nfunction propertyToFieldMeta(\n name: string,\n prop: any,\n required: boolean,\n): FieldMeta {\n if (!prop) return { name, type: 'unknown', required };\n\n // Handle enum (can appear with or without type)\n if (Array.isArray(prop.enum)) {\n return {\n name,\n type: 'enum',\n required,\n enumValues: prop.enum as string[],\n description: prop.description,\n };\n }\n\n // Handle oneOf/anyOf for nullable patterns like { oneOf: [{type:'string'}, {type:'null'}] }\n if (Array.isArray(prop.oneOf) || Array.isArray(prop.anyOf)) {\n const variants = (prop.oneOf ?? prop.anyOf) as any[];\n const nonNull = variants.filter((v: any) => v.type !== 'null');\n if (nonNull.length === 1) {\n // Nullable wrapper — unwrap and mark as optional\n return propertyToFieldMeta(name, nonNull[0], false);\n }\n return { name, type: 'unknown', required, description: prop.description };\n }\n\n const type = prop.type;\n\n if (type === 'string') {\n return {\n name,\n type: 'string',\n required,\n minLength: prop.minLength,\n maxLength: prop.maxLength,\n pattern: prop.pattern,\n description: prop.description,\n };\n }\n\n if (type === 'number' || type === 'integer') {\n return {\n name,\n type: 'number',\n required,\n min: prop.minimum,\n max: prop.maximum,\n isInt: type === 'integer' ? true : undefined,\n description: prop.description,\n };\n }\n\n if (type === 'boolean') {\n return { name, type: 'boolean', required, description: prop.description };\n }\n\n if (type === 'array') {\n const itemMeta = prop.items\n ? propertyToFieldMeta('item', prop.items, true)\n : undefined;\n return {\n name,\n type: 'array',\n required,\n itemMeta,\n description: prop.description,\n };\n }\n\n if (type === 'object') {\n return {\n name,\n type: 'object',\n required,\n fields: jsonSchemaToFieldMeta(prop),\n description: prop.description,\n };\n }\n\n return { name, type: 'unknown', required, description: prop.description };\n}\n\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","/**\n * Scope path matching for subgraph-level registry constraints.\n *\n * Scope paths are slash-separated names derived from the chain of\n * `subgraph()` calls (e.g., `'agents'`, `'agents/memories'`).\n * The root graph has an empty scope path (`''`).\n *\n * Patterns:\n * - `'root'` — matches only the root graph (empty scope path)\n * - `'agents'` — matches exactly `'agents'`\n * - `'agents/memories'` — matches exactly `'agents/memories'`\n * - `'*​/agents'` — `*` matches one segment: `'foo/agents'` but not `'a/b/agents'`\n * - `'**​/memories'` — `**` matches zero or more segments\n * - `'**'` — matches everything including root\n */\n\n/**\n * Test whether a scope path matches a single pattern.\n *\n * @param scopePath - The current scope path (empty string for root)\n * @param pattern - The pattern to match against\n */\nexport function matchScope(scopePath: string, pattern: string): boolean {\n // Special case: 'root' matches only the root graph\n if (pattern === 'root') return scopePath === '';\n\n // Special case: '**' matches everything\n if (pattern === '**') return true;\n\n const pathSegments = scopePath === '' ? [] : scopePath.split('/');\n const patternSegments = pattern.split('/');\n\n return matchSegments(pathSegments, 0, patternSegments, 0);\n}\n\n/**\n * Test whether a scope path matches any pattern in a list.\n * Returns `true` if the list is empty or undefined (allowed everywhere).\n *\n * @param scopePath - The current scope path (empty string for root)\n * @param patterns - Array of patterns to match against\n */\nexport function matchScopeAny(scopePath: string, patterns: string[]): boolean {\n if (!patterns || patterns.length === 0) return true;\n return patterns.some((p) => matchScope(scopePath, p));\n}\n\n/**\n * Recursive segment matcher with support for `*` (one segment) and\n * `**` (zero or more segments).\n */\nfunction matchSegments(\n path: string[],\n pi: number,\n pattern: string[],\n qi: number,\n): boolean {\n // Both exhausted — match\n if (pi === path.length && qi === pattern.length) return true;\n\n // Pattern exhausted but path remains — no match\n if (qi === pattern.length) return false;\n\n const seg = pattern[qi];\n\n if (seg === '**') {\n // '**' at the end of pattern — matches everything remaining\n if (qi === pattern.length - 1) return true;\n\n // Try consuming 0, 1, 2, ... path segments\n for (let skip = 0; skip <= path.length - pi; skip++) {\n if (matchSegments(path, pi + skip, pattern, qi + 1)) return true;\n }\n return false;\n }\n\n // Path exhausted but pattern has non-** segments remaining — no match\n if (pi === path.length) return false;\n\n if (seg === '*') {\n // '*' matches exactly one segment\n return matchSegments(path, pi + 1, pattern, qi + 1);\n }\n\n // Literal match\n if (path[pi] === seg) {\n return matchSegments(path, pi + 1, pattern, qi + 1);\n }\n\n return false;\n}\n","import { RegistryViolationError, RegistryScopeError, ValidationError } from './errors.js';\nimport { compileSchema } from './json-schema.js';\nimport { matchScopeAny } from './scope.js';\nimport { NODE_RELATION } from './internal/constants.js';\nimport type { GraphRegistry, RegistryEntry, DiscoveryResult } from './types.js';\n\nfunction tripleKey(aType: string, axbType: string, bType: string): string {\n return `${aType}:${axbType}:${bType}`;\n}\n\nfunction tripleKeyFor(e: RegistryEntry): string {\n return tripleKey(e.aType, e.axbType, e.bType);\n}\n\n/**\n * Build a registry from either explicit entries or a DiscoveryResult.\n *\n * @example\n * ```ts\n * // From explicit entries (programmatic)\n * const registry = createRegistry([\n * { aType: 'user', axbType: 'is', bType: 'user', jsonSchema: userSchema },\n * { aType: 'user', axbType: 'follows', bType: 'user', jsonSchema: followsSchema },\n * ]);\n *\n * // From discovery result (folder convention)\n * const discovered = await discoverEntities('./entities');\n * const registry = createRegistry(discovered);\n * ```\n */\nexport function createRegistry(\n input: RegistryEntry[] | DiscoveryResult,\n): GraphRegistry {\n const map = new Map<string, { entry: RegistryEntry; validate?: (data: unknown) => void }>();\n\n let entries: RegistryEntry[];\n\n if (Array.isArray(input)) {\n entries = input;\n } else {\n entries = discoveryToEntries(input);\n }\n\n const entryList: ReadonlyArray<RegistryEntry> = Object.freeze([...entries]);\n\n for (const entry of entries) {\n if (entry.targetGraph && entry.targetGraph.includes('/')) {\n throw new ValidationError(\n `Entry (${entry.aType}) -[${entry.axbType}]-> (${entry.bType}) has invalid targetGraph \"${entry.targetGraph}\" — must be a single segment (no \"/\")`,\n );\n }\n const key = tripleKey(entry.aType, entry.axbType, entry.bType);\n const validator = entry.jsonSchema\n ? compileSchema(entry.jsonSchema, `(${entry.aType}) -[${entry.axbType}]-> (${entry.bType})`)\n : undefined;\n map.set(key, { entry, validate: validator });\n }\n\n // Build axbType index for lookupByAxbType\n const axbIndex = new Map<string, ReadonlyArray<RegistryEntry>>();\n const axbBuild = new Map<string, RegistryEntry[]>();\n for (const entry of entries) {\n const existing = axbBuild.get(entry.axbType);\n if (existing) {\n existing.push(entry);\n } else {\n axbBuild.set(entry.axbType, [entry]);\n }\n }\n for (const [key, arr] of axbBuild) {\n axbIndex.set(key, Object.freeze(arr));\n }\n\n return {\n lookup(aType: string, axbType: string, bType: string): RegistryEntry | undefined {\n return map.get(tripleKey(aType, axbType, bType))?.entry;\n },\n\n lookupByAxbType(axbType: string): ReadonlyArray<RegistryEntry> {\n return axbIndex.get(axbType) ?? [];\n },\n\n validate(aType: string, axbType: string, bType: string, data: unknown, scopePath?: string): void {\n const rec = map.get(tripleKey(aType, axbType, bType));\n\n if (!rec) {\n throw new RegistryViolationError(aType, axbType, bType);\n }\n\n // Scope validation: check allowedIn patterns when a scope context is provided\n if (scopePath !== undefined && rec.entry.allowedIn && rec.entry.allowedIn.length > 0) {\n if (!matchScopeAny(scopePath, rec.entry.allowedIn)) {\n throw new RegistryScopeError(aType, axbType, bType, scopePath, rec.entry.allowedIn);\n }\n }\n\n if (rec.validate) {\n try {\n rec.validate(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) throw err;\n throw new ValidationError(\n `Data validation failed for (${aType}) -[${axbType}]-> (${bType})`,\n err,\n );\n }\n }\n },\n\n entries(): ReadonlyArray<RegistryEntry> {\n return entryList;\n },\n };\n}\n\n/**\n * Create a merged registry where `base` entries take priority and `extension`\n * entries fill in gaps. Lookups and validation check `base` first; only if the\n * triple is not found there does the merged registry fall through to\n * `extension`.\n *\n * The `entries()` method returns a deduplicated list (base wins on collision).\n * The `lookupByAxbType()` method merges results from both registries,\n * deduplicating by triple key with base entries winning.\n */\nexport function createMergedRegistry(\n base: GraphRegistry,\n extension: GraphRegistry,\n): GraphRegistry {\n // Build a set of triple keys from the base registry for fast collision checks.\n const baseKeys = new Set(base.entries().map(tripleKeyFor));\n\n return {\n lookup(aType: string, axbType: string, bType: string): RegistryEntry | undefined {\n return base.lookup(aType, axbType, bType) ?? extension.lookup(aType, axbType, bType);\n },\n\n lookupByAxbType(axbType: string): ReadonlyArray<RegistryEntry> {\n const baseResults = base.lookupByAxbType(axbType);\n const extResults = extension.lookupByAxbType(axbType);\n if (extResults.length === 0) return baseResults;\n if (baseResults.length === 0) return extResults;\n\n // Merge, base wins on triple-key collision\n const seen = new Set(baseResults.map(tripleKeyFor));\n const merged = [...baseResults];\n for (const entry of extResults) {\n if (!seen.has(tripleKeyFor(entry))) {\n merged.push(entry);\n }\n }\n return Object.freeze(merged);\n },\n\n validate(aType: string, axbType: string, bType: string, data: unknown, scopePath?: string): void {\n if (baseKeys.has(tripleKey(aType, axbType, bType))) {\n return base.validate(aType, axbType, bType, data, scopePath);\n }\n // Falls through to extension (which throws RegistryViolationError if not found)\n return extension.validate(aType, axbType, bType, data, scopePath);\n },\n\n entries(): ReadonlyArray<RegistryEntry> {\n const extEntries = extension.entries();\n if (extEntries.length === 0) return base.entries();\n\n const merged = [...base.entries()];\n for (const entry of extEntries) {\n if (!baseKeys.has(tripleKeyFor(entry))) {\n merged.push(entry);\n }\n }\n return Object.freeze(merged);\n },\n };\n}\n\n/**\n * Convert a DiscoveryResult into flat RegistryEntry[].\n * Nodes become self-loop triples `(name, 'is', name)`.\n * Edges expand `from`/`to` arrays into one triple per combination.\n */\nfunction discoveryToEntries(discovery: DiscoveryResult): RegistryEntry[] {\n const entries: RegistryEntry[] = [];\n\n // Nodes → self-loop triples\n for (const [name, entity] of discovery.nodes) {\n entries.push({\n aType: name,\n axbType: NODE_RELATION,\n bType: name,\n jsonSchema: entity.schema,\n description: entity.description,\n titleField: entity.titleField,\n subtitleField: entity.subtitleField,\n allowedIn: entity.allowedIn,\n });\n }\n\n // Edges → expand from/to into one triple per combination\n for (const [axbType, entity] of discovery.edges) {\n const topology = entity.topology;\n if (!topology) continue;\n\n const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];\n const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];\n\n const resolvedTargetGraph = entity.targetGraph ?? topology.targetGraph;\n if (resolvedTargetGraph && resolvedTargetGraph.includes('/')) {\n throw new ValidationError(\n `Edge \"${axbType}\" has invalid targetGraph \"${resolvedTargetGraph}\" — must be a single segment (no \"/\")`,\n );\n }\n\n for (const aType of fromTypes) {\n for (const bType of toTypes) {\n entries.push({\n aType,\n axbType,\n bType,\n jsonSchema: entity.schema,\n description: entity.description,\n inverseLabel: topology.inverseLabel,\n titleField: entity.titleField,\n subtitleField: entity.subtitleField,\n allowedIn: entity.allowedIn,\n targetGraph: resolvedTargetGraph,\n });\n }\n }\n }\n\n return entries;\n}\n","import { nanoid } from 'nanoid';\n\nexport function generateId(): string {\n return nanoid();\n}\n","import { TraversalError } from './errors.js';\nimport type {\n GraphReader,\n GraphClient,\n GraphRegistry,\n StoredGraphRecord,\n FindEdgesParams,\n HopDefinition,\n TraversalOptions,\n HopResult,\n TraversalResult,\n TraversalBuilder,\n} from './types.js';\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_MAX_READS = 100;\nconst DEFAULT_CONCURRENCY = 5;\n\n/** One-time warning flag: emitted when cross-graph hop is silently skipped. */\nlet _crossGraphWarned = false;\n\n/** Type guard to check if a reader is a GraphClient (has subgraph method). */\nfunction isGraphClient(reader: GraphReader): reader is GraphClient {\n return 'subgraph' in reader && typeof (reader as GraphClient).subgraph === 'function';\n}\n\nclass Semaphore {\n private queue: Array<() => void> = [];\n private active = 0;\n\n constructor(private readonly slots: number) {}\n\n async acquire(): Promise<void> {\n if (this.active < this.slots) {\n this.active++;\n return;\n }\n return new Promise<void>((resolve) => {\n this.queue.push(resolve);\n });\n }\n\n release(): void {\n this.active--;\n const next = this.queue.shift();\n if (next) {\n this.active++;\n next();\n }\n }\n}\n\nclass TraversalBuilderImpl implements TraversalBuilder {\n private readonly hops: HopDefinition[] = [];\n\n constructor(\n private readonly reader: GraphReader,\n private readonly startUid: string,\n private readonly registry?: GraphRegistry,\n ) {}\n\n follow(axbType: string, options?: Omit<HopDefinition, 'axbType'>): TraversalBuilder {\n this.hops.push({ axbType, ...options });\n return this;\n }\n\n async run(options?: TraversalOptions): Promise<TraversalResult> {\n if (this.hops.length === 0) {\n throw new TraversalError('Traversal requires at least one follow() hop');\n }\n\n const maxReads = options?.maxReads ?? DEFAULT_MAX_READS;\n const concurrency = options?.concurrency ?? DEFAULT_CONCURRENCY;\n const returnIntermediates = options?.returnIntermediates ?? false;\n const semaphore = new Semaphore(concurrency);\n\n let totalReads = 0;\n let truncated = false;\n // Track (uid, reader) pairs to support context carry-forward across hops.\n // When a hop crosses into a subgraph, the resulting UIDs carry the subgraph\n // reader so subsequent hops without targetGraph stay in that subgraph.\n let sources: Array<{ uid: string; reader: GraphReader }> = [\n { uid: this.startUid, reader: this.reader },\n ];\n const hopResults: HopResult[] = [];\n\n for (let depth = 0; depth < this.hops.length; depth++) {\n const hop = this.hops[depth];\n\n if (sources.length === 0) {\n hopResults.push({\n axbType: hop.axbType,\n depth,\n edges: [],\n sourceCount: 0,\n truncated: false,\n });\n continue;\n }\n\n const hopEdges: Array<{ edge: StoredGraphRecord; reader: GraphReader }> = [];\n const sourceCount = sources.length;\n let hopTruncated = false;\n\n // Resolve targetGraph for this hop:\n // 1. Explicit on the hop definition takes precedence\n // 2. Otherwise check the registry for the axbType\n const resolvedTargetGraph = this.resolveTargetGraph(hop);\n const direction = hop.direction ?? 'forward';\n const isCrossGraph = direction === 'forward' && !!resolvedTargetGraph;\n\n const tasks = sources.map(({ uid, reader: sourceReader }) => async () => {\n if (totalReads >= maxReads) {\n hopTruncated = true;\n return;\n }\n\n await semaphore.acquire();\n try {\n if (totalReads >= maxReads) {\n hopTruncated = true;\n return;\n }\n\n totalReads++;\n\n const params: FindEdgesParams = { axbType: hop.axbType };\n\n if (direction === 'forward') {\n params.aUid = uid;\n if (hop.bType) params.bType = hop.bType;\n } else {\n params.bUid = uid;\n if (hop.aType) params.aType = hop.aType;\n }\n\n if (direction === 'forward' && hop.aType) {\n params.aType = hop.aType;\n }\n if (direction === 'reverse' && hop.bType) {\n params.bType = hop.bType;\n }\n\n if (hop.orderBy) params.orderBy = hop.orderBy;\n\n const limit = hop.limit ?? DEFAULT_LIMIT;\n if (hop.filter) {\n params.limit = 0;\n } else {\n params.limit = limit;\n }\n\n // Choose the reader for this hop:\n // - Cross-graph hop: create a subgraph reader from the ROOT client\n // (targetGraph is always relative to root)\n // - No cross-graph: use the carried-forward reader from previous hop\n // (context tracking — stay in whatever subgraph we're already in)\n let hopReader: GraphReader;\n let nextReader: GraphReader;\n if (isCrossGraph) {\n if (isGraphClient(this.reader)) {\n hopReader = this.reader.subgraph(uid, resolvedTargetGraph!);\n nextReader = hopReader;\n } else {\n hopReader = sourceReader;\n nextReader = sourceReader;\n if (!_crossGraphWarned) {\n _crossGraphWarned = true;\n console.warn(\n `[firegraph] Traversal hop \"${hop.axbType}\" has targetGraph \"${resolvedTargetGraph}\" ` +\n 'but the reader does not support subgraph(). Cross-graph hop will query the current ' +\n 'collection instead. Pass a GraphClient to createTraversal() to enable cross-graph traversal.',\n );\n }\n }\n } else {\n // No targetGraph — carry forward context from previous hop\n hopReader = sourceReader;\n nextReader = sourceReader;\n }\n\n let edges = await hopReader.findEdges(params);\n\n if (hop.filter) {\n edges = edges.filter(hop.filter);\n edges = edges.slice(0, limit);\n }\n\n for (const edge of edges) {\n hopEdges.push({ edge, reader: nextReader });\n }\n } finally {\n semaphore.release();\n }\n });\n\n await Promise.all(tasks.map((task) => task()));\n\n const edges = hopEdges.map((h) => h.edge);\n\n hopResults.push({\n axbType: hop.axbType,\n depth,\n edges: returnIntermediates ? [...edges] : edges,\n sourceCount,\n truncated: hopTruncated,\n });\n\n if (hopTruncated) {\n truncated = true;\n }\n\n // Build next sources with deduplication by UID.\n // When the same UID appears from multiple source readers, the first one wins.\n const seen = new Map<string, GraphReader>();\n for (const { edge, reader: edgeReader } of hopEdges) {\n const nextUid = direction === 'forward' ? edge.bUid : edge.aUid;\n if (!seen.has(nextUid)) {\n seen.set(nextUid, edgeReader);\n }\n }\n sources = [...seen.entries()].map(([uid, reader]) => ({ uid, reader }));\n }\n\n const lastHop = hopResults[hopResults.length - 1];\n\n return {\n nodes: lastHop.edges,\n hops: hopResults,\n totalReads,\n truncated,\n };\n }\n\n /**\n * Resolve the targetGraph for a hop. Priority:\n * 1. Explicit `hop.targetGraph` (user override)\n * 2. Registry `targetGraph` for the axbType (if registry available)\n * 3. undefined (no cross-graph)\n */\n private resolveTargetGraph(hop: HopDefinition): string | undefined {\n if (hop.targetGraph) return hop.targetGraph;\n\n if (this.registry) {\n const entries = this.registry.lookupByAxbType(hop.axbType);\n // All entries for the same axbType should share targetGraph; use the first non-undefined\n for (const entry of entries) {\n if (entry.targetGraph) return entry.targetGraph;\n }\n }\n\n return undefined;\n }\n}\n\n/** @internal Reset the one-time cross-graph warning flag (for testing). */\nexport function _resetCrossGraphWarning(): void {\n _crossGraphWarned = false;\n}\n\n/**\n * Create a traversal builder for multi-hop graph traversal.\n *\n * Accepts either a `GraphReader` (backwards compatible) or a `GraphClient`.\n * When a `GraphClient` is provided, cross-graph traversal via `targetGraph`\n * is supported — the traversal can follow edges into subgraphs.\n *\n * @param reader - A `GraphClient` or `GraphReader` to execute queries against\n * @param startUid - UID of the starting node\n * @param registry - Optional registry for automatic `targetGraph` resolution\n */\nexport function createTraversal(\n reader: GraphClient | GraphReader,\n startUid: string,\n registry?: GraphRegistry,\n): TraversalBuilder {\n return new TraversalBuilderImpl(reader, startUid, registry);\n}\n","/**\n * Model Views — framework-agnostic view definitions for graph entities.\n *\n * Projects define Web Components that render entity data in purpose-driven\n * ways. Each view class declares a static `viewName`, and receives the\n * entity's `data` payload via a `data` property setter.\n *\n * @example\n * ```ts\n * import { defineViews } from 'firegraph';\n *\n * class UserCard extends HTMLElement {\n * static viewName = 'card';\n * static description = 'Compact user card';\n * private _data: Record<string, unknown> = {};\n * set data(v: Record<string, unknown>) { this._data = v; this.render(); }\n * connectedCallback() { this.render(); }\n * private render() {\n * this.innerHTML = `<strong>${this._data.displayName ?? ''}</strong>`;\n * }\n * }\n *\n * export default defineViews({\n * nodes: { user: { views: [UserCard] } },\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A Web Component class used as a view. The class must have a static\n * `viewName` and must be constructable. It will be registered as a custom\n * element via `customElements.define()` in browser environments.\n *\n * Note: this interface avoids referencing `HTMLElement` directly so the\n * library can compile without DOM lib types. Consumer code (which has DOM)\n * will satisfy this constraint naturally.\n */\nexport interface ViewComponentClass {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (...args: any[]): { data: Record<string, unknown> };\n /** Short identifier for this view (e.g. 'card', 'profile'). */\n viewName: string;\n /** Optional human-readable description. */\n description?: string;\n}\n\n/** Configuration for all views of a single entity type. */\nexport interface EntityViewConfig {\n /** View component classes to register. */\n views: ViewComponentClass[];\n /**\n * Optional sample data for the gallery. A single object matching\n * the entity's JSON Schema — shared across all views.\n */\n sampleData?: Record<string, unknown>;\n}\n\n/** Input shape accepted by `defineViews()`. */\nexport interface ViewRegistryInput {\n /** Node views keyed by aType (e.g. 'user', 'tour'). */\n nodes?: Record<string, EntityViewConfig>;\n /** Edge views keyed by axbType (e.g. 'hasDeparture'). */\n edges?: Record<string, EntityViewConfig>;\n}\n\n/** Serialisable metadata for a single view. */\nexport interface ViewMeta {\n /** Custom element tag name (e.g. 'fg-user-card'). */\n tagName: string;\n /** Short identifier matching the component's static viewName. */\n viewName: string;\n /** Optional human-readable description. */\n description?: string;\n}\n\n/** Serialisable metadata for all views of a single entity type. */\nexport interface EntityViewMeta {\n views: ViewMeta[];\n sampleData?: Record<string, unknown>;\n}\n\n/** The resolved view registry returned by `defineViews()`. */\nexport interface ViewRegistry {\n nodes: Record<string, EntityViewMeta>;\n edges: Record<string, EntityViewMeta>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Sanitise a string for use as part of a custom element tag name. */\nfunction sanitizeTagPart(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/** Minimal interface for CustomElementRegistry (avoids depending on DOM lib). */\ninterface CustomElementRegistryLike {\n get(name: string): unknown;\n define(name: string, constructor: unknown): void;\n}\n\n/**\n * Try to access the browser's `customElements` registry.\n * Returns `null` in Node.js or environments without Web Components support.\n */\nfunction getCustomElements(): CustomElementRegistryLike | null {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = globalThis as any;\n if (g.customElements && typeof g.customElements.define === 'function') {\n return g.customElements as CustomElementRegistryLike;\n }\n return null;\n}\n\n/**\n * Wrap a view class so that errors in connectedCallback, disconnectedCallback,\n * and the data setter are caught and logged rather than crashing the page.\n * Shows an inline error message when the view fails to render.\n */\nfunction resilientView(ViewClass: ViewComponentClass, tagName: string): ViewComponentClass {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = globalThis as any;\n if (!g.HTMLElement) return ViewClass; // Node.js — no wrapping needed\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const Base = g.HTMLElement as any;\n\n const Wrapped = class extends (ViewClass as unknown as typeof Base) {\n connectedCallback() {\n try {\n super.connectedCallback?.();\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> connectedCallback error:`, err);\n this._showError(err);\n }\n }\n\n disconnectedCallback() {\n try {\n super.disconnectedCallback?.();\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> disconnectedCallback error:`, err);\n }\n }\n\n set data(v: Record<string, unknown>) {\n try {\n super.data = v;\n } catch (err) {\n console.warn(`[firegraph] <${tagName}> data setter error:`, err);\n this._showError(err);\n }\n }\n\n get data(): Record<string, unknown> {\n try {\n return super.data;\n } catch {\n return {};\n }\n }\n\n _showError(err: unknown) {\n try {\n this.innerHTML = `<div style=\"padding:6px;color:#f87171;font-size:11px;font-family:monospace;\">` +\n `View error in &lt;${tagName}&gt;: ${err instanceof Error ? err.message : String(err)}</div>`;\n } catch { /* last resort — don't throw from error handler */ }\n }\n };\n\n // Preserve static metadata\n (Wrapped as unknown as ViewComponentClass).viewName = ViewClass.viewName;\n (Wrapped as unknown as ViewComponentClass).description = ViewClass.description;\n\n return Wrapped as unknown as ViewComponentClass;\n}\n\n// ---------------------------------------------------------------------------\n// defineViews()\n// ---------------------------------------------------------------------------\n\n/**\n * Build a `ViewRegistry` from component classes.\n *\n * In the browser the components are registered as custom elements with\n * deterministic tag names (`fg-{entityType}-{viewName}`). On the server\n * (Node.js) only metadata is returned — no custom element registration.\n */\nexport function defineViews(input: ViewRegistryInput): ViewRegistry {\n const nodes: Record<string, EntityViewMeta> = {};\n const edges: Record<string, EntityViewMeta> = {};\n const registry = getCustomElements();\n\n // --- nodes ---\n for (const [entityType, config] of Object.entries(input.nodes ?? {})) {\n const viewMetas: ViewMeta[] = [];\n for (const ViewClass of config.views) {\n const tagName = `fg-${sanitizeTagPart(entityType)}-${sanitizeTagPart(ViewClass.viewName)}`;\n viewMetas.push({\n tagName,\n viewName: ViewClass.viewName,\n description: ViewClass.description,\n });\n if (registry && !registry.get(tagName)) {\n registry.define(tagName, resilientView(ViewClass, tagName));\n }\n }\n nodes[entityType] = {\n views: viewMetas,\n sampleData: config.sampleData,\n };\n }\n\n // --- edges ---\n for (const [axbType, config] of Object.entries(input.edges ?? {})) {\n const viewMetas: ViewMeta[] = [];\n for (const ViewClass of config.views) {\n const tagName = `fg-edge-${sanitizeTagPart(axbType)}-${sanitizeTagPart(ViewClass.viewName)}`;\n viewMetas.push({\n tagName,\n viewName: ViewClass.viewName,\n description: ViewClass.description,\n });\n if (registry && !registry.get(tagName)) {\n registry.define(tagName, resilientView(ViewClass, tagName));\n }\n }\n edges[axbType] = {\n views: viewMetas,\n sampleData: config.sampleData,\n };\n }\n\n return { nodes, edges };\n}\n","/**\n * Firegraph Configuration — project-level config file support.\n *\n * Projects create a `firegraph.config.ts` (or `.js`/`.mjs`) in their root:\n *\n * @example\n * ```ts\n * import { defineConfig } from 'firegraph';\n *\n * export default defineConfig({\n * entities: './entities',\n * project: 'my-project',\n * collection: 'graph',\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// View Resolution Types\n// ---------------------------------------------------------------------------\n\n/** Display contexts where views can appear. */\nexport type ViewContext = 'listing' | 'detail' | 'inline';\n\n/** View resolution configuration for a single entity type. */\nexport interface ViewResolverConfig {\n /** Default view name (e.g. 'card'). Falls back to 'json' if unset. */\n default?: string;\n /** View to use in NodeBrowser listing rows. */\n listing?: string;\n /** View to use on the NodeDetail page. */\n detail?: string;\n /** View to use for inline/embedded previews (edge rows, traversal). */\n inline?: string;\n}\n\n/** Declarative view defaults, keyed by entity type. */\nexport interface ViewDefaultsConfig {\n /** Node view defaults keyed by aType (e.g. 'user', 'task'). */\n nodes?: Record<string, ViewResolverConfig>;\n /** Edge view defaults keyed by axbType (e.g. 'hasDeparture'). */\n edges?: Record<string, ViewResolverConfig>;\n}\n\n// ---------------------------------------------------------------------------\n// Config Shape\n// ---------------------------------------------------------------------------\n\n/** Project-level firegraph configuration. */\nexport interface FiregraphConfig {\n /** Path to entities directory (per-entity folder convention). */\n entities?: string;\n /** GCP project ID. */\n project?: string;\n /** Firestore collection path (default: 'graph'). */\n collection?: string;\n /** Firestore emulator address (e.g. '127.0.0.1:8080'). */\n emulator?: string;\n /**\n * Query execution backend.\n *\n * - `'pipeline'` (default) — Uses Firestore Pipeline API. Requires Enterprise\n * Firestore. Enables indexless queries on `data.*` fields.\n * - `'standard'` — Uses standard Firestore `.where().get()` queries. Not\n * recommended for production. See README for risk details.\n *\n * When the emulator is active, always falls back to `'standard'`.\n */\n queryMode?: import('./types.js').QueryMode;\n\n /**\n * AI chat configuration. Auto-detects `claude` CLI on PATH by default.\n * Set to `false` to disable chat even if claude is available.\n */\n chat?: false | {\n /** Claude model to use (default: 'sonnet'). */\n model?: string;\n /** Maximum concurrent claude processes (default: 2). */\n maxConcurrency?: number;\n };\n\n /** Editor-specific settings. */\n editor?: {\n /** Server port (default: 3883). */\n port?: number;\n /** Force read-only mode. */\n readonly?: boolean;\n };\n\n /** Declarative view defaults per entity type (overrides per-entity meta.json). */\n viewDefaults?: ViewDefaultsConfig;\n\n /**\n * Dynamic registry mode. When set, the editor loads type definitions\n * from Firestore meta-nodes in addition to filesystem entities.\n * Filesystem types take precedence on name conflicts.\n */\n registryMode?: import('./types.js').DynamicRegistryConfig;\n}\n\n// ---------------------------------------------------------------------------\n// defineConfig()\n// ---------------------------------------------------------------------------\n\n/**\n * Identity function providing type-checking and autocomplete for config files.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'firegraph';\n * export default defineConfig({ entities: './entities' });\n * ```\n */\nexport function defineConfig(config: FiregraphConfig): FiregraphConfig {\n return config;\n}\n\n// ---------------------------------------------------------------------------\n// View Resolution (pure — works client-side and server-side)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve which view to show for a given entity.\n *\n * 1. If `context` is provided and a context-specific default exists, use it.\n * 2. Falls back to `resolverConfig.default`.\n * 3. Ultimate fallback: `'json'`.\n *\n * Only returns view names that exist in `availableViewNames`.\n */\nexport function resolveView(\n resolverConfig: ViewResolverConfig | undefined,\n availableViewNames: string[],\n context?: ViewContext,\n): string {\n if (!resolverConfig) return 'json';\n\n const available = new Set(availableViewNames);\n\n if (context) {\n const contextDefault = resolverConfig[context];\n if (contextDefault && available.has(contextDefault)) {\n return contextDefault;\n }\n }\n\n if (resolverConfig.default && available.has(resolverConfig.default)) {\n return resolverConfig.default;\n }\n\n return 'json';\n}\n","/**\n * Entity Discovery — convention-based auto-discovery of entities from\n * a per-entity folder structure.\n *\n * Scans `entitiesDir/nodes/` and `entitiesDir/edges/` subdirectories.\n * Each subfolder is treated as an entity type.\n *\n * Schema files can be either `schema.json` (plain JSON Schema) or\n * `schema.ts` / `schema.js` (a module whose default export is a JSON Schema\n * object). When both exist, the TS/JS file takes precedence so that authors\n * can compose schemas programmatically while keeping a JSON fallback.\n *\n * @example\n * ```\n * entities/\n * nodes/\n * task/\n * schema.json | schema.ts (required — one or both)\n * views.ts (optional)\n * sample.json (optional)\n * meta.json (optional)\n * edges/\n * hasStep/\n * schema.json | schema.ts (required — one or both)\n * edge.json (required — topology)\n * views.ts (optional)\n * sample.json (optional)\n * meta.json (optional)\n * ```\n */\n\nimport { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join, resolve } from 'node:path';\nimport type { DiscoveredEntity, DiscoveryResult, EdgeTopology } from './types.js';\nimport type { ViewResolverConfig } from './config.js';\nimport { FiregraphError } from './errors.js';\n\nexport class DiscoveryError extends FiregraphError {\n constructor(message: string) {\n super(message, 'DISCOVERY_ERROR');\n this.name = 'DiscoveryError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON parsing helpers\n// ---------------------------------------------------------------------------\n\nfunction readJson(filePath: string): unknown {\n try {\n const raw = readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch (err: unknown) {\n const msg = err instanceof SyntaxError\n ? `Invalid JSON in ${filePath}: ${err.message}`\n : `Cannot read ${filePath}: ${(err as Error).message}`;\n throw new DiscoveryError(msg);\n }\n}\n\nfunction readJsonIfExists(filePath: string): unknown | undefined {\n if (!existsSync(filePath)) return undefined;\n return readJson(filePath);\n}\n\n// ---------------------------------------------------------------------------\n// Schema file loading (JSON or TS/JS via jiti)\n// ---------------------------------------------------------------------------\n\nconst SCHEMA_SCRIPT_EXTENSIONS = ['.ts', '.js', '.mts', '.mjs'];\n\n/**\n * Attempt to load a schema from a TS/JS module (default export) or fall back\n * to schema.json. Returns the parsed schema object or throws.\n */\nfunction loadSchema(dir: string, entityLabel: string): object {\n // Prefer TS/JS schema — allows programmatic composition & shared definitions\n for (const ext of SCHEMA_SCRIPT_EXTENSIONS) {\n const candidate = join(dir, `schema${ext}`);\n if (existsSync(candidate)) {\n return loadSchemaModule(candidate, entityLabel);\n }\n }\n\n // Fall back to schema.json\n const jsonPath = join(dir, 'schema.json');\n if (existsSync(jsonPath)) {\n return readJson(jsonPath) as object;\n }\n\n throw new DiscoveryError(\n `Missing schema for ${entityLabel} in ${dir}. ` +\n 'Provide a schema.ts (or .js/.mts/.mjs) or schema.json file.',\n );\n}\n\nlet _jiti: ((id: string) => unknown) | undefined;\n\nfunction getJiti(): (id: string) => unknown {\n if (!_jiti) {\n const base = typeof __filename !== 'undefined' ? __filename : import.meta.url;\n const esmRequire = createRequire(base);\n const { createJiti } = esmRequire('jiti') as typeof import('jiti');\n _jiti = createJiti(base, { interopDefault: true });\n }\n return _jiti;\n}\n\nfunction loadSchemaModule(filePath: string, entityLabel: string): object {\n try {\n const jiti = getJiti();\n const mod = jiti(filePath) as { default?: unknown } | unknown;\n const schema = (mod && typeof mod === 'object' && 'default' in mod)\n ? (mod as { default: unknown }).default\n : mod;\n\n if (!schema || typeof schema !== 'object') {\n throw new DiscoveryError(\n `Schema file ${filePath} for ${entityLabel} must default-export a JSON Schema object.`,\n );\n }\n return schema as object;\n } catch (err: unknown) {\n if (err instanceof DiscoveryError) throw err;\n throw new DiscoveryError(\n `Failed to load schema module ${filePath} for ${entityLabel}: ${(err as Error).message}`,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// View file detection\n// ---------------------------------------------------------------------------\n\nconst VIEW_EXTENSIONS = ['.ts', '.js', '.mts', '.mjs'];\n\nfunction findViewsFile(dir: string): string | undefined {\n for (const ext of VIEW_EXTENSIONS) {\n const candidate = join(dir, `views${ext}`);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Entity loaders\n// ---------------------------------------------------------------------------\n\nfunction loadNodeEntity(dir: string, name: string): DiscoveredEntity {\n const schema = loadSchema(dir, `node type \"${name}\"`);\n const meta = readJsonIfExists(join(dir, 'meta.json')) as\n | { description?: string; titleField?: string; subtitleField?: string; viewDefaults?: ViewResolverConfig; allowedIn?: string[] }\n | undefined;\n const sampleData = readJsonIfExists(join(dir, 'sample.json')) as\n | Record<string, unknown>\n | undefined;\n const viewsPath = findViewsFile(dir);\n\n return {\n kind: 'node',\n name,\n schema,\n description: meta?.description,\n titleField: meta?.titleField,\n subtitleField: meta?.subtitleField,\n viewDefaults: meta?.viewDefaults,\n viewsPath,\n sampleData,\n allowedIn: meta?.allowedIn,\n };\n}\n\nfunction loadEdgeEntity(dir: string, name: string): DiscoveredEntity {\n const schema = loadSchema(dir, `edge type \"${name}\"`);\n\n const edgePath = join(dir, 'edge.json');\n if (!existsSync(edgePath)) {\n throw new DiscoveryError(\n `Missing edge.json for edge type \"${name}\" in ${dir}. ` +\n 'Edge entities must declare topology (from/to node types).',\n );\n }\n const topology = readJson(edgePath) as EdgeTopology;\n\n // Validate topology shape\n if (!topology.from) {\n throw new DiscoveryError(\n `edge.json for \"${name}\" is missing required \"from\" field`,\n );\n }\n if (!topology.to) {\n throw new DiscoveryError(\n `edge.json for \"${name}\" is missing required \"to\" field`,\n );\n }\n\n const meta = readJsonIfExists(join(dir, 'meta.json')) as\n | { description?: string; titleField?: string; subtitleField?: string; viewDefaults?: ViewResolverConfig; allowedIn?: string[]; targetGraph?: string }\n | undefined;\n const sampleData = readJsonIfExists(join(dir, 'sample.json')) as\n | Record<string, unknown>\n | undefined;\n const viewsPath = findViewsFile(dir);\n\n return {\n kind: 'edge',\n name,\n schema,\n topology,\n description: meta?.description,\n titleField: meta?.titleField,\n subtitleField: meta?.subtitleField,\n viewDefaults: meta?.viewDefaults,\n viewsPath,\n sampleData,\n allowedIn: meta?.allowedIn,\n targetGraph: topology.targetGraph ?? (meta as { targetGraph?: string } | undefined)?.targetGraph,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Directory scanner\n// ---------------------------------------------------------------------------\n\nfunction getSubdirectories(dir: string): string[] {\n if (!existsSync(dir)) return [];\n return readdirSync(dir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface DiscoveryWarning {\n code: 'DANGLING_TOPOLOGY_REF';\n message: string;\n}\n\nexport interface DiscoverResult {\n result: DiscoveryResult;\n warnings: DiscoveryWarning[];\n}\n\n/**\n * Scan an entities directory and return all discovered nodes and edges.\n *\n * @param entitiesDir - Path to the entities directory (absolute or relative to cwd)\n * @returns Discovery result with nodes and edges maps, plus any warnings\n */\nexport function discoverEntities(entitiesDir: string): DiscoverResult {\n const absDir = resolve(entitiesDir);\n\n if (!existsSync(absDir) || !statSync(absDir).isDirectory()) {\n throw new DiscoveryError(`Entities directory not found: ${entitiesDir}`);\n }\n\n const nodes = new Map<string, DiscoveredEntity>();\n const edges = new Map<string, DiscoveredEntity>();\n const warnings: DiscoveryWarning[] = [];\n\n // Discover nodes\n const nodesDir = join(absDir, 'nodes');\n for (const name of getSubdirectories(nodesDir)) {\n nodes.set(name, loadNodeEntity(join(nodesDir, name), name));\n }\n\n // Discover edges\n const edgesDir = join(absDir, 'edges');\n for (const name of getSubdirectories(edgesDir)) {\n edges.set(name, loadEdgeEntity(join(edgesDir, name), name));\n }\n\n // Validate topology references\n const nodeNames = new Set(nodes.keys());\n for (const [axbType, entity] of edges) {\n const topology = entity.topology!;\n const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];\n const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];\n\n for (const ref of [...fromTypes, ...toTypes]) {\n if (!nodeNames.has(ref)) {\n warnings.push({\n code: 'DANGLING_TOPOLOGY_REF',\n message: `Edge \"${axbType}\" references node type \"${ref}\" which was not found in the nodes directory`,\n });\n }\n }\n }\n\n return {\n result: { nodes, edges },\n warnings,\n };\n}\n","/**\n * Cross-graph edge resolution utilities.\n *\n * Provides path-scanning resolution for determining whether an edge's source\n * (aUid) is an ancestor node by checking if the UID appears in the Firestore\n * collection path.\n *\n * Firestore paths have a rigid alternating structure:\n * collection / docId / collection / docId / collection\n *\n * Given a path like `graph/A/workspace/B/context`, segments at even indices\n * are collection names and odd indices are document IDs. When we find a UID\n * at an odd index, the collection containing that document is the path up to\n * (and including) the preceding even-index segment.\n */\n\n/**\n * Parse a Firestore collection path and determine the collection path\n * where a given UID's document lives, if that UID is an ancestor in the path.\n *\n * @param collectionPath - The full Firestore collection path of the current client\n * @param uid - The UID to search for in the path\n * @returns The collection path containing the UID, or `null` if not found in the path\n *\n * @example\n * ```ts\n * // Path: graph/A/workspace/B/context\n * resolveAncestorCollection('graph/A/workspace/B/context', 'A')\n * // → 'graph'\n *\n * resolveAncestorCollection('graph/A/workspace/B/context', 'B')\n * // → 'graph/A/workspace'\n *\n * resolveAncestorCollection('graph/A/workspace/B/context', 'unknown')\n * // → null\n * ```\n */\nexport function resolveAncestorCollection(\n collectionPath: string,\n uid: string,\n): string | null {\n const segments = collectionPath.split('/');\n\n // Walk odd-indexed segments (document IDs in Firestore's alternating path structure)\n for (let i = 1; i < segments.length; i += 2) {\n if (segments[i] === uid) {\n // The collection containing this doc is everything up to index i-1\n return segments.slice(0, i).join('/');\n }\n }\n\n return null;\n}\n\n/**\n * Check whether a UID belongs to an ancestor node by scanning the collection path.\n *\n * @param collectionPath - The full Firestore collection path of the current client\n * @param uid - The UID to check\n * @returns `true` if the UID appears as a document segment in the path\n */\nexport function isAncestorUid(\n collectionPath: string,\n uid: string,\n): boolean {\n return resolveAncestorCollection(collectionPath, uid) !== null;\n}\n","/**\n * Code generation — produces TypeScript type definitions from JSON Schema\n * files discovered via the entity folder convention.\n *\n * Uses `json-schema-to-typescript` to compile each entity's `schema.json`\n * into a TypeScript interface.\n *\n * Naming convention:\n * - Nodes: `{PascalName}Data` (e.g. `TaskData`)\n * - Edges: `{PascalName}EdgeData` (e.g. `HasStepEdgeData`)\n */\n\nimport type { DiscoveryResult } from '../types.js';\n\nfunction pascalCase(s: string): string {\n return s.replace(/(^|[^a-zA-Z0-9])([a-zA-Z])/g, (_, _sep, ch) =>\n ch.toUpperCase(),\n );\n}\n\nexport interface CodegenOptions {\n /** Add banner comment at top of output. Defaults to true. */\n banner?: boolean;\n}\n\n/**\n * Generate TypeScript type definitions from a DiscoveryResult.\n * Returns the full file content as a string.\n */\nexport async function generateTypes(\n discovery: DiscoveryResult,\n options: CodegenOptions = {},\n): Promise<string> {\n // Lazy-load to avoid requiring this dep at runtime for non-codegen usage\n const { compile } = await import('json-schema-to-typescript');\n\n const { banner = true } = options;\n const chunks: string[] = [];\n\n if (banner) {\n chunks.push(\n '// Auto-generated by firegraph codegen — do not edit manually\\n',\n );\n }\n\n // Sort for deterministic output\n const sortedNodes = [...discovery.nodes.entries()].sort(([a], [b]) =>\n a.localeCompare(b),\n );\n const sortedEdges = [...discovery.edges.entries()].sort(([a], [b]) =>\n a.localeCompare(b),\n );\n\n for (const [name, entity] of sortedNodes) {\n const typeName = `${pascalCase(name)}Data`;\n const ts = await compile(entity.schema as any, typeName, {\n bannerComment: '',\n additionalProperties: false,\n });\n chunks.push(ts.trim());\n chunks.push('');\n }\n\n for (const [name, entity] of sortedEdges) {\n const typeName = `${pascalCase(name)}EdgeData`;\n const ts = await compile(entity.schema as any, typeName, {\n bannerComment: '',\n additionalProperties: false,\n });\n chunks.push(ts.trim());\n chunks.push('');\n }\n\n return chunks.join('\\n').trimEnd() + '\\n';\n}\n","import type { DiscoveryResult, RegistryEntry } from './types.js';\n\nexport interface FirestoreIndexField {\n fieldPath: string;\n order: 'ASCENDING' | 'DESCENDING';\n}\n\nexport interface FirestoreIndex {\n collectionGroup: string;\n queryScope: 'COLLECTION' | 'COLLECTION_GROUP';\n fields: FirestoreIndexField[];\n}\n\nexport interface FirestoreIndexConfig {\n indexes: FirestoreIndex[];\n fieldOverrides: unknown[];\n}\n\n/**\n * Base composite indexes required for all firegraph collections.\n * These cover the standard query patterns:\n * - Forward edge lookup: (aUid, axbType)\n * - Reverse edge lookup: (axbType, bUid)\n * - Type-scoped queries: (aType, axbType) — also covers findNodes\n * - Edge type + target: (axbType, bType)\n */\nfunction baseIndexes(collection: string): FirestoreIndex[] {\n return [\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bUid', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bType', order: 'ASCENDING' },\n ],\n },\n ];\n}\n\n/**\n * Extracts top-level field names from a JSON Schema object.\n * Only returns fields from schemas with type: \"object\" and properties.\n */\nfunction extractSchemaFields(schema: object): string[] {\n const s = schema as Record<string, unknown>;\n if (s.type !== 'object' || !s.properties) return [];\n return Object.keys(s.properties as Record<string, unknown>);\n}\n\n/**\n * Collection group indexes for `findEdgesGlobal()` queries.\n *\n * These mirror the base collection indexes but with `COLLECTION_GROUP` scope,\n * which allows querying across all subcollections with the given name.\n * Only generated when the registry has edge types with `targetGraph` set,\n * indicating cross-graph edges exist and global queries are likely.\n */\nfunction collectionGroupIndexes(collectionName: string): FirestoreIndex[] {\n return [\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bUid', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n ],\n },\n {\n collectionGroup: collectionName,\n queryScope: 'COLLECTION_GROUP',\n fields: [\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: 'bType', order: 'ASCENDING' },\n ],\n },\n ];\n}\n\n/**\n * Generates a Firestore index configuration for a firegraph collection.\n *\n * Always includes the 4 base composite indexes. If an entity discovery result\n * is provided, generates additional data-field indexes for common query\n * patterns on node data fields:\n * (aType, axbType, data.{field})\n *\n * When registry entries with `targetGraph` are provided, also generates\n * collection group indexes for `findEdgesGlobal()` queries. The collection\n * group name defaults to `'graph'` (the standard subgraph name) but can be\n * overridden per `targetGraph` value.\n *\n * @param collection - Firestore collection name (e.g. 'graph')\n * @param entities - Optional discovery result for per-entity data field indexes\n * @param registryEntries - Optional registry entries; when any have `targetGraph`,\n * collection group indexes are generated for the distinct subgraph names\n */\nexport function generateIndexConfig(\n collection: string,\n entities?: DiscoveryResult,\n registryEntries?: ReadonlyArray<RegistryEntry>,\n): FirestoreIndexConfig {\n const indexes = baseIndexes(collection);\n\n if (entities) {\n // Generate data-field indexes for node types.\n // Pattern: (aType, axbType, data.{field}) — covers findNodes with where clauses\n // and findEdges scoped by aType + axbType + data filter.\n for (const [, entity] of entities.nodes) {\n const fields = extractSchemaFields(entity.schema);\n for (const field of fields) {\n indexes.push({\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aType', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: `data.${field}`, order: 'ASCENDING' },\n ],\n });\n }\n }\n\n // Generate data-field indexes for edge types.\n // Pattern: (aUid, axbType, data.{field}) — covers forward edge lookups with data filters.\n for (const [, entity] of entities.edges) {\n const fields = extractSchemaFields(entity.schema);\n for (const field of fields) {\n indexes.push({\n collectionGroup: collection,\n queryScope: 'COLLECTION',\n fields: [\n { fieldPath: 'aUid', order: 'ASCENDING' },\n { fieldPath: 'axbType', order: 'ASCENDING' },\n { fieldPath: `data.${field}`, order: 'ASCENDING' },\n ],\n });\n }\n }\n }\n\n // Generate collection group indexes when cross-graph edges exist.\n // Each distinct targetGraph value gets its own set of collection group indexes.\n if (registryEntries) {\n const targetGraphNames = new Set<string>();\n for (const entry of registryEntries) {\n if (entry.targetGraph) {\n targetGraphNames.add(entry.targetGraph);\n }\n }\n for (const name of targetGraphNames) {\n indexes.push(...collectionGroupIndexes(name));\n }\n }\n\n return { indexes, fieldOverrides: [] };\n}\n","import http from 'node:http';\nimport type {\n QueryClientOptions,\n SchemaResult,\n GetNodeDetailInput,\n NodeDetailResult,\n GetNodesInput,\n GetNodesResult,\n GetEdgesInput,\n GetEdgesResult,\n TraverseInput,\n TraverseResult,\n TraverseHopResult,\n SearchInput,\n SearchResult,\n SummarizedRecord,\n SummarizedEdge,\n} from './types.js';\nimport { summarizeRecord, summarizeEdge } from './shaping.js';\nimport { readEditorPort } from './config.js';\n\n// --- Error ---\n\nexport type QueryClientErrorCode = 'VALIDATION_ERROR' | 'CONNECTION_FAILED' | 'SERVER_ERROR';\n\nexport class QueryClientError extends Error {\n constructor(\n message: string,\n public readonly code: QueryClientErrorCode,\n ) {\n super(message);\n this.name = 'QueryClientError';\n }\n}\n\n// --- Validation helpers ---\n\nfunction requireString(value: unknown, name: string): asserts value is string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new QueryClientError(`${name} must be a non-empty string`, 'VALIDATION_ERROR');\n }\n}\n\nfunction clampInt(value: number | undefined, min: number, max: number, fallback: number): number {\n if (value == null) return fallback;\n if (!Number.isInteger(value)) {\n throw new QueryClientError(`limit must be an integer`, 'VALIDATION_ERROR');\n }\n return Math.max(min, Math.min(max, value));\n}\n\nfunction validateSortDir(dir: string | undefined): void {\n if (dir != null && dir !== 'asc' && dir !== 'desc') {\n throw new QueryClientError(`sortDir must be 'asc' or 'desc'`, 'VALIDATION_ERROR');\n }\n}\n\n// --- HTTP helpers ---\n\nfunction httpGet(url: string): Promise<string> {\n return new Promise((resolve, reject) => {\n http\n .get(url, (res) => {\n let body = '';\n res.on('data', (c: string) => (body += c));\n res.on('end', () => resolve(body));\n })\n .on('error', (err) => {\n reject(new QueryClientError(`Connection failed: ${err.message}`, 'CONNECTION_FAILED'));\n });\n });\n}\n\nfunction httpPost(url: string, payload: string): Promise<string> {\n const parsed = new URL(url);\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n hostname: parsed.hostname,\n port: parsed.port,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(payload),\n },\n },\n (res) => {\n let body = '';\n res.on('data', (c: string) => (body += c));\n res.on('end', () => resolve(body));\n },\n );\n req.on('error', (err) => {\n reject(new QueryClientError(`Connection failed: ${err.message}`, 'CONNECTION_FAILED'));\n });\n req.write(payload);\n req.end();\n });\n}\n\nfunction parseTrpcResponse(raw: string, procedure: string): unknown {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new QueryClientError(\n `Invalid JSON from ${procedure}: ${raw.slice(0, 200)}`,\n 'SERVER_ERROR',\n );\n }\n if (parsed.error) {\n const msg =\n typeof parsed.error === 'object' && parsed.error !== null\n ? (parsed.error as Record<string, unknown>).message ?? JSON.stringify(parsed.error)\n : String(parsed.error);\n throw new QueryClientError(`Server error from ${procedure}: ${msg}`, 'SERVER_ERROR');\n }\n return (parsed.result as Record<string, unknown>)?.data ?? parsed;\n}\n\n// --- Client ---\n\nexport class QueryClient {\n private readonly baseUrl: string;\n\n constructor(options?: QueryClientOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? readEditorPort();\n this.baseUrl = `http://${host}:${port}/api/trpc`;\n }\n\n private async query(procedure: string, input?: unknown): Promise<unknown> {\n const qs =\n input != null ? `?input=${encodeURIComponent(JSON.stringify(input))}` : '';\n const url = `${this.baseUrl}/${procedure}${qs}`;\n const raw = await httpGet(url);\n return parseTrpcResponse(raw, procedure);\n }\n\n private async mutate(procedure: string, input: unknown): Promise<unknown> {\n const url = `${this.baseUrl}/${procedure}`;\n const raw = await httpPost(url, JSON.stringify(input));\n return parseTrpcResponse(raw, procedure);\n }\n\n // --- Public API ---\n\n async getSchema(): Promise<SchemaResult> {\n const data = (await this.query('getSchema')) as Record<string, unknown>;\n return {\n nodeTypes: ((data.nodeTypes as unknown[]) ?? []).map(\n (t) => (typeof t === 'object' && t !== null ? (t as Record<string, unknown>).type : t) as string,\n ),\n edgeTypes: ((data.edgeTypes as unknown[]) ?? []).map((t) => {\n const e = t as Record<string, unknown>;\n return {\n relation: e.axbType as string,\n from: e.aType as string,\n to: e.bType as string,\n inverseLabel: (e.inverseLabel as string) ?? null,\n };\n }),\n };\n }\n\n async getNodeDetail(input: GetNodeDetailInput): Promise<NodeDetailResult> {\n requireString(input.uid, 'uid');\n const data = (await this.query('getNodeDetail', { uid: input.uid })) as Record<string, unknown>;\n return {\n node: summarizeRecord(data.node as Record<string, unknown> | null),\n outEdges: ((data.outEdges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n inEdges: ((data.inEdges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n };\n }\n\n async getNodes(input: GetNodesInput): Promise<GetNodesResult> {\n const limit = clampInt(input.limit, 1, 200, 25);\n validateSortDir(input.sortDir);\n const data = (await this.query('getNodes', {\n type: input.type,\n limit,\n startAfter: input.startAfter,\n sortBy: input.sortBy,\n sortDir: input.sortDir,\n where: input.where,\n })) as Record<string, unknown>;\n return {\n nodes: ((data.nodes as Record<string, unknown>[]) ?? []).map(summarizeRecord).filter(Boolean) as SummarizedRecord[],\n hasMore: (data.hasMore as boolean) ?? false,\n nextCursor: data.nextCursor as string | null | undefined,\n };\n }\n\n async getEdges(input: GetEdgesInput): Promise<GetEdgesResult> {\n const hasFilter = input.aType || input.aUid || input.axbType || input.bType || input.bUid || (input.where && input.where.length > 0);\n if (!hasFilter) {\n throw new QueryClientError(\n 'getEdges requires at least one filter field (aType, aUid, axbType, bType, bUid, or where)',\n 'VALIDATION_ERROR',\n );\n }\n const limit = clampInt(input.limit, 1, 200, 25);\n validateSortDir(input.sortDir);\n const data = (await this.query('getEdges', {\n aType: input.aType,\n aUid: input.aUid,\n axbType: input.axbType,\n bType: input.bType,\n bUid: input.bUid,\n limit,\n startAfter: input.startAfter,\n sortBy: input.sortBy,\n sortDir: input.sortDir,\n where: input.where,\n })) as Record<string, unknown>;\n return {\n edges: ((data.edges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n hasMore: (data.hasMore as boolean) ?? false,\n nextCursor: data.nextCursor as string | null | undefined,\n };\n }\n\n async traverse(input: TraverseInput): Promise<TraverseResult> {\n requireString(input.startUid, 'startUid');\n if (!input.hops || input.hops.length === 0) {\n throw new QueryClientError('traverse requires at least one hop', 'VALIDATION_ERROR');\n }\n for (let i = 0; i < input.hops.length; i++) {\n const hop = input.hops[i];\n requireString(hop.axbType, `hops[${i}].axbType`);\n if (hop.direction != null && hop.direction !== 'forward' && hop.direction !== 'reverse') {\n throw new QueryClientError(\n `hops[${i}].direction must be 'forward' or 'reverse'`,\n 'VALIDATION_ERROR',\n );\n }\n if (hop.limit != null && (!Number.isInteger(hop.limit) || hop.limit < 1)) {\n throw new QueryClientError(\n `hops[${i}].limit must be a positive integer`,\n 'VALIDATION_ERROR',\n );\n }\n }\n if (input.maxReads != null && (!Number.isInteger(input.maxReads) || input.maxReads < 1)) {\n throw new QueryClientError('maxReads must be a positive integer', 'VALIDATION_ERROR');\n }\n if (input.concurrency != null && (!Number.isInteger(input.concurrency) || input.concurrency < 1)) {\n throw new QueryClientError('concurrency must be a positive integer', 'VALIDATION_ERROR');\n }\n\n const data = (await this.mutate('traverse', input)) as Record<string, unknown>;\n return {\n hops: ((data.hops as Record<string, unknown>[]) ?? []).map((h): TraverseHopResult => ({\n relation: h.axbType as string,\n direction: h.direction as string,\n depth: h.depth as number,\n edgeCount: ((h.edges as unknown[]) ?? []).length,\n edges: ((h.edges as Record<string, unknown>[]) ?? []).map(summarizeEdge).filter(Boolean) as SummarizedEdge[],\n truncated: (h.truncated as boolean) ?? false,\n })),\n totalReads: (data.totalReads as number) ?? 0,\n truncated: (data.truncated as boolean) ?? false,\n };\n }\n\n async search(input: SearchInput): Promise<SearchResult> {\n requireString(input.q, 'q');\n const limit = clampInt(input.limit, 1, 50, 20);\n const data = (await this.query('search', { q: input.q, limit })) as Record<string, unknown>;\n return {\n results: ((data.results as Record<string, unknown>[]) ?? []).map((r) => {\n const base = summarizeRecord(r);\n if (!base) return null;\n return {\n ...base,\n matchType: (r._matchType as string) ?? null,\n };\n }).filter(Boolean) as (SummarizedRecord & { matchType: string | null })[],\n };\n }\n}\n","import type { SummarizedRecord, SummarizedEdge } from './types.js';\n\nexport function summarizeRecord(r: Record<string, unknown> | null): SummarizedRecord | null {\n if (!r) return null;\n const out: SummarizedRecord = { type: r.aType as string, uid: r.aUid as string };\n const data = r.data as Record<string, unknown> | undefined;\n if (data && typeof data === 'object' && Object.keys(data).length > 0) {\n out.data = data;\n }\n return out;\n}\n\nexport function summarizeEdge(r: Record<string, unknown> | null): SummarizedEdge | null {\n if (!r) return null;\n const out: SummarizedEdge = {\n fromType: r.aType as string,\n fromUid: r.aUid as string,\n relation: r.axbType as string,\n toType: r.bType as string,\n toUid: r.bUid as string,\n };\n const data = r.data as Record<string, unknown> | undefined;\n if (data && typeof data === 'object' && Object.keys(data).length > 0) {\n out.data = data;\n }\n return out;\n}\n","import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst CONFIG_FILES = ['firegraph.config.ts', 'firegraph.config.js', 'firegraph.config.mjs'];\nconst DEFAULT_PORT = 3884;\n\n/**\n * Read the editor port from firegraph config files using regex.\n * Zero-dependency — no jiti needed.\n */\nexport function readEditorPort(cwd?: string): number {\n const dir = cwd ?? process.cwd();\n for (const name of CONFIG_FILES) {\n try {\n const content = readFileSync(join(dir, name), 'utf8');\n const editorBlock = content.match(/editor\\s*:\\s*\\{[^}]*\\}/s)?.[0] ?? '';\n const portMatch = editorBlock.match(/port\\s*:\\s*(\\d+)/);\n if (portMatch) return parseInt(portMatch[1], 10);\n } catch {\n continue;\n }\n }\n return DEFAULT_PORT;\n}\n"],"mappings":"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","names":["import_firestore","import_firestore","import_firestore","resolve","import_node_crypto","Ajv","resolve","edges","import_node_fs","import_node_path","resolve","http"]}