ai-database 0.0.0-development → 0.2.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 (79) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-test.log +102 -0
  3. package/README.md +402 -47
  4. package/TESTING.md +410 -0
  5. package/TEST_SUMMARY.md +250 -0
  6. package/TODO.md +128 -0
  7. package/dist/ai-promise-db.d.ts +370 -0
  8. package/dist/ai-promise-db.d.ts.map +1 -0
  9. package/dist/ai-promise-db.js +839 -0
  10. package/dist/ai-promise-db.js.map +1 -0
  11. package/dist/authorization.d.ts +531 -0
  12. package/dist/authorization.d.ts.map +1 -0
  13. package/dist/authorization.js +632 -0
  14. package/dist/authorization.js.map +1 -0
  15. package/dist/durable-clickhouse.d.ts +193 -0
  16. package/dist/durable-clickhouse.d.ts.map +1 -0
  17. package/dist/durable-clickhouse.js +422 -0
  18. package/dist/durable-clickhouse.js.map +1 -0
  19. package/dist/durable-promise.d.ts +182 -0
  20. package/dist/durable-promise.d.ts.map +1 -0
  21. package/dist/durable-promise.js +409 -0
  22. package/dist/durable-promise.js.map +1 -0
  23. package/dist/execution-queue.d.ts +239 -0
  24. package/dist/execution-queue.d.ts.map +1 -0
  25. package/dist/execution-queue.js +400 -0
  26. package/dist/execution-queue.js.map +1 -0
  27. package/dist/index.d.ts +54 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +79 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/linguistic.d.ts +115 -0
  32. package/dist/linguistic.d.ts.map +1 -0
  33. package/dist/linguistic.js +379 -0
  34. package/dist/linguistic.js.map +1 -0
  35. package/dist/memory-provider.d.ts +304 -0
  36. package/dist/memory-provider.d.ts.map +1 -0
  37. package/dist/memory-provider.js +785 -0
  38. package/dist/memory-provider.js.map +1 -0
  39. package/dist/schema.d.ts +899 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +1165 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/tests.d.ts +107 -0
  44. package/dist/tests.d.ts.map +1 -0
  45. package/dist/tests.js +568 -0
  46. package/dist/tests.js.map +1 -0
  47. package/dist/types.d.ts +972 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +126 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +37 -23
  52. package/src/ai-promise-db.ts +1243 -0
  53. package/src/authorization.ts +1102 -0
  54. package/src/durable-clickhouse.ts +596 -0
  55. package/src/durable-promise.ts +582 -0
  56. package/src/execution-queue.ts +608 -0
  57. package/src/index.test.ts +868 -0
  58. package/src/index.ts +337 -0
  59. package/src/linguistic.ts +404 -0
  60. package/src/memory-provider.test.ts +1036 -0
  61. package/src/memory-provider.ts +1119 -0
  62. package/src/schema.test.ts +1254 -0
  63. package/src/schema.ts +2296 -0
  64. package/src/tests.ts +725 -0
  65. package/src/types.ts +1177 -0
  66. package/test/README.md +153 -0
  67. package/test/edge-cases.test.ts +646 -0
  68. package/test/provider-resolution.test.ts +402 -0
  69. package/tsconfig.json +9 -0
  70. package/vitest.config.ts +19 -0
  71. package/LICENSE +0 -21
  72. package/dist/types/database.d.ts +0 -46
  73. package/dist/types/document.d.ts +0 -15
  74. package/dist/types/index.d.ts +0 -5
  75. package/dist/types/mdxdb/embedding.d.ts +0 -7
  76. package/dist/types/mdxdb/types.d.ts +0 -59
  77. package/dist/types/synthetic.d.ts +0 -9
  78. package/dist/types/tools.d.ts +0 -10
  79. package/dist/types/vector.d.ts +0 -16
package/src/types.ts ADDED
@@ -0,0 +1,1177 @@
1
+ /**
2
+ * Core Type Definitions
3
+ *
4
+ * Contains all foundational types for ai-database:
5
+ * - Thing types (mdxld-based entity structure)
6
+ * - Schema definition types
7
+ * - Parsed schema types
8
+ * - Noun & Verb semantic types
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+
13
+ import type { MDXLD } from 'mdxld'
14
+
15
+ // =============================================================================
16
+ // Thing Types (mdxld-based entity structure)
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Flat Thing shape with $-prefixed metadata fields
21
+ * Used for JSON-LD compatible serialization
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const post: ThingFlat = {
26
+ * $id: 'post-123',
27
+ * $type: 'Post',
28
+ * $context: 'https://schema.org',
29
+ * title: 'Hello World',
30
+ * content: '...',
31
+ * }
32
+ * ```
33
+ */
34
+ export interface ThingFlat {
35
+ /** Unique identifier */
36
+ $id: string
37
+ /** Entity type */
38
+ $type: string
39
+ /** JSON-LD context (optional) */
40
+ $context?: string | Record<string, unknown>
41
+ /** Additional data fields */
42
+ [key: string]: unknown
43
+ }
44
+
45
+ /**
46
+ * Expanded Thing shape with structured data and content
47
+ * Used for full document representation (mdxld format)
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const post: ThingExpanded = {
52
+ * id: 'post-123',
53
+ * type: 'Post',
54
+ * context: 'https://schema.org',
55
+ * data: { title: 'Hello World', author: 'john' },
56
+ * content: '# Hello World\n\nThis is my post...',
57
+ * }
58
+ * ```
59
+ */
60
+ export interface ThingExpanded extends MDXLD {
61
+ /** Unique identifier */
62
+ id: string
63
+ /** Entity type */
64
+ type: string
65
+ }
66
+
67
+ /**
68
+ * Convert flat thing to expanded format
69
+ */
70
+ export function toExpanded(flat: ThingFlat): ThingExpanded {
71
+ const { $id, $type, $context, ...rest } = flat
72
+ return {
73
+ id: $id,
74
+ type: $type,
75
+ context: $context,
76
+ data: rest,
77
+ content: typeof rest.content === 'string' ? rest.content : '',
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Convert expanded thing to flat format
83
+ */
84
+ export function toFlat(expanded: ThingExpanded): ThingFlat {
85
+ const { id, type, context, data, content, ...rest } = expanded
86
+ return {
87
+ $id: id,
88
+ $type: type,
89
+ $context: context,
90
+ ...data,
91
+ ...rest,
92
+ ...(content ? { content } : {}),
93
+ }
94
+ }
95
+
96
+ // =============================================================================
97
+ // Schema Definition Types
98
+ // =============================================================================
99
+
100
+ /**
101
+ * Primitive field types
102
+ */
103
+ export type PrimitiveType =
104
+ | 'string'
105
+ | 'number'
106
+ | 'boolean'
107
+ | 'date'
108
+ | 'datetime'
109
+ | 'json'
110
+ | 'markdown'
111
+ | 'url'
112
+
113
+ /**
114
+ * A field definition can be:
115
+ * - A primitive type: 'string', 'number', etc.
116
+ * - A relation: 'Author.posts' (Type.backref)
117
+ * - An array of primitives: 'string[]'
118
+ * - An array relation: ['Author.posts'] (many-to-many with backref)
119
+ * - Optional modifier: 'string?'
120
+ */
121
+ export type FieldDefinition = string | [string]
122
+
123
+ /**
124
+ * Schema for a single entity type
125
+ */
126
+ export type EntitySchema = Record<string, FieldDefinition>
127
+
128
+ /**
129
+ * Full database schema
130
+ */
131
+ export type DatabaseSchema = Record<string, EntitySchema>
132
+
133
+ // =============================================================================
134
+ // Parsed Schema Types
135
+ // =============================================================================
136
+
137
+ /**
138
+ * Parsed field information
139
+ */
140
+ export interface ParsedField {
141
+ name: string
142
+ type: string
143
+ isArray: boolean
144
+ isOptional: boolean
145
+ isRelation: boolean
146
+ relatedType?: string
147
+ backref?: string
148
+ }
149
+
150
+ /**
151
+ * Parsed entity with all fields including auto-generated backrefs
152
+ */
153
+ export interface ParsedEntity {
154
+ name: string
155
+ fields: Map<string, ParsedField>
156
+ }
157
+
158
+ /**
159
+ * Fully parsed schema with bi-directional relationships resolved
160
+ */
161
+ export interface ParsedSchema {
162
+ entities: Map<string, ParsedEntity>
163
+ }
164
+
165
+ // =============================================================================
166
+ // Noun & Verb - Semantic Types for Self-Documenting Schemas
167
+ // =============================================================================
168
+
169
+ /**
170
+ * Verb conjugations and related forms
171
+ *
172
+ * Maps an action to its various grammatical forms and semantic relationships.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const create: Verb = {
177
+ * action: 'create', // Base form (imperative)
178
+ * actor: 'creator', // Who does it (noun)
179
+ * act: 'creates', // Present tense (3rd person)
180
+ * activity: 'creating', // Gerund/continuous
181
+ * result: 'creation', // Result noun
182
+ * reverse: { // Passive/result properties
183
+ * at: 'createdAt',
184
+ * by: 'createdBy',
185
+ * in: 'createdIn',
186
+ * for: 'createdFor',
187
+ * },
188
+ * inverse: 'delete', // Opposite action
189
+ * }
190
+ * ```
191
+ */
192
+ export interface Verb {
193
+ /** Base form / imperative (create, update, delete, publish) */
194
+ action: string
195
+
196
+ /** Agent noun - who performs the action (creator, updater, author, publisher) */
197
+ actor?: string
198
+
199
+ /** Present tense 3rd person singular (creates, updates, deletes, publishes) */
200
+ act?: string
201
+
202
+ /** Present participle / gerund (creating, updating, deleting, publishing) */
203
+ activity?: string
204
+
205
+ /** Result noun - what is produced (creation, update, deletion, publication) */
206
+ result?: string
207
+
208
+ /** Reverse/passive forms - properties resulting from the action */
209
+ reverse?: {
210
+ /** Timestamp field (createdAt, updatedAt, deletedAt, publishedAt) */
211
+ at?: string
212
+ /** Actor reference (createdBy, updatedBy, deletedBy, publishedBy) */
213
+ by?: string
214
+ /** Location/context (createdIn, updatedIn, publishedIn) */
215
+ in?: string
216
+ /** Purpose/target (createdFor, publishedFor) */
217
+ for?: string
218
+ /** Additional reverse forms */
219
+ [key: string]: string | undefined
220
+ }
221
+
222
+ /** Inverse action (create ↔ delete, publish ↔ unpublish, activate ↔ deactivate) */
223
+ inverse?: string
224
+
225
+ /** Description of what this action does */
226
+ description?: string
227
+ }
228
+
229
+ /**
230
+ * Standard CRUD verbs with pre-defined conjugations
231
+ */
232
+ export const Verbs = {
233
+ create: {
234
+ action: 'create',
235
+ actor: 'creator',
236
+ act: 'creates',
237
+ activity: 'creating',
238
+ result: 'creation',
239
+ reverse: { at: 'createdAt', by: 'createdBy', in: 'createdIn', for: 'createdFor' },
240
+ inverse: 'delete',
241
+ },
242
+ update: {
243
+ action: 'update',
244
+ actor: 'updater',
245
+ act: 'updates',
246
+ activity: 'updating',
247
+ result: 'update',
248
+ reverse: { at: 'updatedAt', by: 'updatedBy' },
249
+ },
250
+ delete: {
251
+ action: 'delete',
252
+ actor: 'deleter',
253
+ act: 'deletes',
254
+ activity: 'deleting',
255
+ result: 'deletion',
256
+ reverse: { at: 'deletedAt', by: 'deletedBy' },
257
+ inverse: 'create',
258
+ },
259
+ publish: {
260
+ action: 'publish',
261
+ actor: 'publisher',
262
+ act: 'publishes',
263
+ activity: 'publishing',
264
+ result: 'publication',
265
+ reverse: { at: 'publishedAt', by: 'publishedBy' },
266
+ inverse: 'unpublish',
267
+ },
268
+ archive: {
269
+ action: 'archive',
270
+ actor: 'archiver',
271
+ act: 'archives',
272
+ activity: 'archiving',
273
+ result: 'archive',
274
+ reverse: { at: 'archivedAt', by: 'archivedBy' },
275
+ inverse: 'unarchive',
276
+ },
277
+ } as const satisfies Record<string, Verb>
278
+
279
+ /**
280
+ * Noun definition - semantic description of an entity type
281
+ *
282
+ * Describes a Thing with its properties, relationships, available actions,
283
+ * and metadata like singular/plural forms for natural language generation.
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * const Post: Noun = {
288
+ * singular: 'post',
289
+ * plural: 'posts',
290
+ * description: 'A blog post or article',
291
+ *
292
+ * properties: {
293
+ * title: { type: 'string', description: 'The post title' },
294
+ * content: { type: 'markdown', description: 'The post body' },
295
+ * status: { type: 'string', description: 'draft | published | archived' },
296
+ * },
297
+ *
298
+ * relationships: {
299
+ * author: { type: 'Author', backref: 'posts', description: 'Who wrote this' },
300
+ * tags: { type: 'Tag[]', backref: 'posts', description: 'Categorization' },
301
+ * },
302
+ *
303
+ * actions: ['create', 'update', 'delete', 'publish', 'archive'],
304
+ *
305
+ * events: ['created', 'updated', 'deleted', 'published', 'archived'],
306
+ * }
307
+ * ```
308
+ */
309
+ export interface Noun {
310
+ /** Singular form (post, user, category) */
311
+ singular: string
312
+
313
+ /** Plural form (posts, users, categories) */
314
+ plural: string
315
+
316
+ /** Human-readable description */
317
+ description?: string
318
+
319
+ /** Property definitions with descriptions */
320
+ properties?: Record<string, NounProperty>
321
+
322
+ /** Relationship definitions with descriptions */
323
+ relationships?: Record<string, NounRelationship>
324
+
325
+ /** Actions that can be performed on this noun (verbs) */
326
+ actions?: Array<string | Verb>
327
+
328
+ /** Events that can occur to this noun */
329
+ events?: string[]
330
+
331
+ /** Additional metadata */
332
+ metadata?: Record<string, unknown>
333
+ }
334
+
335
+ /**
336
+ * Property definition within a Noun
337
+ */
338
+ export interface NounProperty {
339
+ /** Field type */
340
+ type: PrimitiveType | string
341
+
342
+ /** Human-readable description (also used as generation prompt) */
343
+ description?: string
344
+
345
+ /** Whether the field is optional */
346
+ optional?: boolean
347
+
348
+ /** Whether the field is an array */
349
+ array?: boolean
350
+
351
+ /** Default value */
352
+ default?: unknown
353
+
354
+ /** Example values for documentation/generation */
355
+ examples?: unknown[]
356
+ }
357
+
358
+ /**
359
+ * Relationship definition within a Noun
360
+ */
361
+ export interface NounRelationship {
362
+ /** Related entity type (e.g., 'Author', 'Tag[]') */
363
+ type: string
364
+
365
+ /** Backref field name on the related entity */
366
+ backref?: string
367
+
368
+ /** Human-readable description */
369
+ description?: string
370
+
371
+ /** Whether this is a required relationship */
372
+ required?: boolean
373
+ }
374
+
375
+ /**
376
+ * Type metadata - automatically inferred from type name
377
+ *
378
+ * Available on every entity via `entity.$type` or `db.Post.$meta`
379
+ */
380
+ export interface TypeMeta {
381
+ /** Type name as defined in schema (e.g., 'Post', 'BlogPost') */
382
+ name: string
383
+ /** Singular form (e.g., 'post', 'blog post') */
384
+ singular: string
385
+ /** Plural form (e.g., 'posts', 'blog posts') */
386
+ plural: string
387
+ /** URL-safe slug (e.g., 'post', 'blog-post') */
388
+ slug: string
389
+ /** Plural slug (e.g., 'posts', 'blog-posts') */
390
+ slugPlural: string
391
+
392
+ // Verb-derived accessors
393
+ /** Creator relationship name */
394
+ creator: string
395
+ /** Created timestamp field */
396
+ createdAt: string
397
+ /** Created by field */
398
+ createdBy: string
399
+ /** Updated timestamp field */
400
+ updatedAt: string
401
+ /** Updated by field */
402
+ updatedBy: string
403
+
404
+ // Event types
405
+ /** Event type for creation (e.g., 'Post.created') */
406
+ created: string
407
+ /** Event type for update (e.g., 'Post.updated') */
408
+ updated: string
409
+ /** Event type for deletion (e.g., 'Post.deleted') */
410
+ deleted: string
411
+ }
412
+
413
+ // =============================================================================
414
+ // Graph Database Types (Entity-Relationship Model)
415
+ // =============================================================================
416
+
417
+ /**
418
+ * Base identifier for all entities (URL-centric)
419
+ */
420
+ export interface EntityId {
421
+ /** Namespace (e.g., 'example.com', 'api.mdx.org.ai') */
422
+ ns: string
423
+ /** Type of the entity (e.g., 'user', 'post', 'comment') */
424
+ type: string
425
+ /** Unique identifier within the namespace and type */
426
+ id: string
427
+ /**
428
+ * Full URL for the entity
429
+ * Defaults to https://{ns}/{type}/{id}
430
+ */
431
+ url?: string
432
+ }
433
+
434
+ /**
435
+ * A Thing is a node in the database (linked data style)
436
+ */
437
+ export interface Thing<T extends Record<string, unknown> = Record<string, unknown>> extends EntityId {
438
+ /** When the thing was created */
439
+ createdAt: Date
440
+ /** When the thing was last updated */
441
+ updatedAt: Date
442
+ /** Arbitrary properties */
443
+ data: T
444
+ /** JSON-LD context (optional) */
445
+ '@context'?: string | Record<string, unknown>
446
+ }
447
+
448
+ /**
449
+ * Relationship between two things (graph edge)
450
+ */
451
+ export interface Relationship<T extends Record<string, unknown> = Record<string, unknown>> {
452
+ /** Unique identifier for the relationship */
453
+ id: string
454
+ /** Type of relationship (any string) */
455
+ type: string
456
+ /** Source thing URL */
457
+ from: string
458
+ /** Target thing URL */
459
+ to: string
460
+ /** When the relationship was created */
461
+ createdAt: Date
462
+ /** Optional relationship metadata */
463
+ data?: T
464
+ }
465
+
466
+ /**
467
+ * Resolve the URL for an entity
468
+ */
469
+ export function resolveUrl(entity: EntityId): string {
470
+ if (entity.url) return entity.url
471
+ return `https://${entity.ns}/${entity.type}/${entity.id}`
472
+ }
473
+
474
+ /**
475
+ * Resolve URL with just ns/id (no type in path)
476
+ */
477
+ export function resolveShortUrl(entity: Pick<EntityId, 'ns' | 'id'>): string {
478
+ return `https://${entity.ns}/${entity.id}`
479
+ }
480
+
481
+ /**
482
+ * Parse a URL into EntityId components
483
+ */
484
+ export function parseUrl(url: string): EntityId {
485
+ const parsed = new URL(url)
486
+ const parts = parsed.pathname.split('/').filter(Boolean)
487
+
488
+ if (parts.length === 1) {
489
+ return {
490
+ ns: parsed.host,
491
+ type: '',
492
+ id: parts[0]!,
493
+ url
494
+ }
495
+ }
496
+
497
+ if (parts.length >= 2) {
498
+ return {
499
+ ns: parsed.host,
500
+ type: parts[0]!,
501
+ id: parts.slice(1).join('/'),
502
+ url
503
+ }
504
+ }
505
+
506
+ throw new Error(`Invalid entity URL: ${url}`)
507
+ }
508
+
509
+ // =============================================================================
510
+ // Query & Options Types
511
+ // =============================================================================
512
+
513
+ /**
514
+ * Query options for finding things
515
+ */
516
+ export interface QueryOptions {
517
+ /** Filter by namespace */
518
+ ns?: string
519
+ /** Filter by type */
520
+ type?: string
521
+ /** Filter by properties (exact match) */
522
+ where?: Record<string, unknown>
523
+ /** Order by field */
524
+ orderBy?: string
525
+ /** Order direction */
526
+ order?: 'asc' | 'desc'
527
+ /** Limit results */
528
+ limit?: number
529
+ /** Skip results (for pagination) */
530
+ offset?: number
531
+ }
532
+
533
+ /**
534
+ * Search options for semantic/text search
535
+ */
536
+ export interface ThingSearchOptions extends QueryOptions {
537
+ /** The search query */
538
+ query: string
539
+ /** Fields to search in */
540
+ fields?: string[]
541
+ /** Minimum relevance score (0-1) */
542
+ minScore?: number
543
+ }
544
+
545
+ /**
546
+ * Options for creating a thing
547
+ */
548
+ export interface CreateOptions<T extends Record<string, unknown>> {
549
+ /** Namespace */
550
+ ns: string
551
+ /** Type of the thing */
552
+ type: string
553
+ /** ID (auto-generated if not provided) */
554
+ id?: string
555
+ /** Custom URL (auto-generated if not provided) */
556
+ url?: string
557
+ /** Initial data */
558
+ data: T
559
+ /** JSON-LD context */
560
+ '@context'?: string | Record<string, unknown>
561
+ }
562
+
563
+ /**
564
+ * Options for updating a thing
565
+ */
566
+ export interface UpdateOptions<T extends Record<string, unknown>> {
567
+ /** Partial data to merge */
568
+ data: Partial<T>
569
+ }
570
+
571
+ /**
572
+ * Options for creating a relationship
573
+ */
574
+ export interface RelateOptions<T extends Record<string, unknown> = Record<string, unknown>> {
575
+ /** Type of relationship */
576
+ type: string
577
+ /** Source thing URL */
578
+ from: string
579
+ /** Target thing URL */
580
+ to: string
581
+ /** Optional relationship data */
582
+ data?: T
583
+ }
584
+
585
+ // =============================================================================
586
+ // Event, Action, Artifact Types (for workflow integration)
587
+ // =============================================================================
588
+
589
+ /**
590
+ * Immutable event record
591
+ */
592
+ export interface Event<T extends Record<string, unknown> = Record<string, unknown>> {
593
+ /** Unique identifier for the event */
594
+ id: string
595
+ /** Event type (e.g., 'Customer.created', 'Order.completed') */
596
+ type: string
597
+ /** When the event occurred */
598
+ timestamp: Date
599
+ /** Event source (workflow, user, system) */
600
+ source: string
601
+ /** Event data payload */
602
+ data: T
603
+ /** Optional correlation ID for tracing related events */
604
+ correlationId?: string
605
+ /** Optional causation ID (the event that caused this event) */
606
+ causationId?: string
607
+ }
608
+
609
+ /**
610
+ * Action status
611
+ */
612
+ export type ActionStatus = 'pending' | 'active' | 'completed' | 'failed' | 'cancelled'
613
+
614
+ /**
615
+ * Action record for pending/active work
616
+ */
617
+ export interface Action<T extends Record<string, unknown> = Record<string, unknown>> {
618
+ /** Unique identifier for the action */
619
+ id: string
620
+ /** Actor performing the action (user URL, agent ID, 'system') */
621
+ actor: string
622
+ /** Object being acted upon (thing URL) */
623
+ object: string
624
+ /** Action type (e.g., 'approve', 'process', 'review') */
625
+ action: string
626
+ /** Current status */
627
+ status: ActionStatus
628
+ /** When the action was created */
629
+ createdAt: Date
630
+ /** When the action was last updated */
631
+ updatedAt: Date
632
+ /** When the action started (status became 'active') */
633
+ startedAt?: Date
634
+ /** When the action completed or failed */
635
+ completedAt?: Date
636
+ /** Result of the action (when completed) */
637
+ result?: unknown
638
+ /** Error message (when failed) */
639
+ error?: string
640
+ /** Additional action metadata */
641
+ metadata?: T
642
+ }
643
+
644
+ /**
645
+ * Artifact type
646
+ */
647
+ export type ArtifactType = 'ast' | 'types' | 'esm' | 'cjs' | 'worker' | 'html' | 'markdown' | 'bundle' | 'sourcemap' | string
648
+
649
+ /**
650
+ * Cached artifact for compiled/parsed content
651
+ */
652
+ export interface Artifact<T = unknown> {
653
+ /** Unique key for the artifact (usually source URL + artifact type) */
654
+ key: string
655
+ /** Type of artifact */
656
+ type: ArtifactType
657
+ /** Source URL or identifier */
658
+ source: string
659
+ /** Hash of the source content (for cache invalidation) */
660
+ sourceHash: string
661
+ /** When the artifact was created */
662
+ createdAt: Date
663
+ /** When the artifact expires (optional TTL) */
664
+ expiresAt?: Date
665
+ /** The artifact content */
666
+ content: T
667
+ /** Content size in bytes */
668
+ size?: number
669
+ /** Additional metadata */
670
+ metadata?: Record<string, unknown>
671
+ }
672
+
673
+ /**
674
+ * Options for creating an event
675
+ */
676
+ export interface CreateEventOptions<T extends Record<string, unknown>> {
677
+ /** Event type */
678
+ type: string
679
+ /** Event source */
680
+ source: string
681
+ /** Event data */
682
+ data: T
683
+ /** Optional correlation ID */
684
+ correlationId?: string
685
+ /** Optional causation ID */
686
+ causationId?: string
687
+ }
688
+
689
+ /**
690
+ * Options for creating an action
691
+ */
692
+ export interface CreateActionOptions<T extends Record<string, unknown> = Record<string, unknown>> {
693
+ /** Actor performing the action */
694
+ actor: string
695
+ /** Object being acted upon */
696
+ object: string
697
+ /** Action type */
698
+ action: string
699
+ /** Initial status (defaults to 'pending') */
700
+ status?: ActionStatus
701
+ /** Additional metadata */
702
+ metadata?: T
703
+ }
704
+
705
+ /**
706
+ * Options for storing an artifact
707
+ */
708
+ export interface StoreArtifactOptions<T = unknown> {
709
+ /** Unique key for the artifact */
710
+ key: string
711
+ /** Type of artifact */
712
+ type: ArtifactType
713
+ /** Source URL or identifier */
714
+ source: string
715
+ /** Hash of the source content */
716
+ sourceHash: string
717
+ /** The artifact content */
718
+ content: T
719
+ /** TTL in milliseconds (optional) */
720
+ ttl?: number
721
+ /** Additional metadata */
722
+ metadata?: Record<string, unknown>
723
+ }
724
+
725
+ /**
726
+ * Event query options
727
+ */
728
+ export interface EventQueryOptions {
729
+ /** Filter by event type */
730
+ type?: string
731
+ /** Filter by source */
732
+ source?: string
733
+ /** Filter by correlation ID */
734
+ correlationId?: string
735
+ /** Events after this timestamp */
736
+ after?: Date
737
+ /** Events before this timestamp */
738
+ before?: Date
739
+ /** Maximum number of events to return */
740
+ limit?: number
741
+ /** Offset for pagination */
742
+ offset?: number
743
+ }
744
+
745
+ /**
746
+ * Action query options
747
+ */
748
+ export interface ActionQueryOptions {
749
+ /** Filter by actor */
750
+ actor?: string
751
+ /** Filter by object */
752
+ object?: string
753
+ /** Filter by action type */
754
+ action?: string
755
+ /** Filter by status */
756
+ status?: ActionStatus | ActionStatus[]
757
+ /** Maximum number of actions to return */
758
+ limit?: number
759
+ /** Offset for pagination */
760
+ offset?: number
761
+ }
762
+
763
+ // =============================================================================
764
+ // Database Client Interfaces
765
+ // =============================================================================
766
+
767
+ /**
768
+ * Database client interface for graph operations
769
+ */
770
+ export interface DBClient<TData extends Record<string, unknown> = Record<string, unknown>> {
771
+ // Thing operations
772
+ list(options?: QueryOptions): Promise<Thing<TData>[]>
773
+ find(options: QueryOptions): Promise<Thing<TData>[]>
774
+ search(options: ThingSearchOptions): Promise<Thing<TData>[]>
775
+ get(url: string): Promise<Thing<TData> | null>
776
+ getById(ns: string, type: string, id: string): Promise<Thing<TData> | null>
777
+ set(url: string, data: TData): Promise<Thing<TData>>
778
+ create(options: CreateOptions<TData>): Promise<Thing<TData>>
779
+ update(url: string, options: UpdateOptions<TData>): Promise<Thing<TData>>
780
+ upsert(options: CreateOptions<TData>): Promise<Thing<TData>>
781
+ delete(url: string): Promise<boolean>
782
+
783
+ // Iteration
784
+ forEach(
785
+ options: QueryOptions,
786
+ callback: (thing: Thing<TData>) => void | Promise<void>
787
+ ): Promise<void>
788
+
789
+ // Relationship operations (outbound)
790
+ relate<T extends Record<string, unknown> = Record<string, unknown>>(
791
+ options: RelateOptions<T>
792
+ ): Promise<Relationship<T>>
793
+ unrelate(from: string, type: string, to: string): Promise<boolean>
794
+ related(
795
+ url: string,
796
+ relationshipType?: string,
797
+ direction?: 'from' | 'to' | 'both'
798
+ ): Promise<Thing<TData>[]>
799
+ relationships(
800
+ url: string,
801
+ type?: string,
802
+ direction?: 'from' | 'to' | 'both'
803
+ ): Promise<Relationship[]>
804
+
805
+ // Reference operations (inbound - backlinks)
806
+ references(
807
+ url: string,
808
+ relationshipType?: string
809
+ ): Promise<Thing<TData>[]>
810
+
811
+ // Cleanup
812
+ close?(): Promise<void>
813
+ }
814
+
815
+ /**
816
+ * Extended DBClient with Events, Actions, and Artifacts
817
+ */
818
+ export interface DBClientExtended<TData extends Record<string, unknown> = Record<string, unknown>> extends DBClient<TData> {
819
+ // Event operations (immutable, append-only)
820
+ /** Track an event (analytics-style, append-only) */
821
+ track<T extends Record<string, unknown>>(options: CreateEventOptions<T>): Promise<Event<T>>
822
+ getEvent(id: string): Promise<Event | null>
823
+ queryEvents(options?: EventQueryOptions): Promise<Event[]>
824
+
825
+ // Action operations ($.do, $.try, $.send patterns)
826
+ /** Send an action (fire-and-forget, creates in pending state) */
827
+ send<T extends Record<string, unknown>>(options: CreateActionOptions<T>): Promise<Action<T>>
828
+ /** Do an action (create and immediately start, returns in active state) */
829
+ do<T extends Record<string, unknown>>(options: CreateActionOptions<T>): Promise<Action<T>>
830
+ /** Try an action (with built-in error handling) */
831
+ try<T extends Record<string, unknown>>(options: CreateActionOptions<T>, fn: () => Promise<unknown>): Promise<Action<T>>
832
+ getAction(id: string): Promise<Action | null>
833
+ queryActions(options?: ActionQueryOptions): Promise<Action[]>
834
+ startAction(id: string): Promise<Action>
835
+ completeAction(id: string, result?: unknown): Promise<Action>
836
+ failAction(id: string, error: string): Promise<Action>
837
+ cancelAction(id: string): Promise<Action>
838
+
839
+ // Artifact operations (cached content)
840
+ storeArtifact<T>(options: StoreArtifactOptions<T>): Promise<Artifact<T>>
841
+ getArtifact<T = unknown>(key: string): Promise<Artifact<T> | null>
842
+ getArtifactBySource(source: string, type: ArtifactType): Promise<Artifact | null>
843
+ deleteArtifact(key: string): Promise<boolean>
844
+ cleanExpiredArtifacts(): Promise<number>
845
+ }
846
+
847
+ // =============================================================================
848
+ // Document Database Types (for @mdxdb adapters)
849
+ // =============================================================================
850
+ // These types are for document-based storage (MDX files with frontmatter)
851
+ // as opposed to the graph-based DBClient types above.
852
+
853
+ /**
854
+ * Query options for listing documents
855
+ */
856
+ export interface DocListOptions {
857
+ /** Maximum number of documents to return */
858
+ limit?: number
859
+ /** Number of documents to skip */
860
+ offset?: number
861
+ /** Field to sort by */
862
+ sortBy?: string
863
+ /** Sort order */
864
+ sortOrder?: 'asc' | 'desc'
865
+ /** Filter by type */
866
+ type?: string | string[]
867
+ /** Filter by path prefix */
868
+ prefix?: string
869
+ }
870
+
871
+ /**
872
+ * Document with optional score for search results
873
+ */
874
+ export interface DocWithScore<TData = Record<string, unknown>> {
875
+ /** Document ID/path */
876
+ id?: string
877
+ /** Document type */
878
+ type?: string
879
+ /** JSON-LD context */
880
+ context?: string | Record<string, unknown>
881
+ /** Document data (frontmatter) */
882
+ data: TData
883
+ /** Document content (markdown body) */
884
+ content: string
885
+ /** Relevance score (for search results) */
886
+ score?: number
887
+ }
888
+
889
+ /**
890
+ * Query result with pagination info
891
+ */
892
+ export interface DocListResult<TData = Record<string, unknown>> {
893
+ /** List of documents */
894
+ documents: DocWithScore<TData>[]
895
+ /** Total count of matching documents */
896
+ total: number
897
+ /** Whether there are more results */
898
+ hasMore: boolean
899
+ }
900
+
901
+ /**
902
+ * Search options for querying documents
903
+ */
904
+ export interface DocSearchOptions extends DocListOptions {
905
+ /** Search query string */
906
+ query: string
907
+ /** Fields to search in */
908
+ fields?: string[]
909
+ /** Enable semantic/vector search */
910
+ semantic?: boolean
911
+ }
912
+
913
+ /**
914
+ * Search result with relevance info
915
+ */
916
+ export interface DocSearchResult<TData = Record<string, unknown>> extends DocListResult<TData> {
917
+ /** Documents with relevance scores */
918
+ documents: Array<DocWithScore<TData> & { score?: number }>
919
+ }
920
+
921
+ /**
922
+ * Get options for retrieving a document
923
+ */
924
+ export interface DocGetOptions {
925
+ /** Include AST in response */
926
+ includeAst?: boolean
927
+ /** Include compiled code in response */
928
+ includeCode?: boolean
929
+ }
930
+
931
+ /**
932
+ * Set options for storing a document
933
+ */
934
+ export interface DocSetOptions {
935
+ /** Create only if document doesn't exist */
936
+ createOnly?: boolean
937
+ /** Update only if document exists */
938
+ updateOnly?: boolean
939
+ /** Expected version for optimistic locking */
940
+ version?: string
941
+ }
942
+
943
+ /**
944
+ * Set result with metadata
945
+ */
946
+ export interface DocSetResult {
947
+ /** Document ID/path */
948
+ id: string
949
+ /** New version after update */
950
+ version?: string
951
+ /** Whether document was created (vs updated) */
952
+ created: boolean
953
+ }
954
+
955
+ /**
956
+ * Delete options
957
+ */
958
+ export interface DocDeleteOptions {
959
+ /** Soft delete (mark as deleted) */
960
+ soft?: boolean
961
+ /** Expected version for optimistic locking */
962
+ version?: string
963
+ }
964
+
965
+ /**
966
+ * Delete result
967
+ */
968
+ export interface DocDeleteResult {
969
+ /** Document ID/path that was deleted */
970
+ id: string
971
+ /** Whether document was found and deleted */
972
+ deleted: boolean
973
+ }
974
+
975
+ /**
976
+ * Document interface for MDX document storage
977
+ *
978
+ * Generic document type for CRUD operations on MDX content.
979
+ * Used as input/output for DocumentDatabase operations.
980
+ */
981
+ export interface Document<TData = Record<string, unknown>> {
982
+ /** Document ID/path */
983
+ id?: string
984
+ /** Document type ($type) */
985
+ type?: string
986
+ /** JSON-LD context ($context) */
987
+ context?: string | Record<string, unknown>
988
+ /** Document data (frontmatter fields) */
989
+ data: TData
990
+ /** Document content (markdown body) */
991
+ content: string
992
+ }
993
+
994
+ /**
995
+ * Database interface for MDX document storage
996
+ *
997
+ * All backend adapters (fs, sqlite, postgres, api, etc.) implement this interface.
998
+ * Works in any JavaScript runtime (Node.js, Bun, Deno, Workers, Browser).
999
+ *
1000
+ * @example
1001
+ * ```ts
1002
+ * // Using filesystem adapter
1003
+ * import { createFsDatabase } from '@mdxdb/fs'
1004
+ * const db = createFsDatabase({ root: './content' })
1005
+ *
1006
+ * // Using API adapter
1007
+ * import { createApiDatabase } from '@mdxdb/api'
1008
+ * const db = createApiDatabase({ baseUrl: 'https://api.example.com' })
1009
+ *
1010
+ * // Same interface regardless of backend
1011
+ * const doc = await db.get('posts/hello-world')
1012
+ * ```
1013
+ */
1014
+ export interface DocumentDatabase<TData = Record<string, unknown>> {
1015
+ /**
1016
+ * List documents with optional filtering and pagination
1017
+ */
1018
+ list(options?: DocListOptions): Promise<DocListResult<TData>>
1019
+
1020
+ /**
1021
+ * Search documents by query
1022
+ */
1023
+ search(options: DocSearchOptions): Promise<DocSearchResult<TData>>
1024
+
1025
+ /**
1026
+ * Get a document by ID/path
1027
+ */
1028
+ get(id: string, options?: DocGetOptions): Promise<Document<TData> | null>
1029
+
1030
+ /**
1031
+ * Set/create a document
1032
+ */
1033
+ set(id: string, document: Document<TData>, options?: DocSetOptions): Promise<DocSetResult>
1034
+
1035
+ /**
1036
+ * Delete a document
1037
+ */
1038
+ delete(id: string, options?: DocDeleteOptions): Promise<DocDeleteResult>
1039
+
1040
+ /**
1041
+ * Close database connection (for cleanup)
1042
+ */
1043
+ close?(): Promise<void>
1044
+ }
1045
+
1046
+ /**
1047
+ * Database configuration base
1048
+ */
1049
+ export interface DocumentDatabaseConfig {
1050
+ /** Optional namespace/prefix for all operations */
1051
+ namespace?: string
1052
+ }
1053
+
1054
+ /**
1055
+ * Factory function type for creating database instances
1056
+ */
1057
+ export type CreateDocumentDatabase<
1058
+ TConfig extends DocumentDatabaseConfig = DocumentDatabaseConfig,
1059
+ TData = Record<string, unknown>
1060
+ > = (config: TConfig) => DocumentDatabase<TData>
1061
+
1062
+ // =============================================================================
1063
+ // View Types - For bi-directional relationship rendering/extraction
1064
+ // =============================================================================
1065
+
1066
+ /**
1067
+ * Entity item with standard fields (for views)
1068
+ */
1069
+ export interface ViewEntityItem {
1070
+ /** Entity ID (URL or slug) */
1071
+ $id: string
1072
+ /** Entity type */
1073
+ $type?: string
1074
+ /** Entity data fields */
1075
+ [key: string]: unknown
1076
+ }
1077
+
1078
+ /**
1079
+ * View component definition
1080
+ */
1081
+ export interface ViewComponent {
1082
+ /** Component name (e.g., 'Tags', 'Posts') */
1083
+ name: string
1084
+ /** Entity type this component renders */
1085
+ entityType?: string
1086
+ /** Relationship predicate */
1087
+ relationship?: string
1088
+ /** Default columns to render */
1089
+ columns?: string[]
1090
+ /** Render format */
1091
+ format?: 'table' | 'list' | 'cards'
1092
+ }
1093
+
1094
+ /**
1095
+ * A View document is a template that renders related entities
1096
+ */
1097
+ export interface ViewDocument {
1098
+ /** View template ID */
1099
+ id: string
1100
+ /** Entity type this view is for */
1101
+ entityType: string
1102
+ /** The template content */
1103
+ template: string
1104
+ /** Components discovered in the template */
1105
+ components: ViewComponent[]
1106
+ }
1107
+
1108
+ /**
1109
+ * Context for rendering a view
1110
+ */
1111
+ export interface ViewContext {
1112
+ /** The entity URL this view is being rendered for */
1113
+ entityUrl: string
1114
+ /** Optional filters to apply */
1115
+ filters?: Record<string, unknown>
1116
+ }
1117
+
1118
+ /**
1119
+ * Result of rendering a view
1120
+ */
1121
+ export interface ViewRenderResult {
1122
+ /** The rendered markdown */
1123
+ markdown: string
1124
+ /** Entities that were rendered */
1125
+ entities: Record<string, ViewEntityItem[]>
1126
+ }
1127
+
1128
+ /**
1129
+ * Relationship mutation from view extraction
1130
+ */
1131
+ export interface ViewRelationshipMutation {
1132
+ /** Mutation type */
1133
+ type: 'add' | 'remove' | 'update'
1134
+ /** Relationship predicate */
1135
+ predicate: string
1136
+ /** Source entity URL */
1137
+ from: string
1138
+ /** Target entity URL */
1139
+ to: string
1140
+ /** Entity data */
1141
+ data?: Record<string, unknown>
1142
+ /** Previous entity data */
1143
+ previousData?: Record<string, unknown>
1144
+ }
1145
+
1146
+ /**
1147
+ * Result of syncing changes from an edited view
1148
+ */
1149
+ export interface ViewSyncResult {
1150
+ /** Relationship mutations to apply */
1151
+ mutations: ViewRelationshipMutation[]
1152
+ /** Entities that were created */
1153
+ created: ViewEntityItem[]
1154
+ /** Entities that were updated */
1155
+ updated: ViewEntityItem[]
1156
+ }
1157
+
1158
+ /**
1159
+ * View manager interface
1160
+ */
1161
+ export interface ViewManager {
1162
+ discoverViews(): Promise<ViewDocument[]>
1163
+ getView(viewId: string): Promise<ViewDocument | null>
1164
+ render(viewId: string, context: ViewContext): Promise<ViewRenderResult>
1165
+ sync(viewId: string, context: ViewContext, editedMarkdown: string): Promise<ViewSyncResult>
1166
+ inferRelationship(
1167
+ contextType: string,
1168
+ componentName: string
1169
+ ): Promise<{ predicate: string; direction: 'forward' | 'reverse' } | null>
1170
+ }
1171
+
1172
+ /**
1173
+ * Extended DocumentDatabase interface with view support
1174
+ */
1175
+ export interface DocumentDatabaseWithViews<TData = Record<string, unknown>> extends DocumentDatabase<TData> {
1176
+ views: ViewManager
1177
+ }