js-bao 0.2.11 → 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 +260 -19
  57. package/dist/environment-TOTQICSE.js +17 -0
  58. package/dist/environment-TOTQICSE.js.map +1 -0
  59. package/dist/index.cjs +1905 -1492
  60. package/dist/index.d.cts +19 -2
  61. package/dist/index.d.ts +19 -2
  62. package/dist/index.js +1870 -1457
  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 +4758 -4345
  67. package/package.json +42 -13
@@ -0,0 +1,837 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/models/StringSet.ts
34
+ var init_StringSet = __esm({
35
+ "src/models/StringSet.ts"() {
36
+ "use strict";
37
+ }
38
+ });
39
+
40
+ // src/types/documentTypes.ts
41
+ var init_documentTypes = __esm({
42
+ "src/types/documentTypes.ts"() {
43
+ "use strict";
44
+ }
45
+ });
46
+
47
+ // src/types/queryTypes.ts
48
+ var init_queryTypes = __esm({
49
+ "src/types/queryTypes.ts"() {
50
+ "use strict";
51
+ }
52
+ });
53
+
54
+ // src/query/CursorManager.ts
55
+ var init_CursorManager = __esm({
56
+ "src/query/CursorManager.ts"() {
57
+ "use strict";
58
+ init_queryTypes();
59
+ }
60
+ });
61
+
62
+ // src/utils/sql.ts
63
+ var init_sql = __esm({
64
+ "src/utils/sql.ts"() {
65
+ "use strict";
66
+ }
67
+ });
68
+
69
+ // src/utils/patterns.ts
70
+ var init_patterns = __esm({
71
+ "src/utils/patterns.ts"() {
72
+ "use strict";
73
+ }
74
+ });
75
+
76
+ // src/query/DocumentQueryTranslator.ts
77
+ var init_DocumentQueryTranslator = __esm({
78
+ "src/query/DocumentQueryTranslator.ts"() {
79
+ "use strict";
80
+ init_queryTypes();
81
+ init_CursorManager();
82
+ init_sql();
83
+ init_patterns();
84
+ }
85
+ });
86
+
87
+ // src/models/BaseModel.ts
88
+ var Y, import_ulid, Logger;
89
+ var init_BaseModel = __esm({
90
+ "src/models/BaseModel.ts"() {
91
+ "use strict";
92
+ Y = __toESM(require("yjs"), 1);
93
+ import_ulid = require("ulid");
94
+ init_StringSet();
95
+ init_documentTypes();
96
+ init_DocumentQueryTranslator();
97
+ init_CursorManager();
98
+ init_sql();
99
+ Logger = class {
100
+ static _logLevel = 1 /* ERROR */;
101
+ static _logCallback = null;
102
+ static setLogLevel(level) {
103
+ this._logLevel = level;
104
+ }
105
+ static getLogLevel() {
106
+ return this._logLevel;
107
+ }
108
+ static setLogCallback(callback) {
109
+ this._logCallback = callback;
110
+ }
111
+ static error(message, ...args) {
112
+ if (this._logLevel >= 1 /* ERROR */) {
113
+ const fullMessage = args.length > 0 ? `${message} ${args.map(
114
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
115
+ ).join(" ")}` : message;
116
+ console.error(`[ERROR] ${message}`, ...args);
117
+ if (this._logCallback) {
118
+ this._logCallback(fullMessage, 1 /* ERROR */);
119
+ }
120
+ }
121
+ }
122
+ static warn(message, ...args) {
123
+ if (this._logLevel >= 2 /* WARN */) {
124
+ const fullMessage = args.length > 0 ? `${message} ${args.map(
125
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
126
+ ).join(" ")}` : message;
127
+ console.warn(`[WARN] ${message}`, ...args);
128
+ if (this._logCallback) {
129
+ this._logCallback(fullMessage, 2 /* WARN */);
130
+ }
131
+ }
132
+ }
133
+ static info(message, ...args) {
134
+ if (this._logLevel >= 3 /* INFO */) {
135
+ const fullMessage = args.length > 0 ? `${message} ${args.map(
136
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
137
+ ).join(" ")}` : message;
138
+ console.log(`[INFO] ${message}`, ...args);
139
+ if (this._logCallback) {
140
+ this._logCallback(fullMessage, 3 /* INFO */);
141
+ }
142
+ }
143
+ }
144
+ static debug(message, ...args) {
145
+ if (this._logLevel >= 4 /* DEBUG */) {
146
+ const fullMessage = args.length > 0 ? `${message} ${args.map(
147
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
148
+ ).join(" ")}` : message;
149
+ console.log(`[DEBUG] ${message}`, ...args);
150
+ if (this._logCallback) {
151
+ this._logCallback(fullMessage, 4 /* DEBUG */);
152
+ }
153
+ }
154
+ }
155
+ static verbose(message, ...args) {
156
+ if (this._logLevel >= 5 /* VERBOSE */) {
157
+ const fullMessage = args.length > 0 ? `${message} ${args.map(
158
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
159
+ ).join(" ")}` : message;
160
+ console.log(`[VERBOSE] ${message}`, ...args);
161
+ if (this._logCallback) {
162
+ this._logCallback(fullMessage, 5 /* VERBOSE */);
163
+ }
164
+ }
165
+ }
166
+ };
167
+ }
168
+ });
169
+
170
+ // src/client.ts
171
+ var client_exports = {};
172
+ __export(client_exports, {
173
+ DOClientEngine: () => DOClientEngine,
174
+ connectDoDb: () => connectDoDb
175
+ });
176
+ module.exports = __toCommonJS(client_exports);
177
+
178
+ // src/initialize-do.ts
179
+ init_BaseModel();
180
+
181
+ // src/engines/DatabaseEngine.ts
182
+ var DatabaseEngine = class {
183
+ createTable(_modelName, _schema, _options) {
184
+ throw new Error("Method not implemented.");
185
+ }
186
+ createStringSetJunctionTable(_modelName, _fieldName) {
187
+ throw new Error("Method not implemented.");
188
+ }
189
+ insertStringSetValues(_modelName, _fieldName, _recordId, _values) {
190
+ throw new Error("Method not implemented.");
191
+ }
192
+ removeStringSetValues(_modelName, _fieldName, _recordId, _values) {
193
+ throw new Error("Method not implemented.");
194
+ }
195
+ insert(_modelName, _data) {
196
+ throw new Error("Method not implemented.");
197
+ }
198
+ delete(_modelName, _id) {
199
+ throw new Error("Method not implemented.");
200
+ }
201
+ /**
202
+ * Deletes all records for a specific document from the given model table.
203
+ * This is used when disconnecting a document to remove all its data.
204
+ * @param modelName The name of the model/table
205
+ * @param docId The document ID to filter by
206
+ */
207
+ deleteByDocumentId(_modelName, _docId) {
208
+ throw new Error("Method not implemented.");
209
+ }
210
+ getTableName(_modelName) {
211
+ throw new Error("Method not implemented.");
212
+ }
213
+ // Transaction support
214
+ async withTransaction(_callback) {
215
+ throw new Error("Method not implemented.");
216
+ }
217
+ };
218
+
219
+ // src/engines/cloudflare/DOClientEngine.ts
220
+ var DOClientEngine = class extends DatabaseEngine {
221
+ endpoint;
222
+ customFetch;
223
+ authorization;
224
+ timeout;
225
+ currentDocId = null;
226
+ constructor(config) {
227
+ super();
228
+ this.endpoint = config.endpoint.replace(/\/$/, "");
229
+ this.customFetch = config.fetch || fetch;
230
+ this.authorization = config.authorization;
231
+ this.timeout = config.timeout || 3e4;
232
+ }
233
+ /**
234
+ * Set the current document ID for subsequent operations.
235
+ */
236
+ setCurrentDocument(docId) {
237
+ this.currentDocId = docId;
238
+ }
239
+ /**
240
+ * Get the current document ID.
241
+ */
242
+ getCurrentDocument() {
243
+ return this.currentDocId;
244
+ }
245
+ /**
246
+ * Build the URL for a DO endpoint.
247
+ */
248
+ buildUrl(path, extraParams) {
249
+ if (!this.currentDocId) {
250
+ throw new Error("No document ID set. Call setCurrentDocument() first.");
251
+ }
252
+ const url = new URL(`${this.endpoint}${path}`);
253
+ url.searchParams.set("docId", this.currentDocId);
254
+ if (extraParams) {
255
+ for (const [key, value] of Object.entries(extraParams)) {
256
+ url.searchParams.set(key, value);
257
+ }
258
+ }
259
+ return url.toString();
260
+ }
261
+ /**
262
+ * Make a fetch request to the DO.
263
+ */
264
+ async doFetch(path, body) {
265
+ const url = this.buildUrl(path);
266
+ const headers = {
267
+ "Content-Type": "application/json"
268
+ };
269
+ if (this.authorization) {
270
+ headers["Authorization"] = this.authorization;
271
+ }
272
+ const controller = new AbortController();
273
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
274
+ try {
275
+ const response = await this.customFetch(url, {
276
+ method: "POST",
277
+ headers,
278
+ body: JSON.stringify(body),
279
+ signal: controller.signal
280
+ });
281
+ clearTimeout(timeoutId);
282
+ if (!response.ok) {
283
+ const errorBody = await response.json();
284
+ throw new Error(errorBody.error || `HTTP ${response.status}`);
285
+ }
286
+ return response.json();
287
+ } catch (error) {
288
+ clearTimeout(timeoutId);
289
+ if (error instanceof Error && error.name === "AbortError") {
290
+ throw new Error(`Request timeout after ${this.timeout}ms`);
291
+ }
292
+ throw error;
293
+ }
294
+ }
295
+ /**
296
+ * Query records from the DO.
297
+ */
298
+ async queryModel(modelName, filter = {}, options = {}) {
299
+ const request = {
300
+ modelName,
301
+ filter,
302
+ options
303
+ };
304
+ const response = await this.doFetch("/query", request);
305
+ return {
306
+ data: response.data,
307
+ hasMore: response.hasMore ?? false,
308
+ nextCursor: response.nextCursor,
309
+ prevCursor: response.prevCursor
310
+ };
311
+ }
312
+ /**
313
+ * Save a record to the DO.
314
+ */
315
+ async saveModel(modelName, id, data, stringSets, options) {
316
+ const request = {
317
+ modelName,
318
+ id,
319
+ data,
320
+ stringSets,
321
+ ifNotExists: options?.ifNotExists,
322
+ condition: options?.condition
323
+ };
324
+ const response = await this.doFetch("/save", request);
325
+ return response.id;
326
+ }
327
+ /**
328
+ * Patch (partial update) a record in the DO.
329
+ * Only the provided fields are updated; existing fields are preserved.
330
+ */
331
+ async patchModel(modelName, id, data, stringSets, options) {
332
+ const request = {
333
+ modelName,
334
+ id,
335
+ data,
336
+ stringSets,
337
+ condition: options?.condition
338
+ };
339
+ const response = await this.doFetch("/patch", request);
340
+ return response.id;
341
+ }
342
+ /**
343
+ * Delete a record from the DO.
344
+ */
345
+ async deleteModel(modelName, id, options) {
346
+ const request = {
347
+ modelName,
348
+ id,
349
+ condition: options?.condition
350
+ };
351
+ const response = await this.doFetch("/delete", request);
352
+ return response.success;
353
+ }
354
+ /**
355
+ * Count records matching a filter.
356
+ */
357
+ async countModel(modelName, filter = {}) {
358
+ const request = {
359
+ modelName,
360
+ filter
361
+ };
362
+ const response = await this.doFetch("/count", request);
363
+ return response.count;
364
+ }
365
+ /**
366
+ * Aggregate records with groupBy and operations (count, sum, avg, min, max).
367
+ */
368
+ async aggregateModel(modelName, options) {
369
+ const request = {
370
+ modelName,
371
+ options
372
+ };
373
+ const response = await this.doFetch("/aggregate", request);
374
+ return response.result;
375
+ }
376
+ /**
377
+ * Atomically add values to StringSet fields on a record.
378
+ */
379
+ async addToStringSet(modelName, id, sets, options) {
380
+ const request = { modelName, id, sets, condition: options?.condition };
381
+ await this.doFetch("/stringset/add", request);
382
+ }
383
+ /**
384
+ * Atomically remove values from StringSet fields on a record.
385
+ */
386
+ async removeFromStringSet(modelName, id, sets, options) {
387
+ const request = { modelName, id, sets, condition: options?.condition };
388
+ await this.doFetch("/stringset/remove", request);
389
+ }
390
+ /**
391
+ * Atomically increment/decrement numeric fields on a record.
392
+ * Returns the new values after the increment.
393
+ */
394
+ async incrementFields(modelName, id, fields, options) {
395
+ const request = { modelName, id, fields, condition: options?.condition };
396
+ const response = await this.doFetch("/increment", request);
397
+ return response.values;
398
+ }
399
+ /**
400
+ * Execute multiple save/patch/delete operations in a single request.
401
+ * All operations run in a single transaction on the server.
402
+ */
403
+ async batchWrite(operations) {
404
+ const request = { operations };
405
+ const response = await this.doFetch("/batch", request);
406
+ return response.results;
407
+ }
408
+ /**
409
+ * Check if the DO is healthy.
410
+ */
411
+ async healthCheck() {
412
+ const url = this.buildUrl("/health");
413
+ const response = await this.customFetch(url, {
414
+ method: "GET",
415
+ headers: this.authorization ? { Authorization: this.authorization } : void 0
416
+ });
417
+ if (!response.ok) {
418
+ throw new Error(`Health check failed: HTTP ${response.status}`);
419
+ }
420
+ return response.json();
421
+ }
422
+ /**
423
+ * Batch sync indexes: send all desired indexes in one request.
424
+ * The DO compares against its _indexes table and registers only what's missing.
425
+ * Returns the number of indexes/constraints newly registered.
426
+ */
427
+ async syncIndexesBatch(request) {
428
+ const response = await this.doFetch("/indexes/sync", request);
429
+ return response.registered;
430
+ }
431
+ /**
432
+ * Register an index on a model field.
433
+ * Creates a SQLite index on json_extract(data_json, '$.fieldName').
434
+ * Set unique=true to enforce uniqueness on this field.
435
+ */
436
+ async registerIndex(modelName, fieldName, fieldType = "string", unique = false) {
437
+ const request = {
438
+ modelName,
439
+ fieldName,
440
+ fieldType,
441
+ unique
442
+ };
443
+ await this.doFetch("/index/register", request);
444
+ }
445
+ /**
446
+ * Drop an index from a model field.
447
+ */
448
+ async dropIndex(modelName, fieldName) {
449
+ const request = {
450
+ modelName,
451
+ fieldName
452
+ };
453
+ await this.doFetch("/index/drop", request);
454
+ }
455
+ /**
456
+ * List indexes, optionally filtered by model name.
457
+ */
458
+ async listIndexes(modelName) {
459
+ const url = this.buildUrl(
460
+ "/indexes",
461
+ modelName ? { modelName } : void 0
462
+ );
463
+ const response = await this.customFetch(url, {
464
+ method: "GET",
465
+ headers: this.authorization ? { Authorization: this.authorization } : void 0
466
+ });
467
+ if (!response.ok) {
468
+ throw new Error(`List indexes failed: HTTP ${response.status}`);
469
+ }
470
+ const body = await response.json();
471
+ return body.indexes;
472
+ }
473
+ /**
474
+ * Describe tracked fields for a model.
475
+ */
476
+ async describe(modelName) {
477
+ const url = this.buildUrl("/describe", { modelName });
478
+ const response = await this.customFetch(url, {
479
+ method: "GET",
480
+ headers: this.authorization ? { Authorization: this.authorization } : void 0
481
+ });
482
+ if (!response.ok) {
483
+ throw new Error(`Describe failed: HTTP ${response.status}`);
484
+ }
485
+ const body = await response.json();
486
+ return body.fields;
487
+ }
488
+ /**
489
+ * Register a composite unique constraint across multiple fields.
490
+ */
491
+ async registerUniqueConstraint(modelName, constraintName, fields) {
492
+ const request = {
493
+ modelName,
494
+ constraintName,
495
+ fields
496
+ };
497
+ await this.doFetch(
498
+ "/unique-constraint/register",
499
+ request
500
+ );
501
+ }
502
+ /**
503
+ * Drop a composite unique constraint.
504
+ */
505
+ async dropUniqueConstraint(modelName, constraintName) {
506
+ const request = {
507
+ modelName,
508
+ constraintName
509
+ };
510
+ await this.doFetch(
511
+ "/unique-constraint/drop",
512
+ request
513
+ );
514
+ }
515
+ /**
516
+ * List composite unique constraints, optionally filtered by model name.
517
+ */
518
+ async listUniqueConstraints(modelName) {
519
+ const url = this.buildUrl(
520
+ "/unique-constraints",
521
+ modelName ? { modelName } : void 0
522
+ );
523
+ const response = await this.customFetch(url, {
524
+ method: "GET",
525
+ headers: this.authorization ? { Authorization: this.authorization } : void 0
526
+ });
527
+ if (!response.ok) {
528
+ throw new Error(
529
+ `List unique constraints failed: HTTP ${response.status}`
530
+ );
531
+ }
532
+ const body = await response.json();
533
+ return body.constraints;
534
+ }
535
+ // ========================================
536
+ // DatabaseEngine interface implementation
537
+ // ========================================
538
+ /**
539
+ * Ensure the engine is ready.
540
+ * For DOClient, this verifies connectivity.
541
+ */
542
+ async ensureReady() {
543
+ if (this.currentDocId) {
544
+ await this.healthCheck();
545
+ }
546
+ }
547
+ /**
548
+ * Execute raw SQL.
549
+ * Not supported in DO client mode - use queryModel instead.
550
+ */
551
+ async query(_sql, _params) {
552
+ throw new Error(
553
+ "Raw SQL queries not supported in DO client mode. Use queryModel() instead."
554
+ );
555
+ }
556
+ /**
557
+ * Get last error message.
558
+ */
559
+ getLastErrorMessage() {
560
+ return void 0;
561
+ }
562
+ /**
563
+ * Get table schema.
564
+ * Not directly supported - schema is managed by the DO.
565
+ */
566
+ async getTableSchema(_tableName) {
567
+ throw new Error("getTableSchema not supported in DO client mode");
568
+ }
569
+ /**
570
+ * Destroy the engine.
571
+ * Nothing to clean up for the client.
572
+ */
573
+ async destroy() {
574
+ this.currentDocId = null;
575
+ }
576
+ /**
577
+ * Create table.
578
+ * No-op in DO client mode - schema is managed by the DO.
579
+ */
580
+ async createTable(_modelName, _schema, _options) {
581
+ }
582
+ /**
583
+ * Create StringSet junction table.
584
+ * No-op in DO client mode.
585
+ */
586
+ async createStringSetJunctionTable(_modelName, _fieldName) {
587
+ }
588
+ /**
589
+ * Insert a record.
590
+ * Delegates to saveModel.
591
+ */
592
+ async insert(modelName, data) {
593
+ const { id, ...rest } = data;
594
+ await this.saveModel(modelName, id, rest);
595
+ }
596
+ /**
597
+ * Delete a record.
598
+ * Delegates to deleteModel.
599
+ */
600
+ async delete(modelName, id) {
601
+ await this.deleteModel(modelName, id);
602
+ }
603
+ /**
604
+ * Get table name.
605
+ * All models use 'records' in JSON schema.
606
+ */
607
+ getTableName(_modelName) {
608
+ return "records";
609
+ }
610
+ /**
611
+ * Transaction support.
612
+ * DO client doesn't support client-side transactions.
613
+ * Operations are atomic on the DO side.
614
+ */
615
+ async withTransaction(callback) {
616
+ const ops = {
617
+ insert: async (modelName, data) => {
618
+ await this.insert(modelName, data);
619
+ },
620
+ delete: async (modelName, id) => {
621
+ await this.delete(modelName, id);
622
+ },
623
+ query: async (_sql, _params) => {
624
+ throw new Error("Raw SQL not supported in DO client transactions");
625
+ }
626
+ };
627
+ return callback(ops);
628
+ }
629
+ };
630
+
631
+ // src/initialize-do.ts
632
+ function resolveModelName(model) {
633
+ if (typeof model === "string") {
634
+ if (!model) throw new Error("Model name must be a non-empty string");
635
+ return model;
636
+ }
637
+ const name = model.modelName;
638
+ if (!name) {
639
+ throw new Error(
640
+ `Model ${model.name} has no modelName. Ensure it was defined with defineModelSchema + attachSchemaToClass.`
641
+ );
642
+ }
643
+ return name;
644
+ }
645
+ function createModelAccessor(engine, modelName) {
646
+ return {
647
+ query: (filter = {}, options = {}) => {
648
+ return engine.queryModel(modelName, filter, options);
649
+ },
650
+ find: async (id) => {
651
+ const result = await engine.queryModel(modelName, { id }, {});
652
+ return result.data.length > 0 ? result.data[0] : null;
653
+ },
654
+ save: (data, options) => {
655
+ if (!data.id) {
656
+ throw new Error("Record must have an 'id' field");
657
+ }
658
+ let stringSets;
659
+ let ifNotExists;
660
+ let condition;
661
+ if (options && typeof options === "object") {
662
+ if (options.ifNotExists !== void 0 || options.stringSets !== void 0 || options.condition !== void 0) {
663
+ stringSets = options.stringSets;
664
+ ifNotExists = options.ifNotExists;
665
+ condition = options.condition;
666
+ } else {
667
+ stringSets = options;
668
+ }
669
+ }
670
+ return engine.saveModel(modelName, data.id, data, stringSets, { ifNotExists, condition });
671
+ },
672
+ patch: (id, data, options) => {
673
+ let stringSets;
674
+ let condition;
675
+ if (options && typeof options === "object") {
676
+ if (options.condition !== void 0 || options.stringSets !== void 0) {
677
+ stringSets = options.stringSets;
678
+ condition = options.condition;
679
+ } else {
680
+ stringSets = options;
681
+ }
682
+ }
683
+ return engine.patchModel(modelName, id, data, stringSets, { condition });
684
+ },
685
+ delete: (id, options) => {
686
+ return engine.deleteModel(modelName, id, { condition: options?.condition });
687
+ },
688
+ count: (filter = {}) => {
689
+ return engine.countModel(modelName, filter);
690
+ },
691
+ aggregate: (options) => {
692
+ return engine.aggregateModel(modelName, options);
693
+ },
694
+ increment: (id, fields, options) => {
695
+ return engine.incrementFields(modelName, id, fields, { condition: options?.condition });
696
+ },
697
+ addToSet: (id, sets, options) => {
698
+ return engine.addToStringSet(modelName, id, sets, { condition: options?.condition });
699
+ },
700
+ removeFromSet: (id, sets, options) => {
701
+ return engine.removeFromStringSet(modelName, id, sets, { condition: options?.condition });
702
+ }
703
+ };
704
+ }
705
+ function extractModelSyncState(modelClass) {
706
+ const schema = modelClass.getSchema?.();
707
+ if (!schema || !schema.fields || !schema.options?.name) {
708
+ throw new Error(
709
+ `Cannot sync indexes: model ${modelClass.name} has no schema. Ensure it was defined with defineModelSchema + attachAndRegisterModel.`
710
+ );
711
+ }
712
+ const modelName = schema.options.name;
713
+ const fields = schema.fields;
714
+ const indexes = [];
715
+ for (const [fieldName, opts] of fields.entries()) {
716
+ if (fieldName === "id") continue;
717
+ if (!opts.indexed && !opts.unique) continue;
718
+ indexes.push({
719
+ fieldName,
720
+ fieldType: opts.type || "string",
721
+ unique: opts.unique ?? false
722
+ });
723
+ }
724
+ const uniqueConstraints = (schema.options.uniqueConstraints ?? []).map(
725
+ (c) => ({ name: c.name, fields: c.fields })
726
+ );
727
+ return { modelName, indexes, uniqueConstraints };
728
+ }
729
+ function buildSyncIndexes(engine) {
730
+ return async (modelClass) => {
731
+ const modelState = extractModelSyncState(modelClass);
732
+ return engine.syncIndexesBatch({ models: [modelState] });
733
+ };
734
+ }
735
+ function connectDoDb(options) {
736
+ const { endpoint, id, models, authorization, fetch: customFetch, timeout } = options;
737
+ const engine = new DOClientEngine({
738
+ endpoint,
739
+ authorization,
740
+ fetch: customFetch,
741
+ timeout
742
+ });
743
+ engine.setCurrentDocument(id);
744
+ const syncIndexes = buildSyncIndexes(engine);
745
+ const db = {
746
+ engine,
747
+ docId: id,
748
+ // Ad-hoc methods
749
+ query: (model, filter = {}, opts = {}) => {
750
+ return engine.queryModel(resolveModelName(model), filter, opts);
751
+ },
752
+ find: async (model, findId) => {
753
+ const result = await engine.queryModel(resolveModelName(model), { id: findId }, {});
754
+ return result.data.length > 0 ? result.data[0] : null;
755
+ },
756
+ save: (model, data, options2) => {
757
+ if (!data.id) {
758
+ throw new Error("Record must have an 'id' field");
759
+ }
760
+ let stringSets;
761
+ let ifNotExists;
762
+ let condition;
763
+ if (options2 && typeof options2 === "object") {
764
+ if (options2.ifNotExists !== void 0 || options2.stringSets !== void 0 || options2.condition !== void 0) {
765
+ stringSets = options2.stringSets;
766
+ ifNotExists = options2.ifNotExists;
767
+ condition = options2.condition;
768
+ } else {
769
+ stringSets = options2;
770
+ }
771
+ }
772
+ return engine.saveModel(resolveModelName(model), data.id, data, stringSets, { ifNotExists, condition });
773
+ },
774
+ patch: (model, id2, data, options2) => {
775
+ let stringSets;
776
+ let condition;
777
+ if (options2 && typeof options2 === "object") {
778
+ if (options2.condition !== void 0 || options2.stringSets !== void 0) {
779
+ stringSets = options2.stringSets;
780
+ condition = options2.condition;
781
+ } else {
782
+ stringSets = options2;
783
+ }
784
+ }
785
+ return engine.patchModel(resolveModelName(model), id2, data, stringSets, { condition });
786
+ },
787
+ delete: (model, deleteId, options2) => {
788
+ return engine.deleteModel(resolveModelName(model), deleteId, { condition: options2?.condition });
789
+ },
790
+ count: (model, filter = {}) => {
791
+ return engine.countModel(resolveModelName(model), filter);
792
+ },
793
+ aggregate: (model, options2) => {
794
+ return engine.aggregateModel(resolveModelName(model), options2);
795
+ },
796
+ increment: (model, id2, fields, options2) => {
797
+ return engine.incrementFields(resolveModelName(model), id2, fields, { condition: options2?.condition });
798
+ },
799
+ addToSet: (model, id2, sets, options2) => {
800
+ return engine.addToStringSet(resolveModelName(model), id2, sets, { condition: options2?.condition });
801
+ },
802
+ removeFromSet: (model, id2, sets, options2) => {
803
+ return engine.removeFromStringSet(resolveModelName(model), id2, sets, { condition: options2?.condition });
804
+ },
805
+ batch: (operations) => {
806
+ return engine.batchWrite(operations);
807
+ },
808
+ // Schema introspection
809
+ describe: (modelName) => {
810
+ return engine.describe(modelName);
811
+ },
812
+ // Index management
813
+ registerIndex: (modelName, fieldName, fieldType = "string", unique = false) => engine.registerIndex(modelName, fieldName, fieldType, unique),
814
+ dropIndex: (modelName, fieldName) => engine.dropIndex(modelName, fieldName),
815
+ listIndexes: (modelName) => engine.listIndexes(modelName),
816
+ registerUniqueConstraint: (modelName, constraintName, fields) => engine.registerUniqueConstraint(modelName, constraintName, fields),
817
+ dropUniqueConstraint: (modelName, constraintName) => engine.dropUniqueConstraint(modelName, constraintName),
818
+ listUniqueConstraints: (modelName) => engine.listUniqueConstraints(modelName),
819
+ syncIndexes,
820
+ syncAllIndexes: async () => {
821
+ if (!models || models.length === 0) return 0;
822
+ const request = {
823
+ models: models.map(extractModelSyncState)
824
+ };
825
+ return engine.syncIndexesBatch(request);
826
+ }
827
+ };
828
+ if (models) {
829
+ for (const model of models) {
830
+ const modelName = resolveModelName(model);
831
+ const className = model.name;
832
+ db[className] = createModelAccessor(engine, modelName);
833
+ }
834
+ }
835
+ Logger.info(`[connectDoDb] Connected to document: ${id} at ${endpoint}`);
836
+ return db;
837
+ }