js-bao 0.2.10 → 0.2.12

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 (67) hide show
  1. package/README.md +174 -0
  2. package/dist/BaseModel-5YQCROYE.js +17 -0
  3. package/dist/BaseModel-5YQCROYE.js.map +1 -0
  4. package/dist/BaseModel-FCNWDJBH.js +17 -0
  5. package/dist/BaseModel-FCNWDJBH.js.map +1 -0
  6. package/dist/BrowserDatabaseFactory-PXOTK2DQ.js +119 -0
  7. package/dist/BrowserDatabaseFactory-PXOTK2DQ.js.map +1 -0
  8. package/dist/BrowserDatabaseFactory-WD4VX2VZ.js +119 -0
  9. package/dist/BrowserDatabaseFactory-WD4VX2VZ.js.map +1 -0
  10. package/dist/IncludeResolver-RCKQGNPZ.js +385 -0
  11. package/dist/IncludeResolver-RCKQGNPZ.js.map +1 -0
  12. package/dist/IncludeResolver-WGSQDMS7.js +385 -0
  13. package/dist/IncludeResolver-WGSQDMS7.js.map +1 -0
  14. package/dist/NodeDatabaseFactory-J4Z36UF3.js +165 -0
  15. package/dist/NodeDatabaseFactory-J4Z36UF3.js.map +1 -0
  16. package/dist/NodeDatabaseFactory-QIEKAXBM.js +10 -0
  17. package/dist/NodeDatabaseFactory-QIEKAXBM.js.map +1 -0
  18. package/dist/NodeSqliteEngine-HJSAYE4E.js +383 -0
  19. package/dist/NodeSqliteEngine-HJSAYE4E.js.map +1 -0
  20. package/dist/NodeSqliteEngine-I5SLWLME.js +383 -0
  21. package/dist/NodeSqliteEngine-I5SLWLME.js.map +1 -0
  22. package/dist/browser.cjs +3779 -3370
  23. package/dist/browser.d.cts +18 -1
  24. package/dist/browser.d.ts +18 -1
  25. package/dist/browser.js +3750 -3341
  26. package/dist/chunk-3PZWHUZO.js +4153 -0
  27. package/dist/chunk-3PZWHUZO.js.map +1 -0
  28. package/dist/chunk-53MS4MN7.js +373 -0
  29. package/dist/chunk-53MS4MN7.js.map +1 -0
  30. package/dist/chunk-65G2P4GL.js +709 -0
  31. package/dist/chunk-65G2P4GL.js.map +1 -0
  32. package/dist/chunk-6UX3YSCW.js +4151 -0
  33. package/dist/chunk-6UX3YSCW.js.map +1 -0
  34. package/dist/chunk-DANSD6BE.js +709 -0
  35. package/dist/chunk-DANSD6BE.js.map +1 -0
  36. package/dist/chunk-DF3JEQXA.js +373 -0
  37. package/dist/chunk-DF3JEQXA.js.map +1 -0
  38. package/dist/chunk-GO3APTPX.js +61 -0
  39. package/dist/chunk-GO3APTPX.js.map +1 -0
  40. package/dist/chunk-ID4U6IQC.js +53 -0
  41. package/dist/chunk-ID4U6IQC.js.map +1 -0
  42. package/dist/chunk-RQVS3LVL.js +165 -0
  43. package/dist/chunk-RQVS3LVL.js.map +1 -0
  44. package/dist/client.cjs +837 -0
  45. package/dist/client.d.cts +1101 -0
  46. package/dist/client.d.ts +1101 -0
  47. package/dist/client.js +806 -0
  48. package/dist/cloudflare-do.cjs +3637 -0
  49. package/dist/cloudflare-do.d.cts +1366 -0
  50. package/dist/cloudflare-do.d.ts +1366 -0
  51. package/dist/cloudflare-do.js +3614 -0
  52. package/dist/cloudflare.cjs +1048 -0
  53. package/dist/cloudflare.d.cts +1381 -0
  54. package/dist/cloudflare.d.ts +1381 -0
  55. package/dist/cloudflare.js +1017 -0
  56. package/dist/codegen.cjs +259 -18
  57. package/dist/environment-TOTQICSE.js +17 -0
  58. package/dist/environment-TOTQICSE.js.map +1 -0
  59. package/dist/index.cjs +1906 -1493
  60. package/dist/index.d.cts +19 -2
  61. package/dist/index.d.ts +19 -2
  62. package/dist/index.js +1871 -1458
  63. package/dist/node.cjs +4779 -4366
  64. package/dist/node.d.cts +18 -1
  65. package/dist/node.d.ts +18 -1
  66. package/dist/node.js +4602 -4189
  67. package/package.json +41 -12
@@ -0,0 +1,1366 @@
1
+ interface RefersToRelationshipConfig {
2
+ type: "refersTo";
3
+ model: string;
4
+ relatedIdField: string;
5
+ }
6
+ interface HasManyRelationshipConfig {
7
+ type: "hasMany";
8
+ model: string;
9
+ relatedIdField: string;
10
+ orderByField?: string;
11
+ orderDirection?: "ASC" | "DESC";
12
+ }
13
+ interface HasManyThroughRelationshipConfig {
14
+ type: "hasManyThrough";
15
+ model: string;
16
+ joinModel: string;
17
+ joinModelLocalField: string;
18
+ joinModelRelatedField: string;
19
+ joinModelOrderByField?: string;
20
+ joinModelOrderDirection?: "ASC" | "DESC";
21
+ }
22
+ type RelationshipConfig = RefersToRelationshipConfig | HasManyRelationshipConfig | HasManyThroughRelationshipConfig;
23
+
24
+ type FieldType = "string" | "number" | "boolean" | "date" | "id" | "stringset";
25
+ interface FieldOptions {
26
+ type: FieldType;
27
+ indexed?: boolean;
28
+ required?: boolean;
29
+ unique?: boolean;
30
+ default?: any | (() => any);
31
+ autoAssign?: boolean;
32
+ maxLength?: number;
33
+ maxCount?: number;
34
+ }
35
+ interface UniqueConstraintConfig {
36
+ name: string;
37
+ fields: string[];
38
+ }
39
+ interface ModelOptions {
40
+ name: string;
41
+ uniqueConstraints?: UniqueConstraintConfig[];
42
+ relationships?: Record<string, RelationshipConfig>;
43
+ }
44
+
45
+ interface ITransactionalDatabaseOperations {
46
+ insert(modelName: string, data: any): Promise<void>;
47
+ delete(modelName: string, id: string): Promise<void>;
48
+ query<T extends Record<string, any>>(sql: string, params?: any[]): Promise<T[]>;
49
+ }
50
+ /**
51
+ * Abstract class defining the interface for database engines.
52
+ * This allows for different database implementations (e.g., SQL.js, DuckDB) to be used interchangeably.
53
+ */
54
+ declare abstract class DatabaseEngine {
55
+ /**
56
+ * Ensures that the database engine is fully initialized and ready for use.
57
+ * For WASM-based engines, this might involve loading the WASM module.
58
+ */
59
+ abstract ensureReady(): Promise<void>;
60
+ /**
61
+ * Executes a SQL query against the database.
62
+ * @param sql The SQL query string.
63
+ * @param params Optional array of parameters for prepared statements.
64
+ * @returns A promise that resolves to an array of query results.
65
+ */
66
+ abstract query(sql: string, params?: any[]): Promise<any[]>;
67
+ /**
68
+ * Retrieves the last error message from the database engine, if any.
69
+ * @returns The last error message as a string, or undefined if no error occurred.
70
+ */
71
+ abstract getLastErrorMessage(): string | undefined;
72
+ /**
73
+ * Retrieves the schema for a given table.
74
+ * This is useful for understanding table structure, field types, etc.
75
+ * The exact return type might vary based on the database engine.
76
+ * @param tableName The name of the table.
77
+ * @returns A promise that resolves to the table schema information.
78
+ */
79
+ abstract getTableSchema(tableName: string): Promise<any>;
80
+ /**
81
+ * Destroys the database engine instance and releases any associated resources.
82
+ * This is crucial for cleanup, especially in testing environments or when the application is shutting down.
83
+ */
84
+ abstract destroy(): Promise<void>;
85
+ createTable(_modelName: string, _schema: Map<string, any>, // Assuming 'any' for field options for now, can be refined
86
+ _options: ModelOptions): Promise<void>;
87
+ createStringSetJunctionTable(_modelName: string, _fieldName: string): Promise<void>;
88
+ insertStringSetValues(_modelName: string, _fieldName: string, _recordId: string, _values: string[]): Promise<void>;
89
+ removeStringSetValues(_modelName: string, _fieldName: string, _recordId: string, _values: string[]): Promise<void>;
90
+ insert(_modelName: string, _data: any): Promise<void>;
91
+ delete(_modelName: string, _id: string): Promise<void>;
92
+ /**
93
+ * Deletes all records for a specific document from the given model table.
94
+ * This is used when disconnecting a document to remove all its data.
95
+ * @param modelName The name of the model/table
96
+ * @param docId The document ID to filter by
97
+ */
98
+ deleteByDocumentId(_modelName: string, _docId: string): Promise<void>;
99
+ getTableName(_modelName: string): string;
100
+ withTransaction<T>(_callback: (operations: ITransactionalDatabaseOperations) => Promise<T>): Promise<T>;
101
+ }
102
+
103
+ /**
104
+ * JSON Schema DDL Generator
105
+ *
106
+ * Generates SQL DDL statements for the JSON schema approach where all records
107
+ * are stored in a single `records` table with a `_data` column.
108
+ *
109
+ * Internal columns use a `_` prefix convention:
110
+ * _id, _type, _data (records table)
111
+ * _record_id, _type (stringset_index table)
112
+ * _meta_doc_id, _meta_permission_hint (yjs mode metadata)
113
+ *
114
+ * This schema is used by both:
115
+ * - OPFS SQLite (browser, with _meta_doc_id for multi-document support)
116
+ * - Durable Objects SQLite (server, one DO per document, no _meta_doc_id needed)
117
+ */
118
+ interface JsonSchemaOptions {
119
+ /**
120
+ * Whether to include the _meta_doc_id column.
121
+ * - true: For yjs mode where multiple documents share the same SQLite DB
122
+ * - false: For DO mode where each DO is a single document
123
+ */
124
+ includeDocIdColumn: boolean;
125
+ }
126
+ declare class JsonSchemaDDL {
127
+ /**
128
+ * Generate CREATE TABLE statement for the records table
129
+ */
130
+ static createRecordsTable(options: JsonSchemaOptions): string;
131
+ /**
132
+ * Generate CREATE TABLE statement for the stringset_index table
133
+ */
134
+ static createStringSetIndexTable(options: JsonSchemaOptions): string;
135
+ /**
136
+ * Generate base indexes for the schema
137
+ */
138
+ static createBaseIndexes(options: JsonSchemaOptions): string[];
139
+ /**
140
+ * Generate CREATE INDEX statement for a model field
141
+ * Uses json_extract for JSON schema
142
+ */
143
+ static createFieldIndex(modelName: string, fieldName: string): string;
144
+ /**
145
+ * Generate DROP INDEX statement for a model field
146
+ */
147
+ static dropFieldIndex(modelName: string, fieldName: string): string;
148
+ /**
149
+ * Generate CREATE TABLE statement for the _indexes table.
150
+ * Stores per-field index registrations (one row per index).
151
+ */
152
+ static createIndexesTable(): string;
153
+ /**
154
+ * Generate CREATE TABLE statement for the _unique_constraints table.
155
+ * Stores composite (multi-field) unique constraints.
156
+ */
157
+ static createUniqueConstraintsTable(): string;
158
+ /**
159
+ * Generate CREATE TABLE statement for the _model_fields table.
160
+ * Tracks field names and inferred types as records are written.
161
+ */
162
+ static createModelFieldsTable(): string;
163
+ /**
164
+ * Generate all DDL statements needed to initialize the schema
165
+ */
166
+ static getAllDDL(options: JsonSchemaOptions): string[];
167
+ /**
168
+ * Generate INSERT statement for a record
169
+ */
170
+ static buildInsertSQL(options: JsonSchemaOptions): string;
171
+ /**
172
+ * Generate DELETE statement for a record by id and type
173
+ */
174
+ static buildDeleteSQL(options: JsonSchemaOptions): string;
175
+ /**
176
+ * Generate DELETE statement for stringset values
177
+ */
178
+ static buildDeleteStringSetSQL(): string;
179
+ /**
180
+ * Generate INSERT statement for stringset values
181
+ */
182
+ static buildInsertStringSetSQL(options: JsonSchemaOptions): string;
183
+ }
184
+
185
+ /**
186
+ * JSON Schema Engine Base Class
187
+ *
188
+ * Abstract base class for database engines that use the JSON schema approach.
189
+ * Provides common implementations for CRUD operations using the single `records`
190
+ * table with `data_json` column.
191
+ *
192
+ * Subclasses must implement:
193
+ * - execSql(sql, params): Execute SQL and return results
194
+ * - ensureReady(): Initialize the engine
195
+ * - destroy(): Clean up resources
196
+ */
197
+
198
+ interface JsonSchemaEngineOptions extends JsonSchemaOptions {
199
+ }
200
+ declare abstract class JsonSchemaEngine extends DatabaseEngine {
201
+ protected schemaOptions: JsonSchemaEngineOptions;
202
+ initialized: boolean;
203
+ constructor(options: JsonSchemaEngineOptions);
204
+ /**
205
+ * Execute SQL and return results.
206
+ * Must be implemented by subclasses.
207
+ */
208
+ abstract execSql(sql: string, params?: any[]): Promise<any[]>;
209
+ /**
210
+ * Execute SQL synchronously (optional, for environments that support it like DO).
211
+ * Returns undefined if not supported.
212
+ */
213
+ execSqlSync?(sql: string, params?: any[]): any[];
214
+ /**
215
+ * Initialize the JSON schema tables.
216
+ * Should be called once during engine setup.
217
+ */
218
+ initializeSchema(): Promise<void>;
219
+ /**
220
+ * Create table for a model.
221
+ * In JSON schema, this is a no-op since all models share the `records` table.
222
+ * However, we can create indexes for indexed fields.
223
+ */
224
+ createTable(modelName: string, schema: Map<string, FieldOptions>, _options: ModelOptions): Promise<void>;
225
+ /**
226
+ * Create StringSet junction table.
227
+ * In JSON schema, this is a no-op since we use the shared stringset_index table.
228
+ */
229
+ createStringSetJunctionTable(_modelName: string, _fieldName: string): Promise<void>;
230
+ /**
231
+ * Insert or update a record.
232
+ */
233
+ insert(modelName: string, data: any): Promise<void>;
234
+ /**
235
+ * Delete a record by ID.
236
+ */
237
+ delete(modelName: string, id: string): Promise<void>;
238
+ /**
239
+ * Delete all records for a specific document.
240
+ * Only applicable in yjs mode with doc ID column.
241
+ */
242
+ deleteByDocumentId(modelName: string, docId: string): Promise<void>;
243
+ /**
244
+ * Insert StringSet values for a record.
245
+ */
246
+ insertStringSetValues(modelName: string, fieldName: string, recordId: string, values: string[], docId?: string): Promise<void>;
247
+ /**
248
+ * Remove StringSet values for a record.
249
+ */
250
+ removeStringSetValues(modelName: string, fieldName: string, recordId: string, values: string[]): Promise<void>;
251
+ /**
252
+ * Get table name for a model.
253
+ * In JSON schema, all models use the 'records' table.
254
+ */
255
+ getTableName(_modelName: string): string;
256
+ /**
257
+ * Execute a query and return results.
258
+ */
259
+ query(sql: string, params?: any[]): Promise<any[]>;
260
+ /**
261
+ * Get the table schema.
262
+ * Returns information about the records table structure.
263
+ */
264
+ getTableSchema(_tableName: string): Promise<any>;
265
+ /**
266
+ * Get the last error message.
267
+ * Subclasses can override this if needed.
268
+ */
269
+ getLastErrorMessage(): string | undefined;
270
+ /**
271
+ * Transaction support.
272
+ * Default implementation runs callback without actual transaction.
273
+ * Subclasses should override for proper transaction support.
274
+ */
275
+ withTransaction<T>(callback: (operations: ITransactionalDatabaseOperations) => Promise<T>): Promise<T>;
276
+ /**
277
+ * Parse a record row from the database.
278
+ * Extracts fields from _data and merges with direct columns.
279
+ */
280
+ protected parseRecordRow(row: any): Record<string, any>;
281
+ }
282
+
283
+ /**
284
+ * Cloudflare Durable Objects Type Definitions
285
+ *
286
+ * These types mirror the Cloudflare Workers runtime types for Durable Objects.
287
+ * They are provided here so js-bao can be built without requiring the
288
+ * @cloudflare/workers-types package as a dependency.
289
+ *
290
+ * When using js-bao in a Cloudflare Worker, you should install
291
+ * @cloudflare/workers-types for complete type coverage.
292
+ */
293
+ /**
294
+ * SqlStorage interface - provides SQLite access in Durable Objects
295
+ */
296
+ interface SqlStorage {
297
+ /**
298
+ * Execute a SQL query with optional parameter bindings.
299
+ * Returns a cursor for iterating over results.
300
+ */
301
+ exec(query: string, ...bindings: any[]): SqlStorageCursor;
302
+ /**
303
+ * Get the current database size in bytes.
304
+ */
305
+ readonly databaseSize: number;
306
+ }
307
+ /**
308
+ * SqlStorageCursor - returned by sql.exec() for iterating results
309
+ */
310
+ interface SqlStorageCursor extends Iterable<Record<string, any>> {
311
+ /**
312
+ * Get the next row from the cursor.
313
+ */
314
+ next(): IteratorResult<Record<string, any>>;
315
+ /**
316
+ * Collect all remaining rows into an array.
317
+ */
318
+ toArray(): Record<string, any>[];
319
+ /**
320
+ * Get exactly one row. Throws if zero or multiple rows.
321
+ */
322
+ one(): Record<string, any>;
323
+ /**
324
+ * Return an iterator yielding arrays instead of objects.
325
+ */
326
+ raw(): Iterator<any[]>;
327
+ /**
328
+ * Column names in result order.
329
+ */
330
+ readonly columnNames: string[];
331
+ /**
332
+ * Number of rows read so far (affects billing).
333
+ */
334
+ readonly rowsRead: number;
335
+ /**
336
+ * Number of rows written so far (affects billing).
337
+ */
338
+ readonly rowsWritten: number;
339
+ }
340
+ /**
341
+ * DurableObjectStorage interface
342
+ */
343
+ interface DurableObjectStorage {
344
+ /**
345
+ * SQLite storage interface
346
+ */
347
+ readonly sql: SqlStorage;
348
+ /**
349
+ * Execute a synchronous transaction with SQLite.
350
+ */
351
+ transactionSync<T>(closure: () => T): T;
352
+ /**
353
+ * Execute an async transaction.
354
+ */
355
+ transaction<T>(closure: (txn: DurableObjectTransaction) => Promise<T>): Promise<T>;
356
+ get<T = unknown>(key: string): Promise<T | undefined>;
357
+ get<T = unknown>(keys: string[]): Promise<Map<string, T>>;
358
+ put<T>(key: string, value: T): Promise<void>;
359
+ put<T>(entries: Record<string, T>): Promise<void>;
360
+ delete(key: string): Promise<boolean>;
361
+ delete(keys: string[]): Promise<number>;
362
+ deleteAll(): Promise<void>;
363
+ list<T = unknown>(options?: DurableObjectListOptions): Promise<Map<string, T>>;
364
+ }
365
+ /**
366
+ * DurableObjectTransaction interface
367
+ */
368
+ interface DurableObjectTransaction {
369
+ get<T = unknown>(key: string): Promise<T | undefined>;
370
+ get<T = unknown>(keys: string[]): Promise<Map<string, T>>;
371
+ put<T>(key: string, value: T): Promise<void>;
372
+ put<T>(entries: Record<string, T>): Promise<void>;
373
+ delete(key: string): Promise<boolean>;
374
+ delete(keys: string[]): Promise<number>;
375
+ rollback(): void;
376
+ }
377
+ /**
378
+ * Options for storage.list()
379
+ */
380
+ interface DurableObjectListOptions {
381
+ start?: string;
382
+ startAfter?: string;
383
+ end?: string;
384
+ prefix?: string;
385
+ reverse?: boolean;
386
+ limit?: number;
387
+ }
388
+ /**
389
+ * DurableObjectState - passed to DO constructor
390
+ */
391
+ interface DurableObjectState {
392
+ /**
393
+ * The unique ID of this Durable Object instance.
394
+ */
395
+ readonly id: DurableObjectId;
396
+ /**
397
+ * Storage interface for this Durable Object.
398
+ */
399
+ readonly storage: DurableObjectStorage;
400
+ /**
401
+ * Wait until the output gate is open.
402
+ */
403
+ waitUntil(promise: Promise<any>): void;
404
+ /**
405
+ * Block until storage operations complete.
406
+ */
407
+ blockConcurrencyWhile<T>(callback: () => Promise<T>): Promise<T>;
408
+ }
409
+ /**
410
+ * DurableObjectId - unique identifier for a DO instance
411
+ */
412
+ interface DurableObjectId {
413
+ toString(): string;
414
+ equals(other: DurableObjectId): boolean;
415
+ }
416
+ /**
417
+ * DurableObjectNamespace - for accessing DO instances
418
+ */
419
+ interface DurableObjectNamespace {
420
+ /**
421
+ * Get a DO ID from a name string.
422
+ */
423
+ idFromName(name: string): DurableObjectId;
424
+ /**
425
+ * Get a DO ID from a hex string.
426
+ */
427
+ idFromString(hexId: string): DurableObjectId;
428
+ /**
429
+ * Generate a new unique DO ID.
430
+ */
431
+ newUniqueId(): DurableObjectId;
432
+ /**
433
+ * Get a stub for accessing a DO instance.
434
+ */
435
+ get(id: DurableObjectId): DurableObjectStub;
436
+ }
437
+ /**
438
+ * DurableObjectStub - proxy for calling DO methods
439
+ */
440
+ interface DurableObjectStub {
441
+ /**
442
+ * The ID of this Durable Object.
443
+ */
444
+ readonly id: DurableObjectId;
445
+ /**
446
+ * The name of this Durable Object (if created via idFromName).
447
+ */
448
+ readonly name?: string;
449
+ /**
450
+ * Send a fetch request to this Durable Object.
451
+ */
452
+ fetch(request: Request | string, init?: RequestInit): Promise<Response>;
453
+ }
454
+
455
+ /**
456
+ * Durable Object Engine
457
+ *
458
+ * Database engine implementation that runs inside a Cloudflare Durable Object.
459
+ * Uses the DO's embedded SQLite database via ctx.storage.sql.
460
+ *
461
+ * Key characteristics:
462
+ * - Synchronous SQL execution (DO SQLite is sync)
463
+ * - No doc ID column needed (one DO = one document)
464
+ * - Uses JSON schema (records + stringset_index tables)
465
+ * - Schemaless: any model/field can be saved and queried without registration
466
+ * - Indexes are additive: register/drop individual field indexes independently
467
+ */
468
+
469
+ interface DurableObjectEngineOptions {
470
+ /**
471
+ * The SqlStorage interface from ctx.storage.sql
472
+ */
473
+ sql: SqlStorage;
474
+ /**
475
+ * The full storage interface for transaction support
476
+ */
477
+ storage: DurableObjectStorage;
478
+ }
479
+ /** Row shape from the _indexes table */
480
+ interface IndexEntry {
481
+ model_name: string;
482
+ field_name: string;
483
+ field_type: string;
484
+ is_unique: number;
485
+ created_at: string;
486
+ }
487
+ /** Row shape from the _unique_constraints table */
488
+ interface UniqueConstraintEntry {
489
+ model_name: string;
490
+ constraint_name: string;
491
+ fields: string[];
492
+ created_at: string;
493
+ }
494
+ /** Row shape from the _model_fields table */
495
+ interface ModelFieldInfo {
496
+ model_name: string;
497
+ field_name: string;
498
+ inferred_type: string;
499
+ first_seen_at: string;
500
+ }
501
+ declare class DurableObjectEngine extends JsonSchemaEngine {
502
+ private sql;
503
+ private storage;
504
+ constructor(options: DurableObjectEngineOptions);
505
+ /**
506
+ * Initialize the engine — creates tables and restores persisted indexes.
507
+ */
508
+ ensureReady(): Promise<void>;
509
+ /**
510
+ * Handle schema migrations for existing databases.
511
+ * Adds columns/tables that were added in later versions.
512
+ */
513
+ private _migrateSchema;
514
+ /**
515
+ * Load indexes from the _indexes table and re-ensure they exist.
516
+ */
517
+ private loadPersistedIndexes;
518
+ /**
519
+ * Register an index on a model field.
520
+ * Idempotent — re-registering the same index is a no-op.
521
+ */
522
+ registerIndex(modelName: string, fieldName: string, fieldType: string, unique?: boolean): void;
523
+ /**
524
+ * Drop an index on a model field.
525
+ * Idempotent — dropping a non-existent index is a no-op.
526
+ */
527
+ dropIndex(modelName: string, fieldName: string): void;
528
+ /**
529
+ * List all registered indexes, optionally filtered by model.
530
+ */
531
+ listIndexes(modelName?: string): IndexEntry[];
532
+ /**
533
+ * Get unique single-field indexes for a model.
534
+ */
535
+ getUniqueIndexes(modelName: string): IndexEntry[];
536
+ /**
537
+ * Register a composite unique constraint.
538
+ * Idempotent — re-registering the same constraint is a no-op.
539
+ */
540
+ registerUniqueConstraint(modelName: string, constraintName: string, fields: string[]): void;
541
+ /**
542
+ * Drop a composite unique constraint.
543
+ * Idempotent — dropping a non-existent constraint is a no-op.
544
+ */
545
+ dropUniqueConstraint(modelName: string, constraintName: string): void;
546
+ /**
547
+ * List composite unique constraints, optionally filtered by model.
548
+ */
549
+ listUniqueConstraints(modelName?: string): UniqueConstraintEntry[];
550
+ /**
551
+ * Check all unique constraints for a model before saving.
552
+ * Returns null if no violation, or an error message string if violated.
553
+ */
554
+ checkUniqueConstraints(modelName: string, id: string, data: Record<string, any>): string | null;
555
+ /**
556
+ * Check if a record exists (used by hooks to determine isNew).
557
+ */
558
+ recordExists(modelName: string, id: string): boolean;
559
+ /**
560
+ * Execute SQL asynchronously.
561
+ * Wraps the synchronous DO SQLite API.
562
+ */
563
+ execSql(sql: string, params?: any[]): Promise<any[]>;
564
+ /**
565
+ * Execute SQL synchronously.
566
+ * This is the native mode for DO SQLite.
567
+ */
568
+ execSqlSync(sql: string, params?: any[]): any[];
569
+ /**
570
+ * Transaction support using DO's transactionSync.
571
+ */
572
+ withTransaction<T>(callback: (operations: ITransactionalDatabaseOperations) => Promise<T>): Promise<T>;
573
+ /**
574
+ * Run operations within a synchronous transaction.
575
+ */
576
+ transactionSync<T>(callback: () => T): T;
577
+ /**
578
+ * Clean up resources.
579
+ */
580
+ destroy(): Promise<void>;
581
+ /**
582
+ * Insert a record with StringSet support.
583
+ */
584
+ insertWithStringSets(modelName: string, data: any, stringSets: Record<string, string[]>): Promise<void>;
585
+ /**
586
+ * Add values to StringSet fields without replacing the entire set.
587
+ * Also updates the arrays stored in data_json.
588
+ */
589
+ addToStringSets(modelName: string, id: string, sets: Record<string, string[]>): void;
590
+ /**
591
+ * Non-transactional core of addToStringSets.
592
+ * Call this from an outer transaction (e.g. batch) to avoid nested transactions.
593
+ * @internal
594
+ */
595
+ addToStringSetsRaw(modelName: string, id: string, sets: Record<string, string[]>): void;
596
+ /**
597
+ * Remove values from StringSet fields without replacing the entire set.
598
+ * Also updates the arrays stored in data_json.
599
+ */
600
+ removeFromStringSets(modelName: string, id: string, sets: Record<string, string[]>): void;
601
+ /**
602
+ * Non-transactional core of removeFromStringSets.
603
+ * Call this from an outer transaction (e.g. batch) to avoid nested transactions.
604
+ * @internal
605
+ */
606
+ removeFromStringSetsRaw(modelName: string, id: string, sets: Record<string, string[]>): void;
607
+ /**
608
+ * Sync stringset_index state back into data_json arrays for the given fields.
609
+ * @internal
610
+ */
611
+ private _syncStringSetsToJson;
612
+ /**
613
+ * Patch a record: merge provided fields into existing data_json.
614
+ * Only the specified fields are updated; all other fields are preserved.
615
+ * If stringSets are provided, those StringSet fields are fully replaced.
616
+ * Returns false if the record does not exist.
617
+ */
618
+ patchRecord(modelName: string, id: string, fields: Record<string, any>, stringSets?: Record<string, string[]>): boolean;
619
+ /**
620
+ * Non-transactional core of patchRecord.
621
+ * Call this from an outer transaction (e.g. batch) to avoid nested transactions.
622
+ * @internal
623
+ */
624
+ patchRecordRaw(modelName: string, id: string, fields: Record<string, any>, stringSets?: Record<string, string[]>): boolean;
625
+ /**
626
+ * Atomically increment/decrement numeric fields on a record.
627
+ * Each key in `fields` is a field name and its value is the delta.
628
+ * Missing fields are initialised to 0 before adding the delta.
629
+ * Returns the new values, or null if the record doesn't exist.
630
+ */
631
+ incrementFields(modelName: string, id: string, fields: Record<string, number>): Record<string, number> | null;
632
+ /**
633
+ * Non-transactional core of incrementFields.
634
+ * Call this from an outer transaction (e.g. batch) to avoid nested transactions.
635
+ * @internal
636
+ */
637
+ incrementFieldsRaw(modelName: string, id: string, fields: Record<string, number>): Record<string, number> | null;
638
+ /**
639
+ * Delete a record and its StringSet values atomically.
640
+ */
641
+ deleteWithStringSets(modelName: string, id: string): Promise<void>;
642
+ /**
643
+ * Track field names and inferred types for a model based on written data.
644
+ * Uses INSERT OR IGNORE so the first-seen type wins.
645
+ */
646
+ trackModelFields(modelName: string, data: Record<string, any>): void;
647
+ /**
648
+ * Get tracked fields for a model, or all models if no name given.
649
+ */
650
+ getModelFields(modelName?: string): ModelFieldInfo[];
651
+ }
652
+
653
+ interface ComparisonOperators<T = any> {
654
+ $eq?: T;
655
+ $ne?: T;
656
+ $gt?: T;
657
+ $gte?: T;
658
+ $lt?: T;
659
+ $lte?: T;
660
+ $in?: T[];
661
+ $nin?: T[];
662
+ }
663
+ interface StringSetOperators {
664
+ /**
665
+ * Exact membership: StringSet contains this specific string
666
+ */
667
+ $contains?: string;
668
+ $all?: string[];
669
+ $size?: number | ComparisonOperators<number>;
670
+ }
671
+ interface SubstringOperators {
672
+ /** Prefix match */
673
+ $startsWith?: string;
674
+ /** Suffix match */
675
+ $endsWith?: string;
676
+ /** Substring anywhere */
677
+ $containsText?: string;
678
+ }
679
+ interface ExistenceOperators {
680
+ $exists?: boolean;
681
+ }
682
+ type FieldOperators<T = any> = ComparisonOperators<T> & ExistenceOperators & StringSetOperators & SubstringOperators;
683
+ interface LogicalOperators {
684
+ $and?: DocumentFilter[];
685
+ $or?: DocumentFilter[];
686
+ }
687
+ type DocumentFilter = {
688
+ [field: string]: any | FieldOperators<any>;
689
+ } & LogicalOperators;
690
+ type SortDirection = 1 | -1;
691
+ type SortSpec = {
692
+ [field: string]: SortDirection;
693
+ };
694
+ type ProjectionSpec = {
695
+ [field: string]: 1 | 0;
696
+ };
697
+ interface IncludeSpec {
698
+ model: string;
699
+ type: "refersTo" | "hasMany" | "refersToMany";
700
+ sourceField?: string;
701
+ foreignKey?: string;
702
+ localField?: string;
703
+ as?: string;
704
+ projection?: ProjectionSpec;
705
+ limit?: number;
706
+ sort?: SortSpec;
707
+ filter?: DocumentFilter;
708
+ include?: IncludeSpec[];
709
+ }
710
+ interface QueryOptions {
711
+ sort?: SortSpec;
712
+ projection?: ProjectionSpec;
713
+ documents?: string | string[];
714
+ limit?: number;
715
+ uniqueStartKey?: string;
716
+ direction?: 1 | -1;
717
+ include?: IncludeSpec[];
718
+ }
719
+ interface TranslatedQuery {
720
+ sql: string;
721
+ params: any[];
722
+ sortFields: string[];
723
+ sortDirections?: (1 | -1)[];
724
+ }
725
+
726
+ /**
727
+ * JSON Query Translator
728
+ *
729
+ * Translates document-style queries to SQL for the JSON schema approach.
730
+ * All records are in a single `records` table with fields stored in `_data`.
731
+ *
732
+ * Key differences from DocumentQueryTranslator:
733
+ * - Uses json_extract(_data, '$.field') instead of direct column access
734
+ * - Uses shared stringset_index table instead of per-model junction tables
735
+ * - Adds _type = ? filter to all queries
736
+ * - Optionally handles _meta_doc_id for yjs mode
737
+ */
738
+
739
+ interface JsonQueryTranslatorOptions {
740
+ /**
741
+ * Whether to include document scoping (_meta_doc_id) in queries.
742
+ * - true: For yjs mode where multiple documents share the same SQLite DB
743
+ * - false: For DO mode where each DO is a single document
744
+ */
745
+ includeDocId: boolean;
746
+ }
747
+ declare class JsonQueryTranslator {
748
+ private modelName;
749
+ private schema?;
750
+ private options;
751
+ private fieldSqlCache;
752
+ constructor(modelName: string, schema?: Map<string, FieldOptions>, options?: JsonQueryTranslatorOptions);
753
+ /**
754
+ * Get SQL expression for a field.
755
+ * System fields (id, type) map to internal columns (_id, _type);
756
+ * others use json_extract(_data, ...).
757
+ * When no schema is provided, any field is accepted (schemaless mode).
758
+ */
759
+ getFieldSql(fieldName: string): string;
760
+ /**
761
+ * Translate document filter and options to SQL for find operations
762
+ */
763
+ translateFind(filter: DocumentFilter, options?: QueryOptions): TranslatedQuery;
764
+ /**
765
+ * Translate document filter to SQL for count operations
766
+ */
767
+ translateCount(filter: DocumentFilter, options?: Pick<QueryOptions, "documents">): {
768
+ sql: string;
769
+ params: any[];
770
+ };
771
+ /**
772
+ * Translate document filter to SQL WHERE clause.
773
+ * Returns the conditions and params without the type = ? prefix.
774
+ */
775
+ translateFilter(filter: DocumentFilter): {
776
+ sql: string;
777
+ params: any[];
778
+ };
779
+ /**
780
+ * Translate logical operators ($and, $or)
781
+ */
782
+ private translateLogicalOperator;
783
+ /**
784
+ * Translate field condition to SQL
785
+ */
786
+ private translateFieldCondition;
787
+ /**
788
+ * Translate field operators to SQL
789
+ */
790
+ private translateFieldOperators;
791
+ /**
792
+ * Translate individual operator to SQL
793
+ */
794
+ private translateOperator;
795
+ /**
796
+ * Build SELECT clause based on projection
797
+ * For JSON schema, we need to extract fields from data_json
798
+ */
799
+ private buildSelectClause;
800
+ /**
801
+ * Build LIMIT clause
802
+ */
803
+ private buildLimitClause;
804
+ /**
805
+ * Build pagination WHERE clause from cursor
806
+ */
807
+ private buildPaginationClause;
808
+ /**
809
+ * Validate projection fields — skipped in schemaless mode
810
+ */
811
+ private validateProjection;
812
+ /**
813
+ * Validate operator is supported for field type
814
+ */
815
+ private validateOperatorForType;
816
+ /**
817
+ * Validate field value matches expected type
818
+ */
819
+ private validateFieldValue;
820
+ /**
821
+ * Validate array values for $in/$nin operators
822
+ */
823
+ private validateArrayValues;
824
+ /**
825
+ * Check if value is a primitive (not an object with operators)
826
+ */
827
+ private isPrimitiveValue;
828
+ /**
829
+ * Get the type of a value for validation
830
+ */
831
+ private getValueType;
832
+ /**
833
+ * Check if value type is compatible with field type
834
+ */
835
+ private isTypeCompatible;
836
+ /**
837
+ * Convert value for SQLite compatibility
838
+ */
839
+ private convertValueForSQLite;
840
+ private normalizeDocumentIds;
841
+ private buildDocumentClause;
842
+ }
843
+
844
+ /**
845
+ * Aggregation types shared between Yjs and DO backends.
846
+ */
847
+
848
+ /**
849
+ * Describes a StringSet membership check in a groupBy clause.
850
+ * Groups records by whether they have a specific value in a StringSet field.
851
+ */
852
+ interface StringSetMembership {
853
+ field: string;
854
+ contains: string;
855
+ }
856
+ /**
857
+ * A groupBy field can be a plain field name or a StringSet membership check.
858
+ */
859
+ type GroupByField = string | StringSetMembership;
860
+ /**
861
+ * An aggregation operation (count, sum, avg, min, max).
862
+ */
863
+ interface AggregationOperation {
864
+ type: "count" | "sum" | "avg" | "min" | "max";
865
+ /** Required for sum, avg, min, max; not used for count */
866
+ field?: string;
867
+ }
868
+ /**
869
+ * Options for an aggregation query.
870
+ */
871
+ interface AggregationOptions {
872
+ groupBy: GroupByField[];
873
+ operations: AggregationOperation[];
874
+ filter?: DocumentFilter;
875
+ limit?: number;
876
+ sort?: {
877
+ /** Can be operation result field like 'count', 'sum_fieldName', etc. */
878
+ field: string;
879
+ /** 1 for ascending, -1 for descending */
880
+ direction: 1 | -1;
881
+ };
882
+ }
883
+ /**
884
+ * Result of an aggregation query — nested object keyed by group values.
885
+ */
886
+ type AggregationResult = Record<string, any> | Record<string, any>[];
887
+
888
+ /**
889
+ * Hook type definitions for Durable Object access control.
890
+ *
891
+ * Hooks run server-side inside the DO before CRUD operations.
892
+ * They can allow/deny operations and inject query filters.
893
+ */
894
+
895
+ /** Context passed to all hooks */
896
+ interface HookContext {
897
+ /** The model (type discriminator) being operated on */
898
+ modelName: string;
899
+ /** The document ID (derived from the DO instance) */
900
+ docId: string;
901
+ /** The raw request (for reading headers, auth tokens, etc.) */
902
+ request: Request;
903
+ /** The DO's SQLite engine (for direct queries, e.g. lookup functions) */
904
+ engine: any;
905
+ }
906
+ /** Context for beforeSave hooks */
907
+ interface BeforeSaveContext extends HookContext {
908
+ /** Record ID being saved */
909
+ id: string;
910
+ /** Data being saved */
911
+ data: Record<string, any>;
912
+ /** StringSet values being saved (if any) */
913
+ stringSets?: Record<string, string[]>;
914
+ /** Whether this is a new record (true) or an update (false) */
915
+ isNew: boolean;
916
+ }
917
+ /** Context for beforeDelete hooks */
918
+ interface BeforeDeleteContext extends HookContext {
919
+ /** Record ID being deleted */
920
+ id: string;
921
+ /** The existing record being deleted (parsed from data_json) */
922
+ record: Record<string, any> | null;
923
+ }
924
+ /** Context for beforeQuery hooks */
925
+ interface BeforeQueryContext extends HookContext {
926
+ /** The filter being applied */
927
+ filter: DocumentFilter;
928
+ /** Query options (sort, limit, etc.) */
929
+ options?: QueryOptions;
930
+ }
931
+ /** Context for afterQuery hooks */
932
+ interface AfterQueryContext extends HookContext {
933
+ /** The query results to filter */
934
+ results: Record<string, any>[];
935
+ }
936
+ /** Result from beforeSave/beforeDelete hooks */
937
+ interface HookResult {
938
+ allow: boolean;
939
+ /** Reason for denial (returned to client as error message) */
940
+ reason?: string;
941
+ }
942
+ /** Result from beforeQuery hooks — can inject additional filters */
943
+ interface BeforeQueryResult extends HookResult {
944
+ /** Additional filter merged into the query via $and */
945
+ injectFilter?: DocumentFilter;
946
+ }
947
+ /** Result from afterQuery hooks — returns filtered results */
948
+ interface AfterQueryResult {
949
+ /** The filtered results to return */
950
+ results: Record<string, any>[];
951
+ }
952
+ /** Hook definitions for createDatabaseDO */
953
+ interface DatabaseDOHooks {
954
+ beforeSave?: (ctx: BeforeSaveContext) => Promise<HookResult>;
955
+ beforeDelete?: (ctx: BeforeDeleteContext) => Promise<HookResult>;
956
+ beforeQuery?: (ctx: BeforeQueryContext) => Promise<BeforeQueryResult>;
957
+ afterQuery?: (ctx: AfterQueryContext) => Promise<AfterQueryResult>;
958
+ }
959
+
960
+ /**
961
+ * Database Durable Object Factory
962
+ *
963
+ * Creates a Durable Object class that serves as a schemaless database store.
964
+ * Each DO instance has its own SQLite database.
965
+ *
966
+ * Usage:
967
+ * ```typescript
968
+ * import { createDatabaseDO } from 'js-bao/cloudflare/do';
969
+ *
970
+ * export const MyDatabaseDO = createDatabaseDO({
971
+ * hooks: {
972
+ * beforeSave: async (ctx) => {
973
+ * // Access control logic
974
+ * return { allow: true };
975
+ * },
976
+ * },
977
+ * });
978
+ * ```
979
+ */
980
+
981
+ interface DatabaseDOConfig {
982
+ /**
983
+ * Hooks for access control. All hooks are async.
984
+ */
985
+ hooks?: DatabaseDOHooks;
986
+ }
987
+ /**
988
+ * @deprecated Use DatabaseDOConfig instead
989
+ */
990
+ type DocumentDOConfig = DatabaseDOConfig;
991
+ /**
992
+ * Request body types for RPC endpoints
993
+ */
994
+ interface QueryRequest {
995
+ modelName: string;
996
+ filter: DocumentFilter;
997
+ options?: QueryOptions;
998
+ }
999
+ interface SaveRequest {
1000
+ modelName: string;
1001
+ id: string;
1002
+ data: Record<string, any>;
1003
+ stringSets?: Record<string, string[]>;
1004
+ ifNotExists?: boolean;
1005
+ condition?: DocumentFilter;
1006
+ }
1007
+ interface DeleteRequest {
1008
+ modelName: string;
1009
+ id: string;
1010
+ condition?: DocumentFilter;
1011
+ }
1012
+ interface CountRequest {
1013
+ modelName: string;
1014
+ filter: DocumentFilter;
1015
+ }
1016
+ interface RegisterIndexRequest {
1017
+ modelName: string;
1018
+ fieldName: string;
1019
+ fieldType: string;
1020
+ unique?: boolean;
1021
+ }
1022
+ interface DropIndexRequest {
1023
+ modelName: string;
1024
+ fieldName: string;
1025
+ }
1026
+ interface RegisterUniqueConstraintRequest {
1027
+ modelName: string;
1028
+ constraintName: string;
1029
+ fields: string[];
1030
+ }
1031
+ interface DropUniqueConstraintRequest {
1032
+ modelName: string;
1033
+ constraintName: string;
1034
+ }
1035
+ /**
1036
+ * Response types
1037
+ */
1038
+ interface QueryResponse {
1039
+ data: Record<string, any>[];
1040
+ hasMore?: boolean;
1041
+ nextCursor?: string;
1042
+ prevCursor?: string;
1043
+ }
1044
+ interface SaveResponse {
1045
+ success: boolean;
1046
+ id: string;
1047
+ }
1048
+ interface DeleteResponse {
1049
+ success: boolean;
1050
+ }
1051
+ interface CountResponse {
1052
+ count: number;
1053
+ }
1054
+ interface ErrorResponse {
1055
+ error: string;
1056
+ code?: string;
1057
+ }
1058
+ interface RegisterIndexResponse {
1059
+ success: boolean;
1060
+ modelName: string;
1061
+ fieldName: string;
1062
+ }
1063
+ interface DropIndexResponse {
1064
+ success: boolean;
1065
+ modelName: string;
1066
+ fieldName: string;
1067
+ }
1068
+ interface IndexListResponse {
1069
+ indexes: IndexEntry[];
1070
+ }
1071
+ interface RegisterUniqueConstraintResponse {
1072
+ success: boolean;
1073
+ modelName: string;
1074
+ constraintName: string;
1075
+ }
1076
+ interface DropUniqueConstraintResponse {
1077
+ success: boolean;
1078
+ modelName: string;
1079
+ constraintName: string;
1080
+ }
1081
+ interface UniqueConstraintListResponse {
1082
+ constraints: UniqueConstraintEntry[];
1083
+ }
1084
+ interface AggregateRequest {
1085
+ modelName: string;
1086
+ options: AggregationOptions;
1087
+ }
1088
+ interface AggregateResponse {
1089
+ result: AggregationResult;
1090
+ }
1091
+ interface SyncIndexesRequest {
1092
+ models: Array<{
1093
+ modelName: string;
1094
+ indexes: Array<{
1095
+ fieldName: string;
1096
+ fieldType: string;
1097
+ unique: boolean;
1098
+ }>;
1099
+ uniqueConstraints: Array<{
1100
+ name: string;
1101
+ fields: string[];
1102
+ }>;
1103
+ }>;
1104
+ }
1105
+ interface SyncIndexesResponse {
1106
+ registered: number;
1107
+ }
1108
+ interface PatchRequest {
1109
+ modelName: string;
1110
+ id: string;
1111
+ data: Record<string, any>;
1112
+ stringSets?: Record<string, string[]>;
1113
+ condition?: DocumentFilter;
1114
+ }
1115
+ interface PatchResponse {
1116
+ success: boolean;
1117
+ id: string;
1118
+ }
1119
+ interface BatchOperation {
1120
+ op: "save" | "patch" | "delete" | "increment" | "addToSet" | "removeFromSet";
1121
+ modelName: string;
1122
+ id: string;
1123
+ data?: Record<string, any>;
1124
+ stringSets?: Record<string, string[]>;
1125
+ fields?: Record<string, number>;
1126
+ ifNotExists?: boolean;
1127
+ condition?: DocumentFilter;
1128
+ }
1129
+ interface BatchRequest {
1130
+ operations: BatchOperation[];
1131
+ }
1132
+ interface BatchOperationResult {
1133
+ success: boolean;
1134
+ id: string;
1135
+ error?: string;
1136
+ values?: Record<string, number>;
1137
+ }
1138
+ interface BatchResponse {
1139
+ results: BatchOperationResult[];
1140
+ }
1141
+ interface IncrementRequest {
1142
+ modelName: string;
1143
+ id: string;
1144
+ fields: Record<string, number>;
1145
+ condition?: DocumentFilter;
1146
+ }
1147
+ interface IncrementResponse {
1148
+ success: boolean;
1149
+ id: string;
1150
+ values: Record<string, number>;
1151
+ }
1152
+ interface StringSetUpdateRequest {
1153
+ modelName: string;
1154
+ id: string;
1155
+ sets: Record<string, string[]>;
1156
+ condition?: DocumentFilter;
1157
+ }
1158
+ interface StringSetUpdateResponse {
1159
+ success: boolean;
1160
+ }
1161
+ /**
1162
+ * Create a Durable Object class for schemaless database storage.
1163
+ *
1164
+ * The returned class can be exported and used in wrangler.toml:
1165
+ * ```toml
1166
+ * [durable_objects]
1167
+ * bindings = [
1168
+ * { name = "DATABASE_DO", class_name = "MyDatabaseDO" }
1169
+ * ]
1170
+ * ```
1171
+ */
1172
+ declare function createDatabaseDO(config?: DatabaseDOConfig): {
1173
+ new (state: DurableObjectState, _env: unknown): {
1174
+ /** @internal */
1175
+ _doState: DurableObjectState;
1176
+ /** @internal */
1177
+ _engine: DurableObjectEngine;
1178
+ /** @internal */
1179
+ _initialized: boolean;
1180
+ /** @internal — cache for $contains misuse check: "model:field" keys known to be in data_json */
1181
+ _containsMisuseCache: Set<string>;
1182
+ get state(): DurableObjectState;
1183
+ get engine(): DurableObjectEngine;
1184
+ /** @internal */
1185
+ _ensureInitialized(): Promise<void>;
1186
+ fetch(request: Request): Promise<Response>;
1187
+ /** @internal */
1188
+ _handleQuery(request: Request, docId: string): Promise<Response>;
1189
+ /** @internal — Check for reserved field names in record data */
1190
+ _checkReservedFields(data: Record<string, any>): string | null;
1191
+ /** @internal */
1192
+ _handleSave(request: Request, docId: string): Promise<Response>;
1193
+ /** @internal — Partial update: merge provided fields into existing record */
1194
+ _handlePatch(request: Request, docId: string): Promise<Response>;
1195
+ /** @internal */
1196
+ _handleDelete(request: Request, docId: string): Promise<Response>;
1197
+ /** @internal — Execute multiple save/patch/delete operations in a single transaction */
1198
+ _handleBatch(request: Request, docId: string): Promise<Response>;
1199
+ /** @internal */
1200
+ _handleCount(request: Request, docId: string): Promise<Response>;
1201
+ /** @internal — Atomically increment/decrement numeric fields */
1202
+ _handleIncrement(request: Request, _docId: string): Promise<Response>;
1203
+ /** @internal — Atomically add values to StringSet fields */
1204
+ _handleStringSetAdd(request: Request, _docId: string): Promise<Response>;
1205
+ /** @internal — Atomically remove values from StringSet fields */
1206
+ _handleStringSetRemove(request: Request, _docId: string): Promise<Response>;
1207
+ _handleAggregate(request: Request, docId: string): Promise<Response>;
1208
+ /** @internal — Build SQL for StringSet facet aggregation */
1209
+ _buildStringSetFacetSql(modelName: string, facetField: string, aggOptions: AggregationOptions, filter: DocumentFilter, translator: JsonQueryTranslator): {
1210
+ sql: string;
1211
+ params: any[];
1212
+ };
1213
+ /** @internal — Build SQL for regular field aggregation */
1214
+ _buildRegularAggregationSql(modelName: string, regularGroupBy: string[], stringSetMemberships: Array<{
1215
+ field: string;
1216
+ contains: string;
1217
+ }>, aggOptions: AggregationOptions, filter: DocumentFilter, translator: JsonQueryTranslator): {
1218
+ sql: string;
1219
+ params: any[];
1220
+ aliasMap: Array<{
1221
+ alias: string;
1222
+ field: string;
1223
+ contains: string;
1224
+ }>;
1225
+ };
1226
+ /** @internal — Extract operation value(s) from a row. Flattens single-op results. */
1227
+ _extractOpValue(row: any, operations: AggregationOptions["operations"]): any;
1228
+ /** @internal — Process raw aggregation rows into nested result */
1229
+ _processAggregationResults(results: any[], aggOptions: AggregationOptions, aliasMap: Array<{
1230
+ alias: string;
1231
+ field: string;
1232
+ contains: string;
1233
+ }>, stringSetFacetField: string | null): AggregationResult;
1234
+ /** @internal */
1235
+ /** @internal — Batch sync: compare desired indexes against _indexes table, register missing */
1236
+ _handleIndexesSync(request: Request): Promise<Response>;
1237
+ /** @internal */
1238
+ _handleIndexRegister(request: Request): Promise<Response>;
1239
+ /** @internal */
1240
+ _handleIndexDrop(request: Request): Promise<Response>;
1241
+ /** @internal */
1242
+ _handleIndexList(request: Request): Response;
1243
+ /** @internal */
1244
+ _handleUniqueConstraintRegister(request: Request): Promise<Response>;
1245
+ /** @internal */
1246
+ _handleUniqueConstraintDrop(request: Request): Promise<Response>;
1247
+ /** @internal */
1248
+ _handleUniqueConstraintList(request: Request): Response;
1249
+ /** @internal */
1250
+ /**
1251
+ * Extract field names that use $contains from a filter tree.
1252
+ * @internal
1253
+ */
1254
+ _findContainsFields(filter: DocumentFilter): string[];
1255
+ /**
1256
+ * Check for $contains misuse with caching.
1257
+ * Returns an error Response if misuse is detected, or null if OK.
1258
+ * @internal
1259
+ */
1260
+ _checkContainsMisuse(modelName: string, filter: DocumentFilter): Response | null;
1261
+ /**
1262
+ * Check a write condition against the current state of a record.
1263
+ * Returns true if the condition is met (record exists and matches the filter).
1264
+ * Returns false if the record doesn't exist or doesn't match.
1265
+ * @internal
1266
+ */
1267
+ _checkCondition(modelName: string, id: string, condition: DocumentFilter): boolean;
1268
+ _handleHealth(): Response;
1269
+ /** @internal — Return tracked field names and types for a model */
1270
+ _handleDescribe(request: Request): Response;
1271
+ /** @internal — List all known model names from records and _model_fields */
1272
+ _handleModelList(): Response;
1273
+ /** @internal */
1274
+ _errorResponse(message: string, status: number): Response;
1275
+ /** @internal */
1276
+ _parseRow(row: Record<string, any>): Record<string, any>;
1277
+ /** @internal — Validate an IncludeSpec, returning an error message or null */
1278
+ _validateIncludeSpec(spec: IncludeSpec): string | null;
1279
+ /** @internal — Resolve all includes for a set of records */
1280
+ _resolveIncludes(records: Record<string, any>[], includes: IncludeSpec[], depth: number, _parentModelName?: string): Record<string, any>[];
1281
+ /** @internal — Resolve a refersTo include (parent FK → single related record) */
1282
+ _resolveRefersTo(records: Record<string, any>[], spec: IncludeSpec, resultKey: string): void;
1283
+ /** @internal — Resolve a refersToMany include (parent StringSet field → array of related records) */
1284
+ _resolveRefersToMany(records: Record<string, any>[], spec: IncludeSpec, resultKey: string): void;
1285
+ /** @internal — Resolve a hasMany include (target FK → array of related records) */
1286
+ _resolveHasMany(records: Record<string, any>[], spec: IncludeSpec, resultKey: string): void;
1287
+ /** @internal — Simple hasMany without per-parent limit */
1288
+ _resolveHasManySimple(spec: IncludeSpec, parentValues: any[]): Record<string, any>[];
1289
+ /** @internal — hasMany with per-parent limit using ROW_NUMBER() */
1290
+ _resolveHasManyWithLimit(spec: IncludeSpec, parentValues: any[]): Record<string, any>[];
1291
+ /**
1292
+ * @internal — Execute IN queries in chunks to stay under Cloudflare DO's
1293
+ * 100 bound parameter limit per SQL statement.
1294
+ */
1295
+ _chunkedIn(model: string, field: string, values: any[], extraFilter?: DocumentFilter, extraOptions?: {
1296
+ sort?: SortSpec;
1297
+ projection?: ProjectionSpec;
1298
+ }): Record<string, any>[];
1299
+ /** @internal — Apply projection to a single record */
1300
+ _applyProjection(record: Record<string, any>, projection: ProjectionSpec): Record<string, any>;
1301
+ };
1302
+ };
1303
+ /**
1304
+ * @deprecated Use createDatabaseDO instead
1305
+ */
1306
+ declare const createDocumentDO: typeof createDatabaseDO;
1307
+
1308
+ /**
1309
+ * Cloudflare Worker Router Template
1310
+ *
1311
+ * This file provides a template for routing requests to Document Durable Objects.
1312
+ * Copy and customize this for your worker implementation.
1313
+ *
1314
+ * Usage:
1315
+ * 1. Copy this file to your worker project
1316
+ * 2. Import your models and create the DO class
1317
+ * 3. Configure wrangler.toml with the DO binding
1318
+ * 4. Deploy with `wrangler deploy`
1319
+ *
1320
+ * Example wrangler.toml:
1321
+ * ```toml
1322
+ * name = "my-worker"
1323
+ * main = "src/index.ts"
1324
+ * compatibility_date = "2024-01-01"
1325
+ *
1326
+ * [[durable_objects.bindings]]
1327
+ * name = "DOCUMENT_DO"
1328
+ * class_name = "DocumentDO"
1329
+ *
1330
+ * [[migrations]]
1331
+ * tag = "v1"
1332
+ * new_sqlite_classes = ["DocumentDO"]
1333
+ * ```
1334
+ */
1335
+
1336
+ /**
1337
+ * Environment interface - customize for your worker
1338
+ */
1339
+ interface Env {
1340
+ /**
1341
+ * The Durable Object namespace binding
1342
+ */
1343
+ DOCUMENT_DO: DurableObjectNamespace;
1344
+ }
1345
+ /**
1346
+ * Create the worker export
1347
+ *
1348
+ * Example usage in your worker:
1349
+ * ```typescript
1350
+ * import { createDocumentDO } from 'js-bao/cloudflare/do';
1351
+ * import { Statement } from './models';
1352
+ *
1353
+ * // Create the DO class
1354
+ * export const DocumentDO = createDocumentDO({ models: [Statement] });
1355
+ *
1356
+ * // Export the worker
1357
+ * export default {
1358
+ * async fetch(request: Request, env: Env): Promise<Response> {
1359
+ * return handleRequest(request, env);
1360
+ * }
1361
+ * };
1362
+ * ```
1363
+ */
1364
+ declare function handleRequest(request: Request, env: Env): Promise<Response>;
1365
+
1366
+ export { type AfterQueryContext, type AfterQueryResult, type AggregateRequest, type AggregateResponse, type AggregationOperation, type AggregationOptions, type AggregationResult, type BatchOperation, type BatchOperationResult, type BatchRequest, type BatchResponse, type BeforeDeleteContext, type BeforeQueryContext, type BeforeQueryResult, type BeforeSaveContext, type CountRequest, type CountResponse, type DatabaseDOConfig, type DatabaseDOHooks, type DeleteRequest, type DeleteResponse, type DocumentDOConfig, type DropIndexRequest, type DropIndexResponse, type DropUniqueConstraintRequest, type DropUniqueConstraintResponse, DurableObjectEngine, type DurableObjectEngineOptions, type DurableObjectId, type DurableObjectNamespace, type DurableObjectState, type DurableObjectStorage, type DurableObjectStub, type Env, type ErrorResponse, type GroupByField, type HookContext, type HookResult, type IncrementRequest, type IncrementResponse, type IndexEntry, type IndexListResponse, JsonQueryTranslator, type JsonQueryTranslatorOptions, JsonSchemaDDL, type JsonSchemaOptions, type PatchRequest, type PatchResponse, type QueryRequest, type QueryResponse, type RegisterIndexRequest, type RegisterIndexResponse, type RegisterUniqueConstraintRequest, type RegisterUniqueConstraintResponse, type SaveRequest, type SaveResponse, type SqlStorage, type SqlStorageCursor, type StringSetMembership, type StringSetUpdateRequest, type StringSetUpdateResponse, type SyncIndexesRequest, type SyncIndexesResponse, type UniqueConstraintEntry, type UniqueConstraintListResponse, createDatabaseDO, createDocumentDO, handleRequest };