ai-database 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/CHANGELOG.md +47 -1
  2. package/README.md +1063 -186
  3. package/dist/actions.d.ts +2 -2
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +1 -1
  6. package/dist/actions.js.map +1 -1
  7. package/dist/ai-promise-db.d.ts +52 -23
  8. package/dist/ai-promise-db.d.ts.map +1 -1
  9. package/dist/ai-promise-db.js +185 -164
  10. package/dist/ai-promise-db.js.map +1 -1
  11. package/dist/authorization.d.ts.map +1 -1
  12. package/dist/authorization.js +38 -30
  13. package/dist/authorization.js.map +1 -1
  14. package/dist/cascade-orchestrator.d.ts +404 -0
  15. package/dist/cascade-orchestrator.d.ts.map +1 -0
  16. package/dist/cascade-orchestrator.js +828 -0
  17. package/dist/cascade-orchestrator.js.map +1 -0
  18. package/dist/cascade-write-strategy.d.ts +584 -0
  19. package/dist/cascade-write-strategy.d.ts.map +1 -0
  20. package/dist/cascade-write-strategy.js +590 -0
  21. package/dist/cascade-write-strategy.js.map +1 -0
  22. package/dist/ch-adapter.d.ts +358 -0
  23. package/dist/ch-adapter.d.ts.map +1 -0
  24. package/dist/ch-adapter.js +929 -0
  25. package/dist/ch-adapter.js.map +1 -0
  26. package/dist/client/index.d.ts +42 -0
  27. package/dist/client/index.d.ts.map +1 -0
  28. package/dist/client/index.js +43 -0
  29. package/dist/client/index.js.map +1 -0
  30. package/dist/client.d.ts +266 -0
  31. package/dist/client.d.ts.map +1 -0
  32. package/dist/client.js +81 -0
  33. package/dist/client.js.map +1 -0
  34. package/dist/constants.d.ts +64 -1
  35. package/dist/constants.d.ts.map +1 -1
  36. package/dist/constants.js +52 -2
  37. package/dist/constants.js.map +1 -1
  38. package/dist/dataloader.d.ts +99 -0
  39. package/dist/dataloader.d.ts.map +1 -0
  40. package/dist/dataloader.js +225 -0
  41. package/dist/dataloader.js.map +1 -0
  42. package/dist/db-provider-port.d.ts +501 -0
  43. package/dist/db-provider-port.d.ts.map +1 -0
  44. package/dist/db-provider-port.js +113 -0
  45. package/dist/db-provider-port.js.map +1 -0
  46. package/dist/digital-objects-provider.d.ts +49 -0
  47. package/dist/digital-objects-provider.d.ts.map +1 -0
  48. package/dist/digital-objects-provider.js +55 -0
  49. package/dist/digital-objects-provider.js.map +1 -0
  50. package/dist/do-sqlite-adapter.d.ts +402 -0
  51. package/dist/do-sqlite-adapter.d.ts.map +1 -0
  52. package/dist/do-sqlite-adapter.js +745 -0
  53. package/dist/do-sqlite-adapter.js.map +1 -0
  54. package/dist/docs-rels/custom-types.d.ts +134 -0
  55. package/dist/docs-rels/custom-types.d.ts.map +1 -0
  56. package/dist/docs-rels/custom-types.js +70 -0
  57. package/dist/docs-rels/custom-types.js.map +1 -0
  58. package/dist/docs-rels/index.d.ts +16 -0
  59. package/dist/docs-rels/index.d.ts.map +1 -0
  60. package/dist/docs-rels/index.js +16 -0
  61. package/dist/docs-rels/index.js.map +1 -0
  62. package/dist/docs-rels/migrations/index.d.ts +30 -0
  63. package/dist/docs-rels/migrations/index.d.ts.map +1 -0
  64. package/dist/docs-rels/migrations/index.js +128 -0
  65. package/dist/docs-rels/migrations/index.js.map +1 -0
  66. package/dist/docs-rels/schema.d.ts +2961 -0
  67. package/dist/docs-rels/schema.d.ts.map +1 -0
  68. package/dist/docs-rels/schema.js +244 -0
  69. package/dist/docs-rels/schema.js.map +1 -0
  70. package/dist/durable-clickhouse.d.ts.map +1 -1
  71. package/dist/durable-clickhouse.js +16 -13
  72. package/dist/durable-clickhouse.js.map +1 -1
  73. package/dist/durable-promise.d.ts.map +1 -1
  74. package/dist/durable-promise.js +34 -15
  75. package/dist/durable-promise.js.map +1 -1
  76. package/dist/errors.d.ts +127 -0
  77. package/dist/errors.d.ts.map +1 -0
  78. package/dist/errors.js +210 -0
  79. package/dist/errors.js.map +1 -0
  80. package/dist/eventbridge.d.ts +117 -0
  81. package/dist/eventbridge.d.ts.map +1 -0
  82. package/dist/eventbridge.js +238 -0
  83. package/dist/eventbridge.js.map +1 -0
  84. package/dist/events.d.ts +2 -2
  85. package/dist/events.d.ts.map +1 -1
  86. package/dist/events.js +1 -1
  87. package/dist/events.js.map +1 -1
  88. package/dist/execution-queue.d.ts.map +1 -1
  89. package/dist/execution-queue.js +4 -5
  90. package/dist/execution-queue.js.map +1 -1
  91. package/dist/index.d.ts +37 -8
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +112 -6
  94. package/dist/index.js.map +1 -1
  95. package/dist/linguistic.d.ts +3 -108
  96. package/dist/linguistic.d.ts.map +1 -1
  97. package/dist/linguistic.js +3 -372
  98. package/dist/linguistic.js.map +1 -1
  99. package/dist/logger.d.ts +132 -0
  100. package/dist/logger.d.ts.map +1 -0
  101. package/dist/logger.js +137 -0
  102. package/dist/logger.js.map +1 -0
  103. package/dist/memory-provider.d.ts +129 -0
  104. package/dist/memory-provider.d.ts.map +1 -1
  105. package/dist/memory-provider.js +592 -257
  106. package/dist/memory-provider.js.map +1 -1
  107. package/dist/pg-adapter.d.ts +424 -0
  108. package/dist/pg-adapter.d.ts.map +1 -0
  109. package/dist/pg-adapter.js +921 -0
  110. package/dist/pg-adapter.js.map +1 -0
  111. package/dist/pipelines-iceberg-emitter.d.ts +327 -0
  112. package/dist/pipelines-iceberg-emitter.d.ts.map +1 -0
  113. package/dist/pipelines-iceberg-emitter.js +351 -0
  114. package/dist/pipelines-iceberg-emitter.js.map +1 -0
  115. package/dist/provider-capabilities.d.ts +146 -0
  116. package/dist/provider-capabilities.d.ts.map +1 -0
  117. package/dist/provider-capabilities.js +214 -0
  118. package/dist/provider-capabilities.js.map +1 -0
  119. package/dist/rdb-provider-adapter.d.ts +195 -0
  120. package/dist/rdb-provider-adapter.d.ts.map +1 -0
  121. package/dist/rdb-provider-adapter.js +291 -0
  122. package/dist/rdb-provider-adapter.js.map +1 -0
  123. package/dist/schema/cascade.d.ts +49 -10
  124. package/dist/schema/cascade.d.ts.map +1 -1
  125. package/dist/schema/cascade.js +491 -273
  126. package/dist/schema/cascade.js.map +1 -1
  127. package/dist/schema/definition-caches.d.ts +24 -0
  128. package/dist/schema/definition-caches.d.ts.map +1 -0
  129. package/dist/schema/definition-caches.js +26 -0
  130. package/dist/schema/definition-caches.js.map +1 -0
  131. package/dist/schema/dependency-graph.d.ts +45 -0
  132. package/dist/schema/dependency-graph.d.ts.map +1 -0
  133. package/dist/schema/dependency-graph.js +47 -0
  134. package/dist/schema/dependency-graph.js.map +1 -0
  135. package/dist/schema/diff.d.ts +103 -0
  136. package/dist/schema/diff.d.ts.map +1 -0
  137. package/dist/schema/diff.js +329 -0
  138. package/dist/schema/diff.js.map +1 -0
  139. package/dist/schema/entity-operations.d.ts +99 -0
  140. package/dist/schema/entity-operations.d.ts.map +1 -0
  141. package/dist/schema/entity-operations.js +818 -0
  142. package/dist/schema/entity-operations.js.map +1 -0
  143. package/dist/schema/generation-context.d.ts +202 -0
  144. package/dist/schema/generation-context.d.ts.map +1 -0
  145. package/dist/schema/generation-context.js +393 -0
  146. package/dist/schema/generation-context.js.map +1 -0
  147. package/dist/schema/index.d.ts +32 -34
  148. package/dist/schema/index.d.ts.map +1 -1
  149. package/dist/schema/index.js +462 -519
  150. package/dist/schema/index.js.map +1 -1
  151. package/dist/schema/migration.d.ts +205 -0
  152. package/dist/schema/migration.d.ts.map +1 -0
  153. package/dist/schema/migration.js +327 -0
  154. package/dist/schema/migration.js.map +1 -0
  155. package/dist/schema/nl-query-generator.d.ts +68 -0
  156. package/dist/schema/nl-query-generator.d.ts.map +1 -0
  157. package/dist/schema/nl-query-generator.js +362 -0
  158. package/dist/schema/nl-query-generator.js.map +1 -0
  159. package/dist/schema/nl-query.d.ts +65 -0
  160. package/dist/schema/nl-query.d.ts.map +1 -0
  161. package/dist/schema/nl-query.js +178 -0
  162. package/dist/schema/nl-query.js.map +1 -0
  163. package/dist/schema/parse.d.ts.map +1 -1
  164. package/dist/schema/parse.js +152 -89
  165. package/dist/schema/parse.js.map +1 -1
  166. package/dist/schema/provider.d.ts +38 -0
  167. package/dist/schema/provider.d.ts.map +1 -1
  168. package/dist/schema/provider.js +15 -7
  169. package/dist/schema/provider.js.map +1 -1
  170. package/dist/schema/resolve.d.ts +46 -5
  171. package/dist/schema/resolve.d.ts.map +1 -1
  172. package/dist/schema/resolve.js +334 -117
  173. package/dist/schema/resolve.js.map +1 -1
  174. package/dist/schema/search-utils.d.ts +76 -0
  175. package/dist/schema/search-utils.d.ts.map +1 -0
  176. package/dist/schema/search-utils.js +86 -0
  177. package/dist/schema/search-utils.js.map +1 -0
  178. package/dist/schema/seed.d.ts +53 -0
  179. package/dist/schema/seed.d.ts.map +1 -0
  180. package/dist/schema/seed.js +94 -0
  181. package/dist/schema/seed.js.map +1 -0
  182. package/dist/schema/semantic.d.ts +11 -0
  183. package/dist/schema/semantic.d.ts.map +1 -1
  184. package/dist/schema/semantic.js +262 -68
  185. package/dist/schema/semantic.js.map +1 -1
  186. package/dist/schema/sub-apis.d.ts +52 -0
  187. package/dist/schema/sub-apis.d.ts.map +1 -0
  188. package/dist/schema/sub-apis.js +216 -0
  189. package/dist/schema/sub-apis.js.map +1 -0
  190. package/dist/schema/system-entities.d.ts +42 -0
  191. package/dist/schema/system-entities.d.ts.map +1 -0
  192. package/dist/schema/system-entities.js +101 -0
  193. package/dist/schema/system-entities.js.map +1 -0
  194. package/dist/schema/types.d.ts +91 -9
  195. package/dist/schema/types.d.ts.map +1 -1
  196. package/dist/schema/union-fallback.d.ts +219 -0
  197. package/dist/schema/union-fallback.d.ts.map +1 -0
  198. package/dist/schema/union-fallback.js +331 -0
  199. package/dist/schema/union-fallback.js.map +1 -0
  200. package/dist/schema/value-generators/ai.d.ts +54 -0
  201. package/dist/schema/value-generators/ai.d.ts.map +1 -0
  202. package/dist/schema/value-generators/ai.js +136 -0
  203. package/dist/schema/value-generators/ai.js.map +1 -0
  204. package/dist/schema/value-generators/index.d.ts +126 -0
  205. package/dist/schema/value-generators/index.d.ts.map +1 -0
  206. package/dist/schema/value-generators/index.js +219 -0
  207. package/dist/schema/value-generators/index.js.map +1 -0
  208. package/dist/schema/value-generators/placeholder.d.ts +52 -0
  209. package/dist/schema/value-generators/placeholder.d.ts.map +1 -0
  210. package/dist/schema/value-generators/placeholder.js +328 -0
  211. package/dist/schema/value-generators/placeholder.js.map +1 -0
  212. package/dist/schema/value-generators/types.d.ts +116 -0
  213. package/dist/schema/value-generators/types.d.ts.map +1 -0
  214. package/dist/schema/value-generators/types.js +11 -0
  215. package/dist/schema/value-generators/types.js.map +1 -0
  216. package/dist/schema/verb-derivation.d.ts +167 -0
  217. package/dist/schema/verb-derivation.d.ts.map +1 -0
  218. package/dist/schema/verb-derivation.js +281 -0
  219. package/dist/schema/verb-derivation.js.map +1 -0
  220. package/dist/schema/version.d.ts +111 -0
  221. package/dist/schema/version.d.ts.map +1 -0
  222. package/dist/schema/version.js +190 -0
  223. package/dist/schema/version.js.map +1 -0
  224. package/dist/schema.d.ts +1095 -23
  225. package/dist/schema.d.ts.map +1 -1
  226. package/dist/schema.js +2854 -38
  227. package/dist/schema.js.map +1 -1
  228. package/dist/semantic-vectors.d.ts +39 -0
  229. package/dist/semantic-vectors.d.ts.map +1 -0
  230. package/dist/semantic-vectors.js +334 -0
  231. package/dist/semantic-vectors.js.map +1 -0
  232. package/dist/semantic.d.ts +29 -1
  233. package/dist/semantic.d.ts.map +1 -1
  234. package/dist/semantic.js +26 -16
  235. package/dist/semantic.js.map +1 -1
  236. package/dist/telemetry.d.ts +128 -0
  237. package/dist/telemetry.d.ts.map +1 -0
  238. package/dist/telemetry.js +305 -0
  239. package/dist/telemetry.js.map +1 -0
  240. package/dist/tests.d.ts.map +1 -1
  241. package/dist/tests.js +30 -22
  242. package/dist/tests.js.map +1 -1
  243. package/dist/type-guards.d.ts +212 -0
  244. package/dist/type-guards.d.ts.map +1 -0
  245. package/dist/type-guards.js +318 -0
  246. package/dist/type-guards.js.map +1 -0
  247. package/dist/types.d.ts +33 -245
  248. package/dist/types.d.ts.map +1 -1
  249. package/dist/types.js +62 -72
  250. package/dist/types.js.map +1 -1
  251. package/dist/validation.d.ts +165 -0
  252. package/dist/validation.d.ts.map +1 -0
  253. package/dist/validation.js +639 -0
  254. package/dist/validation.js.map +1 -0
  255. package/dist/worker/db-provider.d.ts +168 -0
  256. package/dist/worker/db-provider.d.ts.map +1 -0
  257. package/dist/worker/db-provider.js +277 -0
  258. package/dist/worker/db-provider.js.map +1 -0
  259. package/dist/worker/index.d.ts +35 -0
  260. package/dist/worker/index.d.ts.map +1 -0
  261. package/dist/worker/index.js +37 -0
  262. package/dist/worker/index.js.map +1 -0
  263. package/dist/worker.d.ts +779 -0
  264. package/dist/worker.d.ts.map +1 -0
  265. package/dist/worker.js +2786 -0
  266. package/dist/worker.js.map +1 -0
  267. package/package.json +38 -8
  268. package/src/docs-rels/migrations/0001-init.sql +125 -0
@@ -30,23 +30,55 @@
30
30
  *
31
31
  * @packageDocumentation
32
32
  */
33
- import { DBPromise, wrapEntityOperations, setSchemaRelationInfo } from '../ai-promise-db.js';
33
+ import { DBPromise, wrapEntityOperations, setSchemaRelationInfo, } from '../ai-promise-db.js';
34
+ import { logError } from '../logger.js';
34
35
  // Re-export parse functions
35
36
  export { parseOperator, parseField, parseSchema, isPrimitiveType } from './parse.js';
36
- export { setProvider, resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, } from './provider.js';
37
+ // Re-export seed functions
38
+ export { loadSeedData, fetchSeedData, parseDelimitedData, mapSeedDataToRecords } from './seed.js';
39
+ export { setProvider, resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, hasTransactionSupport, } from './provider.js';
40
+ // Import resolve functions used internally
41
+ import { isPromptField } from './resolve.js';
37
42
  // Re-export resolve functions
38
- export { isEntityId, inferTypeFromField, resolveContextPath, resolveInstructions, prefetchContext, isPromptField, resolveNestedPending, resolveReferenceSpec, hydrateEntity, } from './resolve.js';
43
+ export { isEntityId, inferTypeFromField, resolveContextPath, resolveInstructions, prefetchContext, prefetchContextPaths, isPromptField, resolveNestedPending, resolveReferenceSpec, hydrateEntity, } from './resolve.js';
39
44
  // Re-export cascade functions
40
- export { generateContextAwareValue, generateAIFields, generateEntity, resolveForwardExact, generateNaturalLanguageContent, } from './cascade.js';
45
+ export { generateContextAwareValue, generateAIFields, generateEntity, resolveForwardExact, generateNaturalLanguageContent,
46
+ // AI generation configuration
47
+ configureAIGeneration, getAIGenerationConfig,
48
+ // Value generator configuration
49
+ setValueGenerator, getValueGenerator, } from './cascade.js';
41
50
  // Re-export semantic functions
42
51
  export { resolveBackwardFuzzy, resolveForwardFuzzy } from './semantic.js';
52
+ // Re-export NL query generator functions
53
+ export { createDefaultNLQueryGenerator, matchesFilter, applyFilters } from './nl-query-generator.js';
54
+ // Re-export entity operations
55
+ export { createEntityOperations, createEdgeEntityOperations, createNounEntityOperations, createVerbEntityOperations, } from './entity-operations.js';
56
+ // Re-export NL query functions
57
+ export { buildNLQueryContext, executeNLQuery, createNLQueryFn, setNLQueryGenerator, getNLQueryGenerator, } from './nl-query.js';
58
+ // Re-export dependency graph functions
59
+ export { buildDependencyGraph, topologicalSort, detectCycles, getParallelGroups, getAllDependencies, hasCycles, visualizeGraph, CircularDependencyError, PRIMITIVE_TYPES, } from './dependency-graph.js';
60
+ // Re-export union fallback functions
61
+ export { parseUnionTypes, parseUnionThresholds, searchUnionTypes, createProviderSearcher, } from './union-fallback.js';
62
+ // Re-export generation context
63
+ export { GenerationContext, createGenerationContext, ContextOverflowError, } from './generation-context.js';
64
+ // Re-export schema versioning functions
65
+ export { computeSchemaHash, getSchemaVersion, setSchemaVersion, hasSchemaChanged, } from './version.js';
66
+ // Re-export schema diff functions
67
+ export { diffSchemas, describeDiff, } from './diff.js';
68
+ // Re-export migration functions
69
+ export { defineMigration, runMigrations, getPendingMigrations, rollbackLastMigration, } from './migration.js';
70
+ // Re-export verb derivation functions
71
+ export { FORWARD_TO_REVERSE, BIDIRECTIONAL_PAIRS, deriveReverseVerb, fieldNameToVerb, isPassiveVerb, registerVerbPair, registerBidirectionalPair, registerFieldVerb, } from './verb-derivation.js';
43
72
  import { Verbs, parseUrl } from '../types.js';
44
73
  import { inferNoun, getTypeMeta, conjugate } from '../linguistic.js';
45
74
  import { parseSchema } from './parse.js';
46
75
  import { resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, } from './provider.js';
47
76
  import { hydrateEntity, resolveReferenceSpec } from './resolve.js';
48
- import { resolveForwardExact, generateAIFields, generateContextAwareValue, generateNaturalLanguageContent } from './cascade.js';
49
- import { resolveBackwardFuzzy, resolveForwardFuzzy } from './semantic.js';
77
+ import { resolveForwardExact, generateAIFields, generateContextAwareValue, generateNaturalLanguageContent, generateEntity, setValueGenerator, } from './cascade.js';
78
+ import { resolveBackwardFuzzy, resolveForwardFuzzy, getFuzzyThreshold } from './semantic.js';
79
+ // Import from extracted modules for use in DB() factory
80
+ import { createEntityOperations, createEdgeEntityOperations, createNounEntityOperations, createVerbEntityOperations, } from './entity-operations.js';
81
+ import { createNLQueryFn } from './nl-query.js';
50
82
  // =============================================================================
51
83
  // Noun/Verb Helpers
52
84
  // =============================================================================
@@ -224,439 +256,8 @@ function schemaToProperties(schema) {
224
256
  }
225
257
  return properties;
226
258
  }
227
- // =============================================================================
228
- // Natural Language Query Implementation
229
- // =============================================================================
230
- let nlQueryGenerator = null;
231
- /**
232
- * Set the AI generator for natural language queries
233
- */
234
- export function setNLQueryGenerator(generator) {
235
- nlQueryGenerator = generator;
236
- }
237
- function buildNLQueryContext(schema, targetType) {
238
- const types = [];
239
- for (const [name, entity] of schema.entities) {
240
- const fields = [];
241
- const relationships = [];
242
- for (const [fieldName, field] of entity.fields) {
243
- if (field.isRelation && field.relatedType) {
244
- relationships.push({
245
- name: fieldName,
246
- to: field.relatedType,
247
- cardinality: field.isArray ? 'many' : 'one',
248
- });
249
- }
250
- else {
251
- fields.push(fieldName);
252
- }
253
- }
254
- const meta = getTypeMeta(name);
255
- types.push({
256
- name,
257
- singular: meta.singular,
258
- plural: meta.plural,
259
- fields,
260
- relationships,
261
- });
262
- }
263
- return { types, targetType };
264
- }
265
- async function executeNLQuery(question, schema, targetType) {
266
- if (!nlQueryGenerator) {
267
- const provider = await resolveProvider();
268
- const results = [];
269
- // Simple heuristic for common "list all" patterns in fallback mode
270
- const lowerQuestion = question.toLowerCase().trim();
271
- const isListAllQuery = /^(show|list|get|find|display)\s+(all|every|the)?\s*/i.test(lowerQuestion) ||
272
- lowerQuestion === '' ||
273
- /\ball\b/i.test(lowerQuestion);
274
- if (targetType) {
275
- if (isListAllQuery) {
276
- // For "show all X" queries, just list everything
277
- const listResults = await provider.list(targetType);
278
- results.push(...listResults);
279
- }
280
- else {
281
- const searchResults = await provider.search(targetType, question);
282
- results.push(...searchResults);
283
- }
284
- }
285
- else {
286
- for (const [typeName] of schema.entities) {
287
- if (isListAllQuery) {
288
- const listResults = await provider.list(typeName);
289
- results.push(...listResults);
290
- }
291
- else {
292
- const searchResults = await provider.search(typeName, question);
293
- results.push(...searchResults);
294
- }
295
- }
296
- }
297
- return {
298
- interpretation: `Search for "${question}"`,
299
- confidence: 0.5,
300
- results,
301
- explanation: 'Fallback to keyword search (no AI generator configured)',
302
- };
303
- }
304
- const context = buildNLQueryContext(schema, targetType);
305
- const plan = await nlQueryGenerator(question, context);
306
- const provider = await resolveProvider();
307
- const results = [];
308
- for (const typeName of plan.types) {
309
- let typeResults;
310
- if (plan.search) {
311
- typeResults = await provider.search(typeName, plan.search, {
312
- where: plan.filters,
313
- });
314
- }
315
- else {
316
- typeResults = await provider.list(typeName, {
317
- where: plan.filters,
318
- });
319
- }
320
- results.push(...typeResults);
321
- }
322
- return {
323
- interpretation: plan.interpretation,
324
- confidence: plan.confidence,
325
- results,
326
- query: JSON.stringify({ types: plan.types, filters: plan.filters, search: plan.search }),
327
- };
328
- }
329
- function createNLQueryFn(schema, typeName) {
330
- return async (strings, ...values) => {
331
- const question = strings.reduce((acc, str, i) => {
332
- return acc + str + (values[i] !== undefined ? String(values[i]) : '');
333
- }, '');
334
- return executeNLQuery(question, schema, typeName);
335
- };
336
- }
337
- // =============================================================================
338
- // Edge Entity Operations
339
- // =============================================================================
340
- function createEdgeEntityOperations(schemaEdgeRecords, getProvider) {
341
- async function getRuntimeEdges() {
342
- try {
343
- const provider = await getProvider();
344
- const runtimeEdges = await provider.list('Edge');
345
- return runtimeEdges;
346
- }
347
- catch {
348
- return [];
349
- }
350
- }
351
- async function getAllEdges() {
352
- const runtimeEdges = await getRuntimeEdges();
353
- const runtimeEdgeKeys = new Set(runtimeEdges.map(e => `${e.from}:${e.name}`));
354
- const filteredSchemaEdges = schemaEdgeRecords.filter(e => {
355
- const key = `${e.from}:${e.name}`;
356
- const hasRuntimeVersion = runtimeEdgeKeys.has(key);
357
- if (hasRuntimeVersion && e.matchMode === 'fuzzy') {
358
- return false;
359
- }
360
- return !hasRuntimeVersion;
361
- });
362
- return [...filteredSchemaEdges, ...runtimeEdges];
363
- }
364
- return {
365
- async get(id) {
366
- const runtimeEdges = await getRuntimeEdges();
367
- const runtimeMatch = runtimeEdges.find(e => e.$id === id || `${e.from}:${e.name}` === id);
368
- if (runtimeMatch)
369
- return { ...runtimeMatch, $type: 'Edge' };
370
- return schemaEdgeRecords.find(e => `${e.from}:${e.name}` === id) ?? null;
371
- },
372
- async list(options) {
373
- let results = await getAllEdges();
374
- if (options?.where) {
375
- for (const [key, value] of Object.entries(options.where)) {
376
- results = results.filter(e => e[key] === value);
377
- }
378
- }
379
- return results.map(e => ({
380
- ...e,
381
- $id: e.$id || `${e.from}:${e.name}`,
382
- $type: 'Edge',
383
- }));
384
- },
385
- async find(where) {
386
- let results = await getAllEdges();
387
- for (const [key, value] of Object.entries(where)) {
388
- results = results.filter(e => e[key] === value);
389
- }
390
- return results.map(e => ({
391
- ...e,
392
- $id: e.$id || `${e.from}:${e.name}`,
393
- $type: 'Edge',
394
- }));
395
- },
396
- async search(query) {
397
- const allEdges = await getAllEdges();
398
- const queryLower = query.toLowerCase();
399
- return allEdges
400
- .filter(e => String(e.from).toLowerCase().includes(queryLower) ||
401
- String(e.name).toLowerCase().includes(queryLower) ||
402
- String(e.to).toLowerCase().includes(queryLower))
403
- .map(e => ({
404
- ...e,
405
- $id: e.$id || `${e.from}:${e.name}`,
406
- $type: 'Edge',
407
- }));
408
- },
409
- async create() {
410
- throw new Error('Cannot manually create Edge records - they are auto-generated');
411
- },
412
- async update() {
413
- throw new Error('Cannot manually update Edge records - they are auto-generated');
414
- },
415
- async upsert() {
416
- throw new Error('Cannot manually upsert Edge records - they are auto-generated');
417
- },
418
- async delete() {
419
- throw new Error('Cannot manually delete Edge records - they are auto-generated');
420
- },
421
- async forEach(optionsOrCallback, maybeCallback) {
422
- const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
423
- const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
424
- const items = await this.list(options);
425
- for (const item of items) {
426
- await callback(item);
427
- }
428
- },
429
- async semanticSearch() {
430
- return [];
431
- },
432
- async hybridSearch() {
433
- return [];
434
- },
435
- };
436
- }
437
- // =============================================================================
438
- // Entity Operations Factory
439
- // =============================================================================
440
- function createEntityOperations(typeName, entity, schema) {
441
- return {
442
- async get(id) {
443
- const provider = await resolveProvider();
444
- const result = await provider.get(typeName, id);
445
- if (!result)
446
- return null;
447
- return hydrateEntity(result, entity, schema, resolveProvider);
448
- },
449
- async list(options) {
450
- const provider = await resolveProvider();
451
- const results = await provider.list(typeName, options);
452
- return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
453
- },
454
- async find(where) {
455
- const provider = await resolveProvider();
456
- const results = await provider.list(typeName, {
457
- where: where,
458
- });
459
- return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
460
- },
461
- async search(query, options) {
462
- const provider = await resolveProvider();
463
- const results = await provider.search(typeName, query, options);
464
- return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
465
- },
466
- async create(idOrData, maybeData) {
467
- const provider = await resolveProvider();
468
- const providedId = typeof idOrData === 'string' ? idOrData : undefined;
469
- const data = typeof idOrData === 'string'
470
- ? maybeData
471
- : idOrData;
472
- const entityId = providedId || crypto.randomUUID();
473
- const { data: resolvedData, pendingRelations } = await resolveForwardExact(typeName, data, entity, schema, provider, entityId);
474
- const { data: fuzzyResolvedData, pendingRelations: fuzzyPendingRelations } = await resolveForwardFuzzy(typeName, resolvedData, entity, schema, provider, entityId);
475
- const backwardResolvedData = await resolveBackwardFuzzy(typeName, fuzzyResolvedData, entity, schema, provider);
476
- const finalData = await generateAIFields(backwardResolvedData, typeName, entity, schema, provider);
477
- const result = await provider.create(typeName, entityId, finalData);
478
- for (const rel of pendingRelations) {
479
- await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId);
480
- }
481
- const createdEdgeIds = new Set();
482
- for (const rel of fuzzyPendingRelations) {
483
- await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId, {
484
- matchMode: 'fuzzy',
485
- similarity: rel.similarity
486
- });
487
- const edgeId = `${typeName}:${rel.fieldName}:${entityId}:${rel.targetId}`;
488
- if (!createdEdgeIds.has(edgeId)) {
489
- createdEdgeIds.add(edgeId);
490
- try {
491
- await provider.create('Edge', edgeId, {
492
- from: typeName,
493
- name: rel.fieldName,
494
- to: rel.targetType,
495
- direction: 'forward',
496
- matchMode: 'fuzzy',
497
- similarity: rel.similarity,
498
- fromId: entityId,
499
- toId: rel.targetId,
500
- });
501
- }
502
- catch {
503
- // Edge already exists
504
- }
505
- }
506
- }
507
- return hydrateEntity(result, entity, schema, resolveProvider);
508
- },
509
- async update(id, data) {
510
- const provider = await resolveProvider();
511
- const result = await provider.update(typeName, id, data);
512
- return hydrateEntity(result, entity, schema, resolveProvider);
513
- },
514
- async upsert(id, data) {
515
- const provider = await resolveProvider();
516
- const existing = await provider.get(typeName, id);
517
- if (existing) {
518
- const result = await provider.update(typeName, id, data);
519
- return hydrateEntity(result, entity, schema, resolveProvider);
520
- }
521
- const result = await provider.create(typeName, id, data);
522
- return hydrateEntity(result, entity, schema, resolveProvider);
523
- },
524
- async delete(id) {
525
- const provider = await resolveProvider();
526
- return provider.delete(typeName, id);
527
- },
528
- async forEach(optionsOrCallback, maybeCallback) {
529
- const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
530
- const callback = typeof optionsOrCallback === 'function'
531
- ? optionsOrCallback
532
- : maybeCallback;
533
- const items = await this.list(options);
534
- for (const item of items) {
535
- await callback(item);
536
- }
537
- },
538
- async semanticSearch(query, options) {
539
- const provider = await resolveProvider();
540
- if (hasSemanticSearch(provider)) {
541
- const results = await provider.semanticSearch(typeName, query, options);
542
- return Promise.all(results.map((r) => ({
543
- ...hydrateEntity(r, entity, schema, resolveProvider),
544
- $score: r.$score,
545
- })));
546
- }
547
- return [];
548
- },
549
- async hybridSearch(query, options) {
550
- const provider = await resolveProvider();
551
- if (hasHybridSearch(provider)) {
552
- const results = await provider.hybridSearch(typeName, query, options);
553
- return Promise.all(results.map((r) => ({
554
- ...hydrateEntity(r, entity, schema, resolveProvider),
555
- $rrfScore: r.$rrfScore,
556
- $ftsRank: r.$ftsRank,
557
- $semanticRank: r.$semanticRank,
558
- $score: r.$score,
559
- })));
560
- }
561
- return [];
562
- },
563
- async draft(data, options) {
564
- const draftData = { ...data, $phase: 'draft' };
565
- const refs = {};
566
- for (const [fieldName, field] of entity.fields) {
567
- if (draftData[fieldName] !== undefined && draftData[fieldName] !== null) {
568
- continue;
569
- }
570
- if (field.operator && field.relatedType) {
571
- const matchMode = field.matchMode ?? (field.operator.includes('~') ? 'fuzzy' : 'exact');
572
- if (field.isArray) {
573
- const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
574
- draftData[fieldName] = generatedText;
575
- const refSpec = {
576
- field: fieldName,
577
- operator: field.operator,
578
- type: field.relatedType,
579
- matchMode,
580
- resolved: false,
581
- prompt: field.prompt,
582
- generatedText,
583
- };
584
- refs[fieldName] = [refSpec];
585
- if (options?.stream && options.onChunk) {
586
- options.onChunk(generatedText);
587
- }
588
- }
589
- else {
590
- const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
591
- draftData[fieldName] = generatedText;
592
- refs[fieldName] = {
593
- field: fieldName,
594
- operator: field.operator,
595
- type: field.relatedType,
596
- matchMode,
597
- resolved: false,
598
- prompt: field.prompt,
599
- generatedText,
600
- };
601
- if (options?.stream && options.onChunk) {
602
- options.onChunk(generatedText);
603
- }
604
- }
605
- }
606
- }
607
- draftData.$refs = refs;
608
- return draftData;
609
- },
610
- async resolve(draft, options) {
611
- // Draft<T> interface requires $phase: 'draft', so we can access it directly
612
- if (draft.$phase !== 'draft') {
613
- throw new Error('Cannot resolve entity: not a draft (missing $phase: "draft")');
614
- }
615
- const provider = await resolveProvider();
616
- const resolved = { ...draft };
617
- const errors = [];
618
- delete resolved.$refs;
619
- resolved.$phase = 'resolved';
620
- const refs = draft.$refs;
621
- for (const [fieldName, refSpec] of Object.entries(refs)) {
622
- try {
623
- if (Array.isArray(refSpec)) {
624
- const resolvedIds = [];
625
- for (const spec of refSpec) {
626
- const resolvedId = await resolveReferenceSpec(spec, resolved, schema, provider, generateContextAwareValue);
627
- if (resolvedId) {
628
- resolvedIds.push(resolvedId);
629
- options?.onResolved?.(fieldName, resolvedId);
630
- }
631
- }
632
- resolved[fieldName] = resolvedIds;
633
- }
634
- else {
635
- const resolvedId = await resolveReferenceSpec(refSpec, resolved, schema, provider, generateContextAwareValue);
636
- if (resolvedId) {
637
- resolved[fieldName] = resolvedId;
638
- options?.onResolved?.(fieldName, resolvedId);
639
- }
640
- }
641
- }
642
- catch (err) {
643
- const errorMsg = err instanceof Error ? err.message : String(err);
644
- if (options?.onError === 'skip') {
645
- errors.push({ field: fieldName, error: errorMsg });
646
- }
647
- else {
648
- throw err;
649
- }
650
- }
651
- }
652
- if (errors.length > 0 || options?.onError === 'skip') {
653
- // resolved is typed as Record<string, unknown>, so we can assign $errors directly
654
- resolved.$errors = errors;
655
- }
656
- return resolved;
657
- },
658
- };
659
- }
259
+ // Note: NL Query functions extracted to nl-query.ts
260
+ // Note: Edge Entity Operations extracted to entity-operations.ts
660
261
  // =============================================================================
661
262
  // DB Factory
662
263
  // =============================================================================
@@ -665,23 +266,199 @@ function createEntityOperations(typeName, entity, schema) {
665
266
  */
666
267
  export function DB(schema, options) {
667
268
  const parsedSchema = parseSchema(schema);
668
- // Add Edge entity to the parsed schema
269
+ // Add system entities to the parsed schema (Noun, Verb, Edge)
270
+ // Noun entity - represents type definitions
271
+ const nounEntity = {
272
+ name: 'Noun',
273
+ fields: new Map([
274
+ [
275
+ 'name',
276
+ { name: 'name', type: 'string', isArray: false, isOptional: false, isRelation: false },
277
+ ],
278
+ [
279
+ 'singular',
280
+ { name: 'singular', type: 'string', isArray: false, isOptional: false, isRelation: false },
281
+ ],
282
+ [
283
+ 'plural',
284
+ { name: 'plural', type: 'string', isArray: false, isOptional: false, isRelation: false },
285
+ ],
286
+ [
287
+ 'slug',
288
+ { name: 'slug', type: 'string', isArray: false, isOptional: false, isRelation: false },
289
+ ],
290
+ [
291
+ 'slugPlural',
292
+ {
293
+ name: 'slugPlural',
294
+ type: 'string',
295
+ isArray: false,
296
+ isOptional: false,
297
+ isRelation: false,
298
+ },
299
+ ],
300
+ [
301
+ 'description',
302
+ {
303
+ name: 'description',
304
+ type: 'string',
305
+ isArray: false,
306
+ isOptional: true,
307
+ isRelation: false,
308
+ },
309
+ ],
310
+ [
311
+ 'properties',
312
+ { name: 'properties', type: 'json', isArray: false, isOptional: true, isRelation: false },
313
+ ],
314
+ [
315
+ 'relationships',
316
+ {
317
+ name: 'relationships',
318
+ type: 'json',
319
+ isArray: false,
320
+ isOptional: true,
321
+ isRelation: false,
322
+ },
323
+ ],
324
+ [
325
+ 'actions',
326
+ { name: 'actions', type: 'json', isArray: false, isOptional: true, isRelation: false },
327
+ ],
328
+ [
329
+ 'events',
330
+ { name: 'events', type: 'json', isArray: false, isOptional: true, isRelation: false },
331
+ ],
332
+ [
333
+ 'metadata',
334
+ { name: 'metadata', type: 'json', isArray: false, isOptional: true, isRelation: false },
335
+ ],
336
+ ]),
337
+ };
338
+ parsedSchema.entities.set('Noun', nounEntity);
339
+ // Verb entity - represents action definitions
340
+ const verbEntity = {
341
+ name: 'Verb',
342
+ fields: new Map([
343
+ [
344
+ 'action',
345
+ { name: 'action', type: 'string', isArray: false, isOptional: false, isRelation: false },
346
+ ],
347
+ [
348
+ 'actor',
349
+ { name: 'actor', type: 'string', isArray: false, isOptional: true, isRelation: false },
350
+ ],
351
+ ['act', { name: 'act', type: 'string', isArray: false, isOptional: true, isRelation: false }],
352
+ [
353
+ 'activity',
354
+ { name: 'activity', type: 'string', isArray: false, isOptional: true, isRelation: false },
355
+ ],
356
+ [
357
+ 'result',
358
+ { name: 'result', type: 'string', isArray: false, isOptional: true, isRelation: false },
359
+ ],
360
+ [
361
+ 'reverse',
362
+ { name: 'reverse', type: 'json', isArray: false, isOptional: true, isRelation: false },
363
+ ],
364
+ [
365
+ 'inverse',
366
+ { name: 'inverse', type: 'string', isArray: false, isOptional: true, isRelation: false },
367
+ ],
368
+ [
369
+ 'description',
370
+ {
371
+ name: 'description',
372
+ type: 'string',
373
+ isArray: false,
374
+ isOptional: true,
375
+ isRelation: false,
376
+ },
377
+ ],
378
+ ]),
379
+ };
380
+ parsedSchema.entities.set('Verb', verbEntity);
381
+ // Edge entity - represents relationships
669
382
  const edgeEntity = {
670
383
  name: 'Edge',
671
384
  fields: new Map([
672
- ['from', { name: 'from', type: 'string', isArray: false, isOptional: false, isRelation: false }],
673
- ['name', { name: 'name', type: 'string', isArray: false, isOptional: false, isRelation: false }],
385
+ [
386
+ 'from',
387
+ { name: 'from', type: 'string', isArray: false, isOptional: false, isRelation: false },
388
+ ],
389
+ [
390
+ 'name',
391
+ { name: 'name', type: 'string', isArray: false, isOptional: false, isRelation: false },
392
+ ],
674
393
  ['to', { name: 'to', type: 'string', isArray: false, isOptional: false, isRelation: false }],
675
- ['backref', { name: 'backref', type: 'string', isArray: false, isOptional: true, isRelation: false }],
676
- ['cardinality', { name: 'cardinality', type: 'string', isArray: false, isOptional: false, isRelation: false }],
677
- ['direction', { name: 'direction', type: 'string', isArray: false, isOptional: false, isRelation: false }],
678
- ['matchMode', { name: 'matchMode', type: 'string', isArray: false, isOptional: true, isRelation: false }],
394
+ [
395
+ 'backref',
396
+ { name: 'backref', type: 'string', isArray: false, isOptional: true, isRelation: false },
397
+ ],
398
+ [
399
+ 'cardinality',
400
+ {
401
+ name: 'cardinality',
402
+ type: 'string',
403
+ isArray: false,
404
+ isOptional: false,
405
+ isRelation: false,
406
+ },
407
+ ],
408
+ [
409
+ 'direction',
410
+ { name: 'direction', type: 'string', isArray: false, isOptional: false, isRelation: false },
411
+ ],
412
+ [
413
+ 'matchMode',
414
+ { name: 'matchMode', type: 'string', isArray: false, isOptional: true, isRelation: false },
415
+ ],
679
416
  ]),
680
417
  };
681
418
  parsedSchema.entities.set('Edge', edgeEntity);
419
+ // Create local getProvider function for dependency injection
420
+ // If options.provider is provided, use it; otherwise fall back to global resolveProvider()
421
+ let cachedProvider = null;
422
+ let providerPromise = null;
423
+ async function getProvider() {
424
+ // Return cached provider if available
425
+ if (cachedProvider)
426
+ return cachedProvider;
427
+ // Return pending promise if resolution is in progress
428
+ if (providerPromise)
429
+ return providerPromise;
430
+ // Check if options.provider is provided (dependency injection)
431
+ if (options?.provider) {
432
+ providerPromise = (async () => {
433
+ const providerOption = options.provider;
434
+ if (typeof providerOption === 'function') {
435
+ // It's a factory function - call it
436
+ const result = providerOption();
437
+ // Handle both sync and async factory functions
438
+ cachedProvider = result instanceof Promise ? await result : result;
439
+ }
440
+ else {
441
+ // It's a direct provider instance
442
+ cachedProvider = providerOption;
443
+ }
444
+ return cachedProvider;
445
+ })();
446
+ return providerPromise;
447
+ }
448
+ // Fall back to global resolveProvider()
449
+ providerPromise = resolveProvider().then((p) => {
450
+ cachedProvider = p;
451
+ return p;
452
+ });
453
+ return providerPromise;
454
+ }
455
+ // Configure value generator if provided
456
+ if (options?.valueGenerator) {
457
+ setValueGenerator(options.valueGenerator);
458
+ }
682
459
  // Configure provider with embeddings settings if provided
683
460
  if (options?.embeddings) {
684
- resolveProvider().then(provider => {
461
+ getProvider().then((provider) => {
685
462
  if (hasEmbeddingsConfig(provider)) {
686
463
  provider.setEmbeddingsConfig(options.embeddings);
687
464
  }
@@ -690,11 +467,27 @@ export function DB(schema, options) {
690
467
  // Collect all edge records from the schema
691
468
  const allEdgeRecords = [];
692
469
  for (const [entityName, entity] of parsedSchema.entities) {
693
- if (entityName !== 'Edge') {
470
+ // Only create edge records for user-defined entities (not system entities)
471
+ if (entityName !== 'Edge' && entityName !== 'Noun' && entityName !== 'Verb') {
694
472
  const edgeRecords = createEdgeRecords(entityName, schema[entityName] ?? {}, entity);
695
473
  allEdgeRecords.push(...edgeRecords);
696
474
  }
697
475
  }
476
+ // Collect all noun records from the schema (user-defined entities only)
477
+ const allNounRecords = [];
478
+ for (const [entityName, entity] of parsedSchema.entities) {
479
+ // Only create noun records for user-defined entities (not system entities)
480
+ if (entityName !== 'Edge' && entityName !== 'Noun' && entityName !== 'Verb') {
481
+ const nounRecord = createNounRecord(entityName, schema[entityName]);
482
+ allNounRecords.push(nounRecord);
483
+ }
484
+ }
485
+ // Collect all verb records from the standard verbs
486
+ const allVerbRecords = Object.values(Verbs).map((verb) => ({
487
+ ...verb,
488
+ $id: verb.action,
489
+ $type: 'Verb',
490
+ }));
698
491
  // Build and set schema relation info for batch loading
699
492
  // Maps entityType -> fieldName -> relatedType
700
493
  const relationInfo = new Map();
@@ -714,7 +507,7 @@ export function DB(schema, options) {
714
507
  // This API adapts DBAction to ForEachActionsAPI interface
715
508
  const actionsAPI = {
716
509
  async create(data) {
717
- const provider = await resolveProvider();
510
+ const provider = await getProvider();
718
511
  if (hasActionsAPI(provider)) {
719
512
  const action = await provider.createAction(data);
720
513
  return { id: action.id };
@@ -722,35 +515,45 @@ export function DB(schema, options) {
722
515
  throw new Error('Provider does not support actions');
723
516
  },
724
517
  async get(id) {
725
- const provider = await resolveProvider();
518
+ const provider = await getProvider();
726
519
  if (hasActionsAPI(provider)) {
727
520
  const action = await provider.getAction(id);
728
521
  if (!action)
729
522
  return null;
730
523
  // Adapt DBAction to ForEachActionState
731
- return {
524
+ const state = {
732
525
  id: action.id,
733
526
  type: action.action ?? action.type ?? 'unknown',
734
527
  status: action.status,
735
- progress: action.progress,
736
- total: action.total,
737
528
  data: action.objectData ?? {},
738
- result: action.result,
739
- error: action.error,
740
529
  };
530
+ if (action.progress !== undefined)
531
+ state.progress = action.progress;
532
+ if (action.total !== undefined)
533
+ state.total = action.total;
534
+ if (action.result !== undefined)
535
+ state.result = action.result;
536
+ if (action.error !== undefined)
537
+ state.error = action.error;
538
+ return state;
741
539
  }
742
540
  return null;
743
541
  },
744
542
  async update(id, updates) {
745
- const provider = await resolveProvider();
543
+ const provider = await getProvider();
746
544
  if (hasActionsAPI(provider)) {
747
- await provider.updateAction(id, {
748
- status: updates.status,
749
- progress: updates.progress,
750
- // ForEachResult needs to be converted to Record<string, unknown> for DBAction.result
751
- result: updates.result,
752
- error: updates.error,
753
- });
545
+ const updatePayload = {};
546
+ if (updates.status !== undefined)
547
+ updatePayload.status = updates.status;
548
+ if (updates.progress !== undefined)
549
+ updatePayload.progress = updates.progress;
550
+ if (updates.error !== undefined)
551
+ updatePayload.error = updates.error;
552
+ // ForEachResult needs to be converted to Record<string, unknown> for DBAction.result
553
+ if (updates.result !== undefined) {
554
+ updatePayload.result = updates.result;
555
+ }
556
+ await provider.updateAction(id, updatePayload);
754
557
  return;
755
558
  }
756
559
  throw new Error('Provider does not support actions');
@@ -771,12 +574,13 @@ export function DB(schema, options) {
771
574
  function emitInternalEventForOps(eventType, data) {
772
575
  const handlers = eventHandlersForOps.get(eventType);
773
576
  if (handlers) {
774
- for (const handler of handlers) {
577
+ const snapshot = [...handlers];
578
+ for (const handler of snapshot) {
775
579
  try {
776
580
  handler(data);
777
581
  }
778
582
  catch (e) {
779
- console.error(`Error in event handler for ${eventType}:`, e);
583
+ logError(`Error in event handler for ${eventType}:`, e);
780
584
  }
781
585
  }
782
586
  }
@@ -798,10 +602,23 @@ export function DB(schema, options) {
798
602
  }
799
603
  for (const [entityName, entity] of parsedSchema.entities) {
800
604
  if (entityName === 'Edge') {
801
- const edgeOps = createEdgeEntityOperations(allEdgeRecords, resolveProvider);
605
+ // Edge entity - auto-generated from schema relationships
606
+ const edgeOps = createEdgeEntityOperations(allEdgeRecords, getProvider);
802
607
  const wrappedEdgeOps = wrapEntityOperations(entityName, edgeOps, actionsAPI);
803
608
  entityOperations[entityName] = makeCallableEntityOps(wrappedEdgeOps, entityName);
804
609
  }
610
+ else if (entityName === 'Noun') {
611
+ // Noun entity - auto-generated from schema entity types
612
+ const nounOps = createNounEntityOperations(allNounRecords);
613
+ const wrappedNounOps = wrapEntityOperations(entityName, nounOps, actionsAPI);
614
+ entityOperations[entityName] = makeCallableEntityOps(wrappedNounOps, entityName);
615
+ }
616
+ else if (entityName === 'Verb') {
617
+ // Verb entity - standard verbs with conjugation forms
618
+ const verbOps = createVerbEntityOperations(allVerbRecords);
619
+ const wrappedVerbOps = wrapEntityOperations(entityName, verbOps, actionsAPI);
620
+ entityOperations[entityName] = makeCallableEntityOps(wrappedVerbOps, entityName);
621
+ }
805
622
  else {
806
623
  const baseOps = createEntityOperations(entityName, entity, parsedSchema);
807
624
  const wrappedOps = wrapEntityOperations(entityName, baseOps, actionsAPI);
@@ -813,7 +630,7 @@ export function DB(schema, options) {
813
630
  throw new Error(`Draft method not available for ${entityName}`);
814
631
  }
815
632
  const draft = await draftMethod(data, options);
816
- draft.$type = entityName;
633
+ draft['$type'] = entityName;
817
634
  emitInternalEventForOps('draft', draft);
818
635
  return draft;
819
636
  };
@@ -824,7 +641,8 @@ export function DB(schema, options) {
824
641
  }
825
642
  const resolved = await resolveMethod(draft, options);
826
643
  if (resolved && typeof resolved === 'object') {
827
- resolved.$type = entityName;
644
+ ;
645
+ resolved['$type'] = entityName;
828
646
  }
829
647
  emitInternalEventForOps('resolve', resolved);
830
648
  return resolved;
@@ -848,27 +666,57 @@ export function DB(schema, options) {
848
666
  const draft = await draftFn(data);
849
667
  return draft;
850
668
  }
669
+ // Check if entity has reference fields that need two-phase processing
670
+ const entityDef = parsedSchema.entities.get(entityName);
851
671
  const effectiveMaxDepth = options?.maxDepth ?? (options?.cascade ? 3 : 0);
672
+ // Disable auto-generation when:
673
+ // 1. cascade is explicitly set to false
674
+ // 2. cascade is true but maxDepth is 0 (depth exhausted)
675
+ // When cascade is undefined, single-level array generation is allowed
676
+ const cascadeExplicitlyDisabled = options?.cascade === false || (options?.cascade === true && effectiveMaxDepth === 0);
677
+ const hasReferenceFields = entityDef &&
678
+ Array.from(entityDef.fields.values()).some((field) => {
679
+ if (!field.operator || !field.relatedType)
680
+ return false;
681
+ // Exclude forward fuzzy (~>) - handled by resolveForwardFuzzy in the direct create path
682
+ if (field.operator === '~>')
683
+ return false;
684
+ // For forward exact (->) array fields when cascade is explicitly disabled
685
+ if (field.operator === '->' && field.isArray && cascadeExplicitlyDisabled) {
686
+ return false;
687
+ }
688
+ return true;
689
+ });
690
+ // Cascade takes priority over two-phase processing when enabled
691
+ // Cascade handles generating related entities through the graph
852
692
  if (options?.cascade && effectiveMaxDepth > 0) {
853
- const provider = await resolveProvider();
693
+ const provider = await getProvider();
854
694
  const entityDef = parsedSchema.entities.get(entityName);
855
695
  if (entityDef) {
856
696
  // CreateEntityOptions now includes _cascadeState as an optional property
857
697
  const cascadeState = options._cascadeState ?? {
858
698
  totalEntitiesCreated: 0,
859
699
  initialMaxDepth: effectiveMaxDepth,
860
- rootOnProgress: options.onProgress,
861
- rootOnError: options.onError,
862
- stopOnError: options.stopOnError,
863
- cascadeTypes: options.cascadeTypes,
700
+ ...(options.onProgress !== undefined && { rootOnProgress: options.onProgress }),
701
+ ...(options.onError !== undefined && { rootOnError: options.onError }),
702
+ ...(options.stopOnError !== undefined && { stopOnError: options.stopOnError }),
703
+ ...(options.cascadeTypes !== undefined && { cascadeTypes: options.cascadeTypes }),
864
704
  };
865
705
  const currentDepth = cascadeState.initialMaxDepth - effectiveMaxDepth;
866
706
  const cascadeData = { ...data };
707
+ // Emit progress for current entity being generated
708
+ cascadeState.rootOnProgress?.({
709
+ phase: 'generating',
710
+ depth: currentDepth,
711
+ currentType: entityName,
712
+ totalEntitiesCreated: cascadeState.totalEntitiesCreated,
713
+ });
867
714
  for (const [fieldName, field] of entityDef.fields) {
868
715
  if (cascadeData[fieldName] !== undefined)
869
716
  continue;
870
717
  if (field.operator === '->' && field.relatedType) {
871
- if (cascadeState.cascadeTypes && !cascadeState.cascadeTypes.includes(field.relatedType)) {
718
+ if (cascadeState.cascadeTypes &&
719
+ !cascadeState.cascadeTypes.includes(field.relatedType)) {
872
720
  continue;
873
721
  }
874
722
  const relatedEntity = parsedSchema.entities.get(field.relatedType);
@@ -882,39 +730,48 @@ export function DB(schema, options) {
882
730
  totalEntitiesCreated: cascadeState.totalEntitiesCreated,
883
731
  });
884
732
  const childEntityData = {};
885
- const parentInstructions = entityDef.schema?.$instructions;
886
- const childInstructions = relatedEntity.schema?.$instructions;
733
+ const parentInstructions = entityDef.schema?.['$instructions'];
734
+ const childInstructions = relatedEntity.schema?.['$instructions'];
887
735
  const contextParts = [];
888
736
  if (parentInstructions)
889
737
  contextParts.push(parentInstructions);
890
738
  if (childInstructions)
891
739
  contextParts.push(childInstructions);
892
740
  for (const [key, value] of Object.entries(cascadeData)) {
893
- if (!key.startsWith('$') && !key.startsWith('_') && typeof value === 'string' && value) {
741
+ if (!key.startsWith('$') &&
742
+ !key.startsWith('_') &&
743
+ typeof value === 'string' &&
744
+ value) {
894
745
  contextParts.push(`${key}: ${value}`);
895
746
  }
896
747
  }
897
748
  const fullContext = contextParts.join(' | ');
898
749
  for (const [childFieldName, childField] of relatedEntity.fields) {
899
- if (!childField.isRelation && childField.type === 'string') {
900
- childEntityData[childFieldName] = generateContextAwareValue(childFieldName, field.relatedType, fullContext, undefined, cascadeData);
750
+ const isPrompt = isPromptField(childField);
751
+ if (!childField.isRelation && (childField.type === 'string' || isPrompt)) {
752
+ // Use field type as hint for prompt fields
753
+ const fieldHint = isPrompt ? childField.type : undefined;
754
+ childEntityData[childFieldName] = generateContextAwareValue(childFieldName, field.relatedType, fullContext, fieldHint, cascadeData);
901
755
  }
902
756
  }
903
757
  const childOptions = {
904
758
  ...options,
759
+ cascade: true, // Ensure cascade continues for child entities
905
760
  maxDepth: effectiveMaxDepth - 1,
906
761
  _cascadeState: cascadeState,
907
762
  };
908
763
  const relatedOps = entityOperations[field.relatedType];
909
- const createFn = relatedOps?.create;
910
- const childEntity = createFn ? await createFn(childEntityData, childOptions) : undefined;
911
- if (childEntity?.$id) {
764
+ const createFn = relatedOps?.['create'];
765
+ const childEntity = createFn
766
+ ? await createFn(childEntityData, childOptions)
767
+ : undefined;
768
+ if (childEntity?.['$id']) {
912
769
  cascadeState.totalEntitiesCreated++;
913
770
  if (field.isArray) {
914
- cascadeData[fieldName] = [childEntity.$id];
771
+ cascadeData[fieldName] = [childEntity['$id']];
915
772
  }
916
773
  else {
917
- cascadeData[fieldName] = childEntity.$id;
774
+ cascadeData[fieldName] = childEntity['$id'];
918
775
  }
919
776
  }
920
777
  }
@@ -926,12 +783,13 @@ export function DB(schema, options) {
926
783
  }
927
784
  }
928
785
  }
786
+ const createFn = originalCreate;
929
787
  let result;
930
788
  if (id) {
931
- result = await originalCreate.call(wrappedOps, id, cascadeData);
789
+ result = await createFn.call(wrappedOps, id, cascadeData);
932
790
  }
933
791
  else {
934
- result = await originalCreate.call(wrappedOps, cascadeData);
792
+ result = await createFn.call(wrappedOps, cascadeData);
935
793
  }
936
794
  cascadeState.totalEntitiesCreated++;
937
795
  if (currentDepth === 0) {
@@ -944,8 +802,78 @@ export function DB(schema, options) {
944
802
  return result;
945
803
  }
946
804
  }
947
- return originalCreate.call(wrappedOps, ...args);
805
+ // Use two-phase draft/resolve pipeline when entity has reference fields (but cascade not enabled)
806
+ if (hasReferenceFields) {
807
+ // Phase 1: Draft - create placeholder with natural language refs
808
+ // Skip promptless refs when cascade is not explicitly enabled (default behavior = no auto-generation)
809
+ const skipPromptless = options?.cascade !== true;
810
+ const draft = await draftFn(data, { _skipPromptlessRefs: skipPromptless });
811
+ // Phase 2: Resolve - convert refs to actual entity IDs
812
+ const resolved = await resolveFn(draft);
813
+ // Extract clean data for persistence (remove $phase, $refs, $errors)
814
+ const { $phase, $refs, $errors, $type, ...cleanData } = resolved;
815
+ // Phase 3: Generate AI fields for entities with $context dependencies
816
+ // The draft phase skips prompt fields for entities with $context because
817
+ // those fields need pre-fetched context data to generate properly.
818
+ // generateAIFields handles this context pre-fetching and field generation.
819
+ const provider = await getProvider();
820
+ const entityDefForAI = parsedSchema.entities.get(entityName);
821
+ let finalCleanData = cleanData;
822
+ if (entityDefForAI) {
823
+ finalCleanData = await generateAIFields(cleanData, entityName, entityDefForAI, parsedSchema, provider);
824
+ }
825
+ const createFn = originalCreate;
826
+ let result;
827
+ if (id) {
828
+ result = await createFn.call(wrappedOps, id, finalCleanData);
829
+ }
830
+ else {
831
+ result = await createFn.call(wrappedOps, finalCleanData);
832
+ }
833
+ return result;
834
+ }
835
+ // Pre-initialize empty arrays for ->Type[] fields when cascade is explicitly disabled
836
+ // This prevents resolveForwardExact from auto-generating entities for array fields
837
+ let processedData = data;
838
+ if (cascadeExplicitlyDisabled && entityDef) {
839
+ processedData = { ...data };
840
+ for (const [fieldName, field] of entityDef.fields) {
841
+ if (processedData[fieldName] !== undefined)
842
+ continue;
843
+ if (field.isArray && field.operator === '->' && field.relatedType) {
844
+ processedData[fieldName] = [];
845
+ }
846
+ }
847
+ }
848
+ // Call with properly typed arguments (already extracted above)
849
+ // Use type assertion for internal overload dispatch via .call()
850
+ const createFnFinal = originalCreate;
851
+ if (id) {
852
+ return createFnFinal.call(wrappedOps, id, processedData, options);
853
+ }
854
+ return createFnFinal.call(wrappedOps, processedData, options);
948
855
  };
856
+ // Add seed method if entity has seed configuration
857
+ if (entity.seedConfig) {
858
+ const seedConfig = entity.seedConfig;
859
+ wrappedOps['seed'] = async () => {
860
+ const { loadSeedData } = await import('./seed.js');
861
+ const records = await loadSeedData(seedConfig);
862
+ const provider = await getProvider();
863
+ for (const record of records) {
864
+ const { $id, ...data } = record;
865
+ // Upsert: check if exists, then update or create
866
+ const existing = await provider.get(entityName, $id);
867
+ if (existing) {
868
+ await provider.update(entityName, $id, data);
869
+ }
870
+ else {
871
+ await provider.create(entityName, $id, data);
872
+ }
873
+ }
874
+ return { count: records.length };
875
+ };
876
+ }
949
877
  // Make the entity operations callable as a tagged template literal
950
878
  entityOperations[entityName] = makeCallableEntityOps(wrappedOps, entityName);
951
879
  }
@@ -970,12 +898,12 @@ export function DB(schema, options) {
970
898
  const db = {
971
899
  $schema: parsedSchema,
972
900
  async get(url) {
973
- const provider = await resolveProvider();
901
+ const provider = await getProvider();
974
902
  const parsed = parseUrl(url);
975
903
  return provider.get(parsed.type, parsed.id);
976
904
  },
977
905
  async search(query, options) {
978
- const provider = await resolveProvider();
906
+ const provider = await getProvider();
979
907
  const results = [];
980
908
  for (const [typeName] of parsedSchema.entities) {
981
909
  const typeResults = await provider.search(typeName, query, options);
@@ -984,7 +912,7 @@ export function DB(schema, options) {
984
912
  return results;
985
913
  },
986
914
  async semanticSearch(query, options) {
987
- const provider = await resolveProvider();
915
+ const provider = await getProvider();
988
916
  const results = [];
989
917
  if (hasSemanticSearch(provider)) {
990
918
  for (const [typeName] of parsedSchema.entities) {
@@ -997,13 +925,19 @@ export function DB(schema, options) {
997
925
  return results.slice(0, limit);
998
926
  },
999
927
  async count(type, where) {
1000
- const provider = await resolveProvider();
1001
- const results = await provider.list(type, { where });
928
+ const provider = await getProvider();
929
+ const listOpts = {};
930
+ if (where !== undefined)
931
+ listOpts.where = where;
932
+ const results = await provider.list(type, listOpts);
1002
933
  return results.length;
1003
934
  },
1004
935
  async forEach(options, callback) {
1005
- const provider = await resolveProvider();
1006
- const results = await provider.list(options.type, { where: options.where });
936
+ const provider = await getProvider();
937
+ const listOpts = {};
938
+ if (options.where !== undefined)
939
+ listOpts.where = options.where;
940
+ const results = await provider.list(options.type, listOpts);
1007
941
  const concurrency = options.concurrency ?? 1;
1008
942
  if (concurrency === 1) {
1009
943
  for (const entity of results) {
@@ -1017,7 +951,7 @@ export function DB(schema, options) {
1017
951
  }
1018
952
  },
1019
953
  async set(type, id, data) {
1020
- const provider = await resolveProvider();
954
+ const provider = await getProvider();
1021
955
  const existing = await provider.get(type, id);
1022
956
  if (existing) {
1023
957
  return provider.update(type, id, data);
@@ -1025,7 +959,7 @@ export function DB(schema, options) {
1025
959
  return provider.create(type, id, data);
1026
960
  },
1027
961
  async generate(options) {
1028
- const provider = await resolveProvider();
962
+ const provider = await getProvider();
1029
963
  if (options.mode === 'background') {
1030
964
  const { createMemoryProvider } = await import('../memory-provider.js');
1031
965
  const memProvider = provider;
@@ -1047,7 +981,7 @@ export function DB(schema, options) {
1047
981
  const events = {
1048
982
  on(pattern, handler) {
1049
983
  let unsubscribe = () => { };
1050
- resolveProvider().then((provider) => {
984
+ getProvider().then((provider) => {
1051
985
  if (hasEventsAPI(provider)) {
1052
986
  unsubscribe = provider.on(pattern, handler);
1053
987
  }
@@ -1055,7 +989,7 @@ export function DB(schema, options) {
1055
989
  return () => unsubscribe();
1056
990
  },
1057
991
  async emit(optionsOrType, data) {
1058
- const provider = await resolveProvider();
992
+ const provider = await getProvider();
1059
993
  if (hasEventsAPI(provider)) {
1060
994
  // The provider.emit has overloads: (options: CreateEventOptions) or (type: string, data: unknown)
1061
995
  if (typeof optionsOrType === 'string') {
@@ -1065,36 +999,45 @@ export function DB(schema, options) {
1065
999
  }
1066
1000
  const now = new Date();
1067
1001
  if (typeof optionsOrType === 'string') {
1068
- return {
1002
+ const baseEvent = {
1069
1003
  id: crypto.randomUUID(),
1070
1004
  actor: 'system',
1071
1005
  event: optionsOrType,
1072
- objectData: data,
1073
1006
  timestamp: now,
1074
1007
  };
1008
+ if (data !== undefined)
1009
+ baseEvent.objectData = data;
1010
+ return baseEvent;
1075
1011
  }
1076
- return {
1012
+ const baseEvent = {
1077
1013
  id: crypto.randomUUID(),
1078
1014
  actor: optionsOrType.actor,
1079
- actorData: optionsOrType.actorData,
1080
1015
  event: optionsOrType.event,
1081
- object: optionsOrType.object,
1082
- objectData: optionsOrType.objectData,
1083
- result: optionsOrType.result,
1084
- resultData: optionsOrType.resultData,
1085
- meta: optionsOrType.meta,
1086
1016
  timestamp: now,
1087
1017
  };
1018
+ if (optionsOrType.actorData !== undefined)
1019
+ baseEvent.actorData = optionsOrType.actorData;
1020
+ if (optionsOrType.object !== undefined)
1021
+ baseEvent.object = optionsOrType.object;
1022
+ if (optionsOrType.objectData !== undefined)
1023
+ baseEvent.objectData = optionsOrType.objectData;
1024
+ if (optionsOrType.result !== undefined)
1025
+ baseEvent.result = optionsOrType.result;
1026
+ if (optionsOrType.resultData !== undefined)
1027
+ baseEvent.resultData = optionsOrType.resultData;
1028
+ if (optionsOrType.meta !== undefined)
1029
+ baseEvent.meta = optionsOrType.meta;
1030
+ return baseEvent;
1088
1031
  },
1089
1032
  async list(options) {
1090
- const provider = await resolveProvider();
1033
+ const provider = await getProvider();
1091
1034
  if (hasEventsAPI(provider)) {
1092
1035
  return provider.listEvents(options);
1093
1036
  }
1094
1037
  return [];
1095
1038
  },
1096
1039
  async replay(options) {
1097
- const provider = await resolveProvider();
1040
+ const provider = await getProvider();
1098
1041
  if (hasEventsAPI(provider)) {
1099
1042
  await provider.replayEvents(options);
1100
1043
  }
@@ -1103,42 +1046,42 @@ export function DB(schema, options) {
1103
1046
  // Create Actions API (public version with full DBAction types)
1104
1047
  const actions = {
1105
1048
  async create(options) {
1106
- const provider = await resolveProvider();
1049
+ const provider = await getProvider();
1107
1050
  if (hasActionsAPI(provider)) {
1108
1051
  return provider.createAction(options);
1109
1052
  }
1110
1053
  throw new Error('Provider does not support actions');
1111
1054
  },
1112
1055
  async get(id) {
1113
- const provider = await resolveProvider();
1056
+ const provider = await getProvider();
1114
1057
  if (hasActionsAPI(provider)) {
1115
1058
  return provider.getAction(id);
1116
1059
  }
1117
1060
  return null;
1118
1061
  },
1119
1062
  async update(id, updates) {
1120
- const provider = await resolveProvider();
1063
+ const provider = await getProvider();
1121
1064
  if (hasActionsAPI(provider)) {
1122
1065
  return provider.updateAction(id, updates);
1123
1066
  }
1124
1067
  throw new Error('Provider does not support actions');
1125
1068
  },
1126
1069
  async list(options) {
1127
- const provider = await resolveProvider();
1070
+ const provider = await getProvider();
1128
1071
  if (hasActionsAPI(provider)) {
1129
1072
  return provider.listActions(options);
1130
1073
  }
1131
1074
  return [];
1132
1075
  },
1133
1076
  async retry(id) {
1134
- const provider = await resolveProvider();
1077
+ const provider = await getProvider();
1135
1078
  if (hasActionsAPI(provider)) {
1136
1079
  return provider.retryAction(id);
1137
1080
  }
1138
1081
  throw new Error('Provider does not support actions');
1139
1082
  },
1140
1083
  async cancel(id) {
1141
- const provider = await resolveProvider();
1084
+ const provider = await getProvider();
1142
1085
  if (hasActionsAPI(provider)) {
1143
1086
  await provider.cancelAction(id);
1144
1087
  }
@@ -1148,26 +1091,26 @@ export function DB(schema, options) {
1148
1091
  // Create Artifacts API
1149
1092
  const artifacts = {
1150
1093
  async get(url, type) {
1151
- const provider = await resolveProvider();
1094
+ const provider = await getProvider();
1152
1095
  if (hasArtifactsAPI(provider)) {
1153
1096
  return provider.getArtifact(url, type);
1154
1097
  }
1155
1098
  return null;
1156
1099
  },
1157
1100
  async set(url, type, data) {
1158
- const provider = await resolveProvider();
1101
+ const provider = await getProvider();
1159
1102
  if (hasArtifactsAPI(provider)) {
1160
1103
  await provider.setArtifact(url, type, data);
1161
1104
  }
1162
1105
  },
1163
1106
  async delete(url, type) {
1164
- const provider = await resolveProvider();
1107
+ const provider = await getProvider();
1165
1108
  if (hasArtifactsAPI(provider)) {
1166
1109
  await provider.deleteArtifact(url, type);
1167
1110
  }
1168
1111
  },
1169
1112
  async list(url) {
1170
- const provider = await resolveProvider();
1113
+ const provider = await getProvider();
1171
1114
  if (hasArtifactsAPI(provider)) {
1172
1115
  return provider.listArtifacts(url);
1173
1116
  }