@flowrag/core 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -245,5 +245,14 @@ declare function withNamespace(storage: StorageSet, namespace: string): StorageS
245
245
  */
246
246
  declare function buildExtractionPrompt(content: string, knownEntities: string[], schema: Schema): string;
247
247
  //#endregion
248
- export { Chunk, Document, DocumentMetadata, DocumentParser, Embedder, Entity, EntityFilter, EvalDocument, EvalResult, Evaluator, ExtractedEntity, ExtractedRelation, ExtractionResult, FieldDefinition, GraphStorage, Id, KVStorage, LLMExtractor, ParsedDocument, QueryMode, Relation, RelationDirection, RerankDocument, RerankResult, Reranker, Schema, SchemaConfig, SearchResult, StorageSet, TokenUsage, VectorFilter, VectorRecord, VectorStorage, buildExtractionPrompt, defineSchema, withNamespace };
248
+ //#region src/retry.d.ts
249
+ interface RetryOptions {
250
+ retries?: number;
251
+ backoff?: number;
252
+ maxBackoff?: number;
253
+ retryOn?: (error: unknown) => boolean;
254
+ }
255
+ declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
256
+ //#endregion
257
+ export { Chunk, Document, DocumentMetadata, DocumentParser, Embedder, Entity, EntityFilter, EvalDocument, EvalResult, Evaluator, ExtractedEntity, ExtractedRelation, ExtractionResult, FieldDefinition, GraphStorage, Id, KVStorage, LLMExtractor, ParsedDocument, QueryMode, Relation, RelationDirection, RerankDocument, RerankResult, Reranker, RetryOptions, Schema, SchemaConfig, SearchResult, StorageSet, TokenUsage, VectorFilter, VectorRecord, VectorStorage, buildExtractionPrompt, defineSchema, withNamespace, withRetry };
249
258
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -175,6 +175,39 @@ Return a JSON object with this structure:
175
175
  Focus on technical entities and their relationships. Be precise and avoid duplicates.${entityFieldsDef || relationFieldsDef ? "\nInclude a \"fields\" object in each entity/relation with the custom field values when applicable." : ""}`;
176
176
  }
177
177
 
178
+ //#endregion
179
+ //#region src/retry.ts
180
+ const DEFAULT_RETRIES = 3;
181
+ const DEFAULT_BACKOFF = 1e3;
182
+ const DEFAULT_MAX_BACKOFF = 3e4;
183
+ function isTransientError(error) {
184
+ let current = error;
185
+ while (current instanceof Error) {
186
+ const msg = current.message.toLowerCase();
187
+ if (msg.includes("timeout") || msg.includes("econnreset") || msg.includes("econnrefused")) return true;
188
+ const status = current.status ?? current.statusCode;
189
+ if (status === 429 || status === 500 || status === 502 || status === 503 || status === 504) return true;
190
+ current = current.cause;
191
+ }
192
+ return false;
193
+ }
194
+ async function withRetry(fn, options) {
195
+ const retries = options?.retries ?? DEFAULT_RETRIES;
196
+ const backoff = options?.backoff ?? DEFAULT_BACKOFF;
197
+ const maxBackoff = options?.maxBackoff ?? DEFAULT_MAX_BACKOFF;
198
+ const shouldRetry = options?.retryOn ?? isTransientError;
199
+ let lastError;
200
+ for (let attempt = 0; attempt <= retries; attempt++) try {
201
+ return await fn();
202
+ } catch (error) {
203
+ lastError = error;
204
+ if (attempt === retries || !shouldRetry(error)) throw error;
205
+ const delay = Math.min(backoff * 2 ** attempt, maxBackoff);
206
+ await new Promise((resolve) => setTimeout(resolve, delay));
207
+ }
208
+ throw lastError;
209
+ }
210
+
178
211
  //#endregion
179
212
  //#region src/schema.ts
180
213
  /**
@@ -206,5 +239,5 @@ function defineSchema(config) {
206
239
  }
207
240
 
208
241
  //#endregion
209
- export { buildExtractionPrompt, defineSchema, withNamespace };
242
+ export { buildExtractionPrompt, defineSchema, withNamespace, withRetry };
210
243
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/namespace.ts","../src/prompt.ts","../src/schema.ts"],"sourcesContent":["/**\n * Multi-tenancy namespace wrappers for storage isolation.\n */\n\nimport type { GraphStorage, KVStorage, VectorStorage } from './interfaces/storage.js';\nimport type {\n Entity,\n EntityFilter,\n Id,\n Relation,\n RelationDirection,\n SearchResult,\n VectorFilter,\n VectorRecord,\n} from './types.js';\n\nfunction pfx(ns: string, id: string): string {\n return `${ns}:${id}`;\n}\n\nfunction unpfx(ns: string, id: string): string {\n return id.slice(ns.length + 1);\n}\n\nclass NamespacedKVStorage implements KVStorage {\n constructor(\n private inner: KVStorage,\n private ns: string,\n ) {}\n\n get<T>(key: string): Promise<T | null> {\n return this.inner.get<T>(pfx(this.ns, key));\n }\n\n set<T>(key: string, value: T): Promise<void> {\n return this.inner.set(pfx(this.ns, key), value);\n }\n\n delete(key: string): Promise<void> {\n return this.inner.delete(pfx(this.ns, key));\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys = await this.inner.list(pfx(this.ns, prefix ?? ''));\n return keys.map((k) => unpfx(this.ns, k));\n }\n\n async clear(): Promise<void> {\n const keys = await this.inner.list(`${this.ns}:`);\n await Promise.all(keys.map((k) => this.inner.delete(k)));\n }\n}\n\nclass NamespacedVectorStorage implements VectorStorage {\n constructor(\n private inner: VectorStorage,\n private ns: string,\n ) {}\n\n upsert(records: VectorRecord[]): Promise<void> {\n return this.inner.upsert(\n records.map((r) => ({\n ...r,\n id: pfx(this.ns, r.id),\n metadata: { ...r.metadata, __ns: this.ns },\n })),\n );\n }\n\n async search(vector: number[], limit: number, filter?: VectorFilter): Promise<SearchResult[]> {\n const results = await this.inner.search(vector, limit, { ...filter, __ns: this.ns });\n return results.map((r) => ({\n ...r,\n id: unpfx(this.ns, r.id),\n metadata: { ...r.metadata, __ns: undefined },\n }));\n }\n\n delete(ids: Id[]): Promise<void> {\n return this.inner.delete(ids.map((id) => pfx(this.ns, id)));\n }\n\n count(): Promise<number> {\n return this.inner.count();\n }\n}\n\nclass NamespacedGraphStorage implements GraphStorage {\n constructor(\n private inner: GraphStorage,\n private ns: string,\n ) {}\n\n addEntity(entity: Entity): Promise<void> {\n return this.inner.addEntity({\n ...entity,\n id: pfx(this.ns, entity.id),\n sourceChunkIds: entity.sourceChunkIds.map((id) => pfx(this.ns, id)),\n });\n }\n\n addRelation(relation: Relation): Promise<void> {\n return this.inner.addRelation({\n ...relation,\n id: pfx(this.ns, relation.id),\n sourceId: pfx(this.ns, relation.sourceId),\n targetId: pfx(this.ns, relation.targetId),\n sourceChunkIds: relation.sourceChunkIds.map((id) => pfx(this.ns, id)),\n });\n }\n\n async getEntity(id: Id): Promise<Entity | null> {\n const e = await this.inner.getEntity(pfx(this.ns, id));\n return e ? this.unpfxEntity(e) : null;\n }\n\n async getEntities(filter?: EntityFilter): Promise<Entity[]> {\n const all = await this.inner.getEntities(filter);\n return all.filter((e) => e.id.startsWith(`${this.ns}:`)).map((e) => this.unpfxEntity(e));\n }\n\n async getRelations(entityId: Id, direction?: RelationDirection): Promise<Relation[]> {\n const rels = await this.inner.getRelations(pfx(this.ns, entityId), direction);\n return rels.map((r) => this.unpfxRelation(r));\n }\n\n async traverse(startId: Id, depth: number, relationTypes?: string[]): Promise<Entity[]> {\n const entities = await this.inner.traverse(pfx(this.ns, startId), depth, relationTypes);\n return entities.map((e) => this.unpfxEntity(e));\n }\n\n async findPath(fromId: Id, toId: Id, maxDepth?: number): Promise<Relation[]> {\n const rels = await this.inner.findPath(pfx(this.ns, fromId), pfx(this.ns, toId), maxDepth);\n return rels.map((r) => this.unpfxRelation(r));\n }\n\n deleteEntity(id: Id): Promise<void> {\n return this.inner.deleteEntity(pfx(this.ns, id));\n }\n\n deleteRelation(id: Id): Promise<void> {\n return this.inner.deleteRelation(pfx(this.ns, id));\n }\n\n private unpfxEntity(e: Entity): Entity {\n return {\n ...e,\n id: unpfx(this.ns, e.id),\n sourceChunkIds: e.sourceChunkIds.map((id) => unpfx(this.ns, id)),\n };\n }\n\n private unpfxRelation(r: Relation): Relation {\n return {\n ...r,\n id: unpfx(this.ns, r.id),\n sourceId: unpfx(this.ns, r.sourceId),\n targetId: unpfx(this.ns, r.targetId),\n sourceChunkIds: r.sourceChunkIds.map((id) => unpfx(this.ns, id)),\n };\n }\n}\n\n/** Storage set for FlowRAG */\nexport interface StorageSet {\n kv: KVStorage;\n vector: VectorStorage;\n graph: GraphStorage;\n}\n\n/** Wrap storage with namespace isolation for multi-tenancy. */\nexport function withNamespace(storage: StorageSet, namespace: string): StorageSet {\n return {\n kv: new NamespacedKVStorage(storage.kv, namespace),\n vector: new NamespacedVectorStorage(storage.vector, namespace),\n graph: new NamespacedGraphStorage(storage.graph, namespace),\n };\n}\n","import type { Schema } from './schema.js';\n\n/**\n * Build the standard entity extraction prompt used by all LLM providers.\n */\nexport function buildExtractionPrompt(\n content: string,\n knownEntities: string[],\n schema: Schema,\n): string {\n const entityTypes = schema.entityTypes.join(', ');\n const relationTypes = schema.relationTypes.join(', ');\n const knownEntitiesList =\n knownEntities.length > 0 ? `\\n\\nKnown entities to reference: ${knownEntities.join(', ')}` : '';\n\n const entityFieldsDef =\n Object.keys(schema.entityFields).length > 0\n ? `\\n\\nEntity custom fields: ${JSON.stringify(schema.entityFields)}`\n : '';\n const relationFieldsDef =\n Object.keys(schema.relationFields).length > 0\n ? `\\n\\nRelation custom fields: ${JSON.stringify(schema.relationFields)}`\n : '';\n\n const fieldsInstruction =\n entityFieldsDef || relationFieldsDef\n ? '\\nInclude a \"fields\" object in each entity/relation with the custom field values when applicable.'\n : '';\n\n return `Extract entities and relations from the following content.\n\nEntity types: ${entityTypes}\nRelation types: ${relationTypes}${knownEntitiesList}${entityFieldsDef}${relationFieldsDef}\n\nContent:\n${content}\n\nReturn a JSON object with this structure:\n{\n \"entities\": [\n {\n \"name\": \"entity name\",\n \"type\": \"entity type from the list above, or 'Other' if not matching\",\n \"description\": \"brief description of the entity\"${entityFieldsDef ? ',\\n \"fields\": {}' : ''}\n }\n ],\n \"relations\": [\n {\n \"source\": \"source entity name\",\n \"target\": \"target entity name\",\n \"type\": \"relation type from the list above\",\n \"description\": \"description of the relationship\",\n \"keywords\": [\"keyword1\", \"keyword2\"]${relationFieldsDef ? ',\\n \"fields\": {}' : ''}\n }\n ]\n}\n\nFocus on technical entities and their relationships. Be precise and avoid duplicates.${fieldsInstruction}`;\n}\n","/**\n * Schema definition for FlowRAG\n */\n\nimport { z } from 'zod';\n\n/** Custom field definition */\nexport interface FieldDefinition {\n type: 'string' | 'enum';\n values?: string[];\n default?: string;\n filterable?: boolean;\n}\n\n/** Schema configuration input */\nexport interface SchemaConfig<\n E extends readonly string[] = readonly string[],\n R extends readonly string[] = readonly string[],\n> {\n entityTypes: E;\n relationTypes: R;\n documentFields?: Record<string, FieldDefinition>;\n entityFields?: Record<string, FieldDefinition>;\n relationFields?: Record<string, FieldDefinition>;\n}\n\n/** Resolved schema with validation */\nexport interface Schema<\n E extends readonly string[] = readonly string[],\n R extends readonly string[] = readonly string[],\n> {\n entityTypes: E;\n relationTypes: R;\n documentFields: Record<string, FieldDefinition>;\n entityFields: Record<string, FieldDefinition>;\n relationFields: Record<string, FieldDefinition>;\n isValidEntityType: (type: string) => boolean;\n isValidRelationType: (type: string) => boolean;\n normalizeEntityType: (type: string) => E[number] | 'Other';\n normalizeRelationType: (type: string) => R[number] | 'Other';\n}\n\nconst schemaConfigSchema = z.object({\n entityTypes: z.array(z.string()).min(1),\n relationTypes: z.array(z.string()).min(1),\n});\n\n/**\n * Define a schema for entity and relation types.\n * Types are suggestions - if LLM extracts a type not in the list, it falls back to 'Other'.\n */\nexport function defineSchema<const E extends readonly string[], const R extends readonly string[]>(\n config: SchemaConfig<E, R>,\n): Schema<E, R> {\n schemaConfigSchema.parse(config);\n\n const entitySet = new Set<string>(config.entityTypes);\n const relationSet = new Set<string>(config.relationTypes);\n\n return {\n entityTypes: config.entityTypes,\n relationTypes: config.relationTypes,\n documentFields: config.documentFields ?? {},\n entityFields: config.entityFields ?? {},\n relationFields: config.relationFields ?? {},\n isValidEntityType: (type: string) => entitySet.has(type),\n isValidRelationType: (type: string) => relationSet.has(type),\n normalizeEntityType: (type: string) => (entitySet.has(type) ? (type as E[number]) : 'Other'),\n normalizeRelationType: (type: string) =>\n relationSet.has(type) ? (type as R[number]) : 'Other',\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/namespace.ts","../src/prompt.ts","../src/retry.ts","../src/schema.ts"],"sourcesContent":["/**\n * Multi-tenancy namespace wrappers for storage isolation.\n */\n\nimport type { GraphStorage, KVStorage, VectorStorage } from './interfaces/storage.js';\nimport type {\n Entity,\n EntityFilter,\n Id,\n Relation,\n RelationDirection,\n SearchResult,\n VectorFilter,\n VectorRecord,\n} from './types.js';\n\nfunction pfx(ns: string, id: string): string {\n return `${ns}:${id}`;\n}\n\nfunction unpfx(ns: string, id: string): string {\n return id.slice(ns.length + 1);\n}\n\nclass NamespacedKVStorage implements KVStorage {\n constructor(\n private inner: KVStorage,\n private ns: string,\n ) {}\n\n get<T>(key: string): Promise<T | null> {\n return this.inner.get<T>(pfx(this.ns, key));\n }\n\n set<T>(key: string, value: T): Promise<void> {\n return this.inner.set(pfx(this.ns, key), value);\n }\n\n delete(key: string): Promise<void> {\n return this.inner.delete(pfx(this.ns, key));\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys = await this.inner.list(pfx(this.ns, prefix ?? ''));\n return keys.map((k) => unpfx(this.ns, k));\n }\n\n async clear(): Promise<void> {\n const keys = await this.inner.list(`${this.ns}:`);\n await Promise.all(keys.map((k) => this.inner.delete(k)));\n }\n}\n\nclass NamespacedVectorStorage implements VectorStorage {\n constructor(\n private inner: VectorStorage,\n private ns: string,\n ) {}\n\n upsert(records: VectorRecord[]): Promise<void> {\n return this.inner.upsert(\n records.map((r) => ({\n ...r,\n id: pfx(this.ns, r.id),\n metadata: { ...r.metadata, __ns: this.ns },\n })),\n );\n }\n\n async search(vector: number[], limit: number, filter?: VectorFilter): Promise<SearchResult[]> {\n const results = await this.inner.search(vector, limit, { ...filter, __ns: this.ns });\n return results.map((r) => ({\n ...r,\n id: unpfx(this.ns, r.id),\n metadata: { ...r.metadata, __ns: undefined },\n }));\n }\n\n delete(ids: Id[]): Promise<void> {\n return this.inner.delete(ids.map((id) => pfx(this.ns, id)));\n }\n\n count(): Promise<number> {\n return this.inner.count();\n }\n}\n\nclass NamespacedGraphStorage implements GraphStorage {\n constructor(\n private inner: GraphStorage,\n private ns: string,\n ) {}\n\n addEntity(entity: Entity): Promise<void> {\n return this.inner.addEntity({\n ...entity,\n id: pfx(this.ns, entity.id),\n sourceChunkIds: entity.sourceChunkIds.map((id) => pfx(this.ns, id)),\n });\n }\n\n addRelation(relation: Relation): Promise<void> {\n return this.inner.addRelation({\n ...relation,\n id: pfx(this.ns, relation.id),\n sourceId: pfx(this.ns, relation.sourceId),\n targetId: pfx(this.ns, relation.targetId),\n sourceChunkIds: relation.sourceChunkIds.map((id) => pfx(this.ns, id)),\n });\n }\n\n async getEntity(id: Id): Promise<Entity | null> {\n const e = await this.inner.getEntity(pfx(this.ns, id));\n return e ? this.unpfxEntity(e) : null;\n }\n\n async getEntities(filter?: EntityFilter): Promise<Entity[]> {\n const all = await this.inner.getEntities(filter);\n return all.filter((e) => e.id.startsWith(`${this.ns}:`)).map((e) => this.unpfxEntity(e));\n }\n\n async getRelations(entityId: Id, direction?: RelationDirection): Promise<Relation[]> {\n const rels = await this.inner.getRelations(pfx(this.ns, entityId), direction);\n return rels.map((r) => this.unpfxRelation(r));\n }\n\n async traverse(startId: Id, depth: number, relationTypes?: string[]): Promise<Entity[]> {\n const entities = await this.inner.traverse(pfx(this.ns, startId), depth, relationTypes);\n return entities.map((e) => this.unpfxEntity(e));\n }\n\n async findPath(fromId: Id, toId: Id, maxDepth?: number): Promise<Relation[]> {\n const rels = await this.inner.findPath(pfx(this.ns, fromId), pfx(this.ns, toId), maxDepth);\n return rels.map((r) => this.unpfxRelation(r));\n }\n\n deleteEntity(id: Id): Promise<void> {\n return this.inner.deleteEntity(pfx(this.ns, id));\n }\n\n deleteRelation(id: Id): Promise<void> {\n return this.inner.deleteRelation(pfx(this.ns, id));\n }\n\n private unpfxEntity(e: Entity): Entity {\n return {\n ...e,\n id: unpfx(this.ns, e.id),\n sourceChunkIds: e.sourceChunkIds.map((id) => unpfx(this.ns, id)),\n };\n }\n\n private unpfxRelation(r: Relation): Relation {\n return {\n ...r,\n id: unpfx(this.ns, r.id),\n sourceId: unpfx(this.ns, r.sourceId),\n targetId: unpfx(this.ns, r.targetId),\n sourceChunkIds: r.sourceChunkIds.map((id) => unpfx(this.ns, id)),\n };\n }\n}\n\n/** Storage set for FlowRAG */\nexport interface StorageSet {\n kv: KVStorage;\n vector: VectorStorage;\n graph: GraphStorage;\n}\n\n/** Wrap storage with namespace isolation for multi-tenancy. */\nexport function withNamespace(storage: StorageSet, namespace: string): StorageSet {\n return {\n kv: new NamespacedKVStorage(storage.kv, namespace),\n vector: new NamespacedVectorStorage(storage.vector, namespace),\n graph: new NamespacedGraphStorage(storage.graph, namespace),\n };\n}\n","import type { Schema } from './schema.js';\n\n/**\n * Build the standard entity extraction prompt used by all LLM providers.\n */\nexport function buildExtractionPrompt(\n content: string,\n knownEntities: string[],\n schema: Schema,\n): string {\n const entityTypes = schema.entityTypes.join(', ');\n const relationTypes = schema.relationTypes.join(', ');\n const knownEntitiesList =\n knownEntities.length > 0 ? `\\n\\nKnown entities to reference: ${knownEntities.join(', ')}` : '';\n\n const entityFieldsDef =\n Object.keys(schema.entityFields).length > 0\n ? `\\n\\nEntity custom fields: ${JSON.stringify(schema.entityFields)}`\n : '';\n const relationFieldsDef =\n Object.keys(schema.relationFields).length > 0\n ? `\\n\\nRelation custom fields: ${JSON.stringify(schema.relationFields)}`\n : '';\n\n const fieldsInstruction =\n entityFieldsDef || relationFieldsDef\n ? '\\nInclude a \"fields\" object in each entity/relation with the custom field values when applicable.'\n : '';\n\n return `Extract entities and relations from the following content.\n\nEntity types: ${entityTypes}\nRelation types: ${relationTypes}${knownEntitiesList}${entityFieldsDef}${relationFieldsDef}\n\nContent:\n${content}\n\nReturn a JSON object with this structure:\n{\n \"entities\": [\n {\n \"name\": \"entity name\",\n \"type\": \"entity type from the list above, or 'Other' if not matching\",\n \"description\": \"brief description of the entity\"${entityFieldsDef ? ',\\n \"fields\": {}' : ''}\n }\n ],\n \"relations\": [\n {\n \"source\": \"source entity name\",\n \"target\": \"target entity name\",\n \"type\": \"relation type from the list above\",\n \"description\": \"description of the relationship\",\n \"keywords\": [\"keyword1\", \"keyword2\"]${relationFieldsDef ? ',\\n \"fields\": {}' : ''}\n }\n ]\n}\n\nFocus on technical entities and their relationships. Be precise and avoid duplicates.${fieldsInstruction}`;\n}\n","export interface RetryOptions {\n retries?: number;\n backoff?: number;\n maxBackoff?: number;\n retryOn?: (error: unknown) => boolean;\n}\n\nconst DEFAULT_RETRIES = 3;\nconst DEFAULT_BACKOFF = 1000;\nconst DEFAULT_MAX_BACKOFF = 30000;\n\nfunction isTransientError(error: unknown): boolean {\n let current: unknown = error;\n while (current instanceof Error) {\n const msg = current.message.toLowerCase();\n if (msg.includes('timeout') || msg.includes('econnreset') || msg.includes('econnrefused'))\n return true;\n\n // HTTP status codes in error messages or properties\n const status =\n (current as { status?: number }).status ?? (current as { statusCode?: number }).statusCode;\n if (status === 429 || status === 500 || status === 502 || status === 503 || status === 504)\n return true;\n\n current = current.cause;\n }\n return false;\n}\n\nexport async function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T> {\n const retries = options?.retries ?? DEFAULT_RETRIES;\n const backoff = options?.backoff ?? DEFAULT_BACKOFF;\n const maxBackoff = options?.maxBackoff ?? DEFAULT_MAX_BACKOFF;\n const shouldRetry = options?.retryOn ?? isTransientError;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (attempt === retries || !shouldRetry(error)) throw error;\n\n const delay = Math.min(backoff * 2 ** attempt, maxBackoff);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n","/**\n * Schema definition for FlowRAG\n */\n\nimport { z } from 'zod';\n\n/** Custom field definition */\nexport interface FieldDefinition {\n type: 'string' | 'enum';\n values?: string[];\n default?: string;\n filterable?: boolean;\n}\n\n/** Schema configuration input */\nexport interface SchemaConfig<\n E extends readonly string[] = readonly string[],\n R extends readonly string[] = readonly string[],\n> {\n entityTypes: E;\n relationTypes: R;\n documentFields?: Record<string, FieldDefinition>;\n entityFields?: Record<string, FieldDefinition>;\n relationFields?: Record<string, FieldDefinition>;\n}\n\n/** Resolved schema with validation */\nexport interface Schema<\n E extends readonly string[] = readonly string[],\n R extends readonly string[] = readonly string[],\n> {\n entityTypes: E;\n relationTypes: R;\n documentFields: Record<string, FieldDefinition>;\n entityFields: Record<string, FieldDefinition>;\n relationFields: Record<string, FieldDefinition>;\n isValidEntityType: (type: string) => boolean;\n isValidRelationType: (type: string) => boolean;\n normalizeEntityType: (type: string) => E[number] | 'Other';\n normalizeRelationType: (type: string) => R[number] | 'Other';\n}\n\nconst schemaConfigSchema = z.object({\n entityTypes: z.array(z.string()).min(1),\n relationTypes: z.array(z.string()).min(1),\n});\n\n/**\n * Define a schema for entity and relation types.\n * Types are suggestions - if LLM extracts a type not in the list, it falls back to 'Other'.\n */\nexport function defineSchema<const E extends readonly string[], const R extends readonly string[]>(\n config: SchemaConfig<E, R>,\n): Schema<E, R> {\n schemaConfigSchema.parse(config);\n\n const entitySet = new Set<string>(config.entityTypes);\n const relationSet = new Set<string>(config.relationTypes);\n\n return {\n entityTypes: config.entityTypes,\n relationTypes: config.relationTypes,\n documentFields: config.documentFields ?? {},\n entityFields: config.entityFields ?? {},\n relationFields: config.relationFields ?? {},\n isValidEntityType: (type: string) => entitySet.has(type),\n isValidRelationType: (type: string) => relationSet.has(type),\n normalizeEntityType: (type: string) => (entitySet.has(type) ? (type as E[number]) : 'Other'),\n normalizeRelationType: (type: string) =>\n relationSet.has(type) ? (type as R[number]) : 'Other',\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowrag/core",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "📐 The heart of FlowRAG. Defines all TypeScript interfaces (Storage, Embedder, LLMExtractor), the Zod-based schema system for defining entity/relation types, and the orchestration pipeline that coordinates indexing and querying. This package contains only contracts and types, no concrete implementations.",
5
5
  "keywords": [
6
6
  "interfaces",