digital-objects 1.0.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 (87) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +25 -0
  3. package/LICENSE +21 -0
  4. package/README.md +476 -0
  5. package/dist/ai-database-adapter.d.ts +49 -0
  6. package/dist/ai-database-adapter.d.ts.map +1 -0
  7. package/dist/ai-database-adapter.js +89 -0
  8. package/dist/ai-database-adapter.js.map +1 -0
  9. package/dist/errors.d.ts +47 -0
  10. package/dist/errors.d.ts.map +1 -0
  11. package/dist/errors.js +72 -0
  12. package/dist/errors.js.map +1 -0
  13. package/dist/http-schemas.d.ts +165 -0
  14. package/dist/http-schemas.d.ts.map +1 -0
  15. package/dist/http-schemas.js +55 -0
  16. package/dist/http-schemas.js.map +1 -0
  17. package/dist/index.d.ts +29 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +32 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/linguistic.d.ts +54 -0
  22. package/dist/linguistic.d.ts.map +1 -0
  23. package/dist/linguistic.js +226 -0
  24. package/dist/linguistic.js.map +1 -0
  25. package/dist/memory-provider.d.ts +46 -0
  26. package/dist/memory-provider.d.ts.map +1 -0
  27. package/dist/memory-provider.js +279 -0
  28. package/dist/memory-provider.js.map +1 -0
  29. package/dist/ns-client.d.ts +88 -0
  30. package/dist/ns-client.d.ts.map +1 -0
  31. package/dist/ns-client.js +253 -0
  32. package/dist/ns-client.js.map +1 -0
  33. package/dist/ns-exports.d.ts +23 -0
  34. package/dist/ns-exports.d.ts.map +1 -0
  35. package/dist/ns-exports.js +21 -0
  36. package/dist/ns-exports.js.map +1 -0
  37. package/dist/ns.d.ts +60 -0
  38. package/dist/ns.d.ts.map +1 -0
  39. package/dist/ns.js +818 -0
  40. package/dist/ns.js.map +1 -0
  41. package/dist/r2-persistence.d.ts +112 -0
  42. package/dist/r2-persistence.d.ts.map +1 -0
  43. package/dist/r2-persistence.js +252 -0
  44. package/dist/r2-persistence.js.map +1 -0
  45. package/dist/schema-validation.d.ts +80 -0
  46. package/dist/schema-validation.d.ts.map +1 -0
  47. package/dist/schema-validation.js +233 -0
  48. package/dist/schema-validation.js.map +1 -0
  49. package/dist/types.d.ts +184 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +26 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +55 -0
  54. package/src/ai-database-adapter.test.ts +610 -0
  55. package/src/ai-database-adapter.ts +189 -0
  56. package/src/benchmark.test.ts +109 -0
  57. package/src/errors.ts +91 -0
  58. package/src/http-schemas.ts +67 -0
  59. package/src/index.ts +87 -0
  60. package/src/linguistic.test.ts +1107 -0
  61. package/src/linguistic.ts +253 -0
  62. package/src/memory-provider.ts +470 -0
  63. package/src/ns-client.test.ts +1360 -0
  64. package/src/ns-client.ts +342 -0
  65. package/src/ns-exports.ts +23 -0
  66. package/src/ns.test.ts +1381 -0
  67. package/src/ns.ts +1215 -0
  68. package/src/provider.test.ts +675 -0
  69. package/src/r2-persistence.test.ts +263 -0
  70. package/src/r2-persistence.ts +367 -0
  71. package/src/schema-validation.test.ts +167 -0
  72. package/src/schema-validation.ts +330 -0
  73. package/src/types.ts +252 -0
  74. package/test/action-status.test.ts +42 -0
  75. package/test/batch-limits.test.ts +165 -0
  76. package/test/docs.test.ts +48 -0
  77. package/test/errors.test.ts +148 -0
  78. package/test/http-validation.test.ts +401 -0
  79. package/test/ns-client-errors.test.ts +208 -0
  80. package/test/ns-namespace.test.ts +307 -0
  81. package/test/performance.test.ts +168 -0
  82. package/test/schema-validation-error.test.ts +213 -0
  83. package/test/schema-validation.test.ts +440 -0
  84. package/test/search-escaping.test.ts +359 -0
  85. package/test/security.test.ts +322 -0
  86. package/tsconfig.json +10 -0
  87. package/wrangler.jsonc +16 -0
@@ -0,0 +1,4 @@
1
+
2
+ > digital-objects@0.1.0 build /Users/nathanclevenger/projects/primitives.org.ai/packages/digital-objects
3
+ > tsc -p tsconfig.json
4
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## [1.0.0] - 2026-01-15
4
+
5
+ ### Added
6
+ - Core model: Nouns, Verbs, Things, Actions
7
+ - MemoryProvider for in-memory storage
8
+ - NS Durable Object with SQLite persistence
9
+ - NSClient HTTP client
10
+ - R2 persistence (snapshots, WAL, JSONL)
11
+ - ai-database adapter (DBProvider interface)
12
+ - Schema validation with opt-in validation
13
+ - Batch operations (createMany, updateMany, deleteMany, performMany)
14
+ - Graph traversal (related, edges)
15
+ - Linguistic derivation (pluralization, verb conjugation)
16
+ - Query limits (DEFAULT_LIMIT=100, MAX_LIMIT=1000)
17
+ - Custom error classes (NotFoundError, ValidationError, ConflictError)
18
+
19
+ ### Security
20
+ - SQL injection prevention with orderBy validation
21
+ - GDPR compliance with deleteAction support
22
+
23
+ ### Documentation
24
+ - Comprehensive MDX documentation in content/digital-objects/
25
+ - README with quick start and examples
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 .org.ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,476 @@
1
+ # digital-objects
2
+
3
+ Unified storage primitive for AI primitives - a linguistically-aware entity and graph system.
4
+
5
+ > **Documentation:** For comprehensive guides and examples, see the [Digital Objects documentation](https://primitives.org.ai/digital-objects).
6
+
7
+ ## Overview
8
+
9
+ `digital-objects` provides a coherent model for defining and managing entities (nouns/things) and relationships (verbs/actions). It automatically derives linguistic forms (pluralization, verb conjugation) and unifies events, graph edges, and audit trails into a single "action" concept.
10
+
11
+ ## Core Concepts
12
+
13
+ ### Nouns and Things
14
+
15
+ **Nouns** define entity types. **Things** are instances of nouns.
16
+
17
+ ```typescript
18
+ import { createMemoryProvider } from 'digital-objects'
19
+
20
+ const provider = createMemoryProvider()
21
+
22
+ // Define a noun (entity type)
23
+ const postNoun = await provider.defineNoun({
24
+ name: 'Post',
25
+ description: 'A blog post',
26
+ schema: {
27
+ title: 'string',
28
+ body: 'markdown',
29
+ publishedAt: 'datetime?',
30
+ },
31
+ })
32
+
33
+ // Linguistic forms are auto-derived:
34
+ // postNoun.singular = 'post'
35
+ // postNoun.plural = 'posts'
36
+ // postNoun.slug = 'post'
37
+
38
+ // Create a thing (entity instance)
39
+ const post = await provider.create('Post', {
40
+ title: 'Hello World',
41
+ body: '# Welcome\n\nThis is my first post.',
42
+ })
43
+ ```
44
+
45
+ ### Verbs and Actions
46
+
47
+ **Verbs** define action types. **Actions** represent events, graph edges, and audit records - unified.
48
+
49
+ ```typescript
50
+ // Define a verb
51
+ const publishVerb = await provider.defineVerb({
52
+ name: 'publish',
53
+ inverse: 'unpublish',
54
+ })
55
+
56
+ // Conjugations are auto-derived:
57
+ // publishVerb.action = 'publish' (imperative)
58
+ // publishVerb.act = 'publishes' (3rd person)
59
+ // publishVerb.activity = 'publishing' (gerund)
60
+ // publishVerb.event = 'published' (past participle)
61
+ // publishVerb.reverseBy = 'publishedBy'
62
+ // publishVerb.reverseAt = 'publishedAt'
63
+
64
+ // Perform an action (creates an event + edge)
65
+ const action = await provider.perform(
66
+ 'publish', // verb
67
+ author.id, // subject (who/from)
68
+ post.id, // object (what/to)
69
+ { featured: true } // metadata
70
+ )
71
+ ```
72
+
73
+ ### Actions as Graph Edges
74
+
75
+ Actions form a directed graph. Use `related()` and `edges()` for traversal:
76
+
77
+ ```typescript
78
+ // Get all things this author has published
79
+ const publishedPosts = await provider.related(author.id, 'publish', 'out')
80
+
81
+ // Get who published this post
82
+ const publishers = await provider.related(post.id, 'publish', 'in')
83
+
84
+ // Get all relationships (both directions)
85
+ const allRelated = await provider.related(post.id, undefined, 'both')
86
+
87
+ // Get edge details (the actions themselves)
88
+ const publishActions = await provider.edges(author.id, 'publish', 'out')
89
+ ```
90
+
91
+ ## Linguistic Derivation
92
+
93
+ The package automatically derives linguistic forms from base words.
94
+
95
+ ### Noun Derivation
96
+
97
+ ```typescript
98
+ import { deriveNoun, pluralize, singularize } from 'digital-objects'
99
+
100
+ deriveNoun('Post') // { singular: 'post', plural: 'posts', slug: 'post' }
101
+ deriveNoun('BlogPost') // { singular: 'blog post', plural: 'blog posts', slug: 'blog-post' }
102
+ deriveNoun('Person') // { singular: 'person', plural: 'people', slug: 'person' }
103
+
104
+ pluralize('category') // 'categories'
105
+ pluralize('child') // 'children'
106
+ singularize('posts') // 'post'
107
+ ```
108
+
109
+ ### Verb Derivation
110
+
111
+ ```typescript
112
+ import { deriveVerb } from 'digital-objects'
113
+
114
+ deriveVerb('create')
115
+ // {
116
+ // action: 'create',
117
+ // act: 'creates',
118
+ // activity: 'creating',
119
+ // event: 'created',
120
+ // reverseBy: 'createdBy',
121
+ // reverseAt: 'createdAt'
122
+ // }
123
+
124
+ deriveVerb('write')
125
+ // {
126
+ // action: 'write',
127
+ // act: 'writes',
128
+ // activity: 'writing',
129
+ // event: 'written', (irregular)
130
+ // reverseBy: 'writtenBy',
131
+ // reverseAt: 'writtenAt'
132
+ // }
133
+ ```
134
+
135
+ ## Providers
136
+
137
+ ### MemoryProvider
138
+
139
+ In-memory implementation for testing and development:
140
+
141
+ ```typescript
142
+ import { createMemoryProvider, MemoryProvider } from 'digital-objects'
143
+
144
+ // Factory function
145
+ const provider = createMemoryProvider()
146
+
147
+ // Or instantiate directly
148
+ const provider = new MemoryProvider()
149
+
150
+ // Clean up
151
+ await provider.close()
152
+ ```
153
+
154
+ ### NS (Namespace Durable Object)
155
+
156
+ SQLite-backed implementation for Cloudflare Workers with multi-tenant support:
157
+
158
+ ```typescript
159
+ // In wrangler.toml:
160
+ // [[durable_objects.bindings]]
161
+ // name = "NS"
162
+ // class_name = "NS"
163
+
164
+ // Import for Workers
165
+ import { NS } from 'digital-objects/ns'
166
+
167
+ // Access via HTTP
168
+ export default {
169
+ async fetch(request: Request, env: Env) {
170
+ const namespace = 'tenant-123'
171
+ const id = env.NS.idFromName(namespace)
172
+ const stub = env.NS.get(id)
173
+ return stub.fetch(request)
174
+ }
175
+ }
176
+
177
+ // HTTP API endpoints:
178
+ // POST /nouns - Define a noun
179
+ // GET /nouns/:name - Get a noun
180
+ // GET /nouns - List nouns
181
+ // POST /verbs - Define a verb
182
+ // POST /things - Create a thing
183
+ // GET /things/:id - Get a thing
184
+ // PATCH /things/:id - Update a thing
185
+ // DELETE /things/:id - Delete a thing
186
+ // POST /actions - Perform an action
187
+ // GET /related/:id - Get related things
188
+ ```
189
+
190
+ ### NS Client
191
+
192
+ HTTP client for accessing NS from other services:
193
+
194
+ ```typescript
195
+ import { createNSClient } from 'digital-objects'
196
+
197
+ const client = createNSClient({
198
+ baseUrl: 'https://ns.example.com',
199
+ namespace: 'my-namespace',
200
+ })
201
+
202
+ const post = await client.create('Post', { title: 'Hello' })
203
+ ```
204
+
205
+ ## R2 Persistence
206
+
207
+ Backup, restore, and export functionality using Cloudflare R2.
208
+
209
+ ### Snapshots
210
+
211
+ ```typescript
212
+ import { createSnapshot, restoreSnapshot } from 'digital-objects'
213
+
214
+ // Create a full snapshot
215
+ const result = await createSnapshot(provider, r2, 'my-namespace', {
216
+ timestamp: true, // Include timestamp in filename
217
+ })
218
+ // result.key = 'snapshots/my-namespace/1234567890.json'
219
+
220
+ // Restore from snapshot
221
+ await restoreSnapshot(provider, r2, 'my-namespace')
222
+ // or specify a snapshot key:
223
+ await restoreSnapshot(provider, r2, 'my-namespace', 'snapshots/my-namespace/1234567890.json')
224
+ ```
225
+
226
+ ### Write-Ahead Log (WAL)
227
+
228
+ ```typescript
229
+ import { appendWAL, replayWAL, compactWAL } from 'digital-objects'
230
+
231
+ // Append operation to WAL
232
+ await appendWAL(r2, 'my-namespace', {
233
+ type: 'create',
234
+ noun: 'Post',
235
+ id: post.id,
236
+ data: post.data,
237
+ timestamp: Date.now(),
238
+ })
239
+
240
+ // Replay WAL entries
241
+ const replayed = await replayWAL(provider, r2, 'my-namespace', lastSnapshotTimestamp)
242
+
243
+ // Clean up old WAL entries
244
+ const deleted = await compactWAL(r2, 'my-namespace', snapshotTimestamp)
245
+ ```
246
+
247
+ ### JSONL Export/Import
248
+
249
+ ```typescript
250
+ import { exportJSONL, importJSONL, exportToR2, importFromR2 } from 'digital-objects'
251
+
252
+ // Export to string
253
+ const jsonl = await exportJSONL(provider)
254
+
255
+ // Import from string
256
+ const stats = await importJSONL(provider, jsonl)
257
+ // stats = { nouns: 5, verbs: 3, things: 100, actions: 250 }
258
+
259
+ // Export directly to R2
260
+ await exportToR2(provider, r2, 'exports/backup.jsonl')
261
+
262
+ // Import directly from R2
263
+ await importFromR2(provider, r2, 'exports/backup.jsonl')
264
+ ```
265
+
266
+ ## ai-database Adapter
267
+
268
+ Use digital-objects as a storage backend for ai-database:
269
+
270
+ ```typescript
271
+ import { createMemoryProvider, createDBProviderAdapter } from 'digital-objects'
272
+
273
+ const doProvider = createMemoryProvider()
274
+ const dbProvider = createDBProviderAdapter(doProvider)
275
+
276
+ // Now use ai-database's interface
277
+ const user = await dbProvider.create('User', undefined, {
278
+ name: 'Alice',
279
+ email: 'alice@example.com',
280
+ })
281
+ // Returns: { $id: 'uuid', $type: 'User', name: 'Alice', email: '...' }
282
+
283
+ // Get by ID
284
+ const found = await dbProvider.get('User', user.$id)
285
+
286
+ // List with filters
287
+ const admins = await dbProvider.list('User', {
288
+ where: { role: 'admin' },
289
+ orderBy: 'name',
290
+ limit: 10,
291
+ })
292
+
293
+ // Create relationships
294
+ await dbProvider.relate('User', user.$id, 'author', 'Post', post.$id)
295
+
296
+ // Query relationships
297
+ const userPosts = await dbProvider.related('Post', user.$id, 'author')
298
+ ```
299
+
300
+ ## Type Definitions
301
+
302
+ ### Noun
303
+
304
+ ```typescript
305
+ interface Noun {
306
+ name: string // 'Post'
307
+ singular: string // 'post'
308
+ plural: string // 'posts'
309
+ slug: string // 'post' (URL-safe)
310
+ description?: string
311
+ schema?: Record<string, FieldDefinition>
312
+ createdAt: Date
313
+ }
314
+ ```
315
+
316
+ ### Verb
317
+
318
+ ```typescript
319
+ interface Verb {
320
+ name: string // 'create'
321
+ action: string // 'create' (imperative)
322
+ act: string // 'creates' (3rd person)
323
+ activity: string // 'creating' (gerund)
324
+ event: string // 'created' (past participle)
325
+ reverseBy?: string // 'createdBy'
326
+ reverseAt?: string // 'createdAt'
327
+ inverse?: string // 'delete'
328
+ description?: string
329
+ createdAt: Date
330
+ }
331
+ ```
332
+
333
+ ### Thing
334
+
335
+ ```typescript
336
+ interface Thing<T = Record<string, unknown>> {
337
+ id: string
338
+ noun: string // References noun.name
339
+ data: T
340
+ createdAt: Date
341
+ updatedAt: Date
342
+ }
343
+ ```
344
+
345
+ ### Action
346
+
347
+ ```typescript
348
+ interface Action<T = Record<string, unknown>> {
349
+ id: string
350
+ verb: string // References verb.name
351
+ subject?: string // Thing ID (actor/from)
352
+ object?: string // Thing ID (target/to)
353
+ data?: T // Payload/metadata
354
+ status: ActionStatus
355
+ createdAt: Date
356
+ completedAt?: Date
357
+ }
358
+
359
+ type ActionStatus = 'pending' | 'active' | 'completed' | 'failed' | 'cancelled'
360
+ ```
361
+
362
+ ### Field Types
363
+
364
+ ```typescript
365
+ type FieldDefinition =
366
+ | 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'json' | 'markdown' | 'url'
367
+ | `${string}.${string}` // Relation: 'Author.posts'
368
+ | `[${string}.${string}]` // Array relation: '[Tag.posts]'
369
+ | `${PrimitiveType}?` // Optional field
370
+ ```
371
+
372
+ ## Schema Validation
373
+
374
+ Digital Objects provides runtime schema validation with clear, actionable error messages.
375
+
376
+ ### Enable Validation
377
+
378
+ Validation is opt-in. Pass `{ validate: true }` to `create()` or `update()`:
379
+
380
+ ```typescript
381
+ // Define a noun with schema
382
+ await provider.defineNoun({
383
+ name: 'User',
384
+ schema: {
385
+ email: { type: 'string', required: true },
386
+ age: 'number',
387
+ bio: 'string?', // Optional
388
+ },
389
+ })
390
+
391
+ // Validation enabled - will throw on errors
392
+ await provider.create('User', { name: 'Alice' }, undefined, { validate: true })
393
+ // Error: Validation failed (1 error):
394
+ // - Missing required field 'email'
395
+ ```
396
+
397
+ ### Pre-flight Validation
398
+
399
+ Use `validateOnly()` to check data before attempting operations:
400
+
401
+ ```typescript
402
+ import { validateOnly } from 'digital-objects'
403
+
404
+ const schema = {
405
+ email: { type: 'string', required: true },
406
+ age: 'number',
407
+ }
408
+
409
+ const result = validateOnly({ age: '25' }, schema)
410
+
411
+ if (!result.valid) {
412
+ console.log('Errors:', result.errors)
413
+ // [
414
+ // {
415
+ // field: 'email',
416
+ // message: "Missing required field 'email'",
417
+ // code: 'REQUIRED_FIELD',
418
+ // expected: 'string',
419
+ // received: 'undefined'
420
+ // },
421
+ // {
422
+ // field: 'age',
423
+ // message: "Field 'age' has wrong type: expected number, got string",
424
+ // code: 'TYPE_MISMATCH',
425
+ // expected: 'number',
426
+ // received: 'string',
427
+ // suggestion: 'Convert to number: 25'
428
+ // }
429
+ // ]
430
+ }
431
+ ```
432
+
433
+ ### Error Codes
434
+
435
+ | Code | Description |
436
+ |------|-------------|
437
+ | `REQUIRED_FIELD` | A required field is missing or null |
438
+ | `TYPE_MISMATCH` | Value has wrong type for the field |
439
+ | `INVALID_FORMAT` | Value format doesn't match expected pattern |
440
+ | `UNKNOWN_FIELD` | Field not defined in schema (future feature) |
441
+
442
+ ### Suggestions
443
+
444
+ Validation errors include helpful suggestions when possible:
445
+
446
+ ```typescript
447
+ // String that looks like a number
448
+ { age: '25' }
449
+ // suggestion: "Convert to number: 25"
450
+
451
+ // Number when string expected
452
+ { name: 42 }
453
+ // suggestion: 'Convert to string: "42"'
454
+
455
+ // String boolean
456
+ { active: 'true' }
457
+ // suggestion: "Convert to boolean: true"
458
+
459
+ // Wrong type for array
460
+ { tags: 'single-tag' }
461
+ // suggestion: "Wrap value in an array: [value]"
462
+
463
+ // Wrong type for date
464
+ { createdAt: 1705312800000 }
465
+ // suggestion: "Provide a valid ISO 8601 date string"
466
+ ```
467
+
468
+ ## Installation
469
+
470
+ ```bash
471
+ npm install digital-objects
472
+ ```
473
+
474
+ ## License
475
+
476
+ MIT
@@ -0,0 +1,49 @@
1
+ /**
2
+ * ai-database Adapter
3
+ *
4
+ * Wraps a DigitalObjectsProvider to provide the ai-database DBProvider interface.
5
+ * This enables ai-database to use digital-objects as its storage backend.
6
+ */
7
+ import type { DigitalObjectsProvider } from './types.js';
8
+ export interface ListOptions {
9
+ limit?: number;
10
+ offset?: number;
11
+ where?: Record<string, unknown>;
12
+ orderBy?: string;
13
+ order?: 'asc' | 'desc';
14
+ }
15
+ export interface SearchOptions extends ListOptions {
16
+ fields?: string[];
17
+ }
18
+ export interface SemanticSearchOptions extends SearchOptions {
19
+ embedding?: number[];
20
+ minScore?: number;
21
+ }
22
+ export interface HybridSearchOptions extends SearchOptions {
23
+ semanticWeight?: number;
24
+ ftsWeight?: number;
25
+ minScore?: number;
26
+ }
27
+ /**
28
+ * ai-database DBProvider interface (simplified)
29
+ */
30
+ export interface DBProvider {
31
+ get(type: string, id: string): Promise<Record<string, unknown> | null>;
32
+ list(type: string, options?: ListOptions): Promise<Record<string, unknown>[]>;
33
+ search(type: string, query: string, options?: SearchOptions): Promise<Record<string, unknown>[]>;
34
+ create(type: string, id: string | undefined, data: Record<string, unknown>): Promise<Record<string, unknown>>;
35
+ update(type: string, id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
36
+ delete(type: string, id: string): Promise<boolean>;
37
+ related(type: string, id: string, relation: string): Promise<Record<string, unknown>[]>;
38
+ relate(fromType: string, fromId: string, relation: string, toType: string, toId: string, metadata?: {
39
+ matchMode?: 'exact' | 'fuzzy';
40
+ similarity?: number;
41
+ matchedType?: string;
42
+ }): Promise<void>;
43
+ unrelate(fromType: string, fromId: string, relation: string, toType: string, toId: string): Promise<void>;
44
+ }
45
+ /**
46
+ * Create a DBProvider adapter from a DigitalObjectsProvider
47
+ */
48
+ export declare function createDBProviderAdapter(provider: DigitalObjectsProvider): DBProvider;
49
+ //# sourceMappingURL=ai-database-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-database-adapter.d.ts","sourceRoot":"","sources":["../src/ai-database-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,YAAY,CAAA;AAGnB,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAEzB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IACtE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAC7E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAChG,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACjG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAGlD,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IACvF,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACtF,OAAO,CAAC,IAAI,CAAC,CAAA;IAChB,QAAQ,CACN,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAAA;CACjB;AAuBD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,UAAU,CAgGpF"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ai-database Adapter
3
+ *
4
+ * Wraps a DigitalObjectsProvider to provide the ai-database DBProvider interface.
5
+ * This enables ai-database to use digital-objects as its storage backend.
6
+ */
7
+ /**
8
+ * Convert Thing to entity format (with $id, $type)
9
+ */
10
+ function thingToEntity(thing) {
11
+ return {
12
+ $id: thing.id,
13
+ $type: thing.noun,
14
+ ...thing.data,
15
+ };
16
+ }
17
+ /**
18
+ * Extract data from entity (remove $id, $type)
19
+ */
20
+ function entityToData(entity) {
21
+ const { $id, $type, ...data } = entity;
22
+ return data;
23
+ }
24
+ /**
25
+ * Create a DBProvider adapter from a DigitalObjectsProvider
26
+ */
27
+ export function createDBProviderAdapter(provider) {
28
+ return {
29
+ async get(type, id) {
30
+ const thing = await provider.get(id);
31
+ if (!thing || thing.noun !== type)
32
+ return null;
33
+ return thingToEntity(thing);
34
+ },
35
+ async list(type, options) {
36
+ const things = await provider.list(type, options);
37
+ return things.map(thingToEntity);
38
+ },
39
+ async search(type, query, options) {
40
+ const things = await provider.search(query, { ...options, where: { ...options?.where } });
41
+ // Filter by type since search is global
42
+ return things.filter((t) => t.noun === type).map(thingToEntity);
43
+ },
44
+ async create(type, id, data) {
45
+ // Ensure noun is defined
46
+ const existingNoun = await provider.getNoun(type);
47
+ if (!existingNoun) {
48
+ await provider.defineNoun({ name: type });
49
+ }
50
+ const thing = await provider.create(type, entityToData(data), id);
51
+ return thingToEntity(thing);
52
+ },
53
+ async update(_type, id, data) {
54
+ const thing = await provider.update(id, entityToData(data));
55
+ return thingToEntity(thing);
56
+ },
57
+ async delete(_type, id) {
58
+ return provider.delete(id);
59
+ },
60
+ async related(type, id, relation) {
61
+ // ai-database expects related entities of a specific type via a relation
62
+ // digital-objects uses verb as the relation type
63
+ const things = await provider.related(id, relation, 'both');
64
+ // Filter by expected type
65
+ return things.filter((t) => t.noun === type).map(thingToEntity);
66
+ },
67
+ async relate(_fromType, fromId, relation, _toType, toId, metadata) {
68
+ // Ensure verb is defined
69
+ const existingVerb = await provider.getVerb(relation);
70
+ if (!existingVerb) {
71
+ await provider.defineVerb({ name: relation });
72
+ }
73
+ await provider.perform(relation, fromId, toId, metadata);
74
+ },
75
+ async unrelate(_fromType, fromId, relation, _toType, toId) {
76
+ // Find the action(s) matching this relation and delete them
77
+ const actions = await provider.listActions({
78
+ verb: relation,
79
+ subject: fromId,
80
+ object: toId,
81
+ });
82
+ // Delete all matching actions (for GDPR compliance)
83
+ for (const action of actions) {
84
+ await provider.deleteAction(action.id);
85
+ }
86
+ },
87
+ };
88
+ }
89
+ //# sourceMappingURL=ai-database-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-database-adapter.js","sourceRoot":"","sources":["../src/ai-database-adapter.ts"],"names":[],"mappings":"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"}