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,709 @@
1
+ import {
2
+ BaseModel,
3
+ Logger
4
+ } from "./chunk-3PZWHUZO.js";
5
+
6
+ // src/models/relationshipManager.ts
7
+ function generateRefersToMethod(_sourceModelClass, config, targetModelClass) {
8
+ return async function() {
9
+ const relatedId = this[config.relatedIdField];
10
+ if (relatedId === null || typeof relatedId === "undefined") return null;
11
+ return targetModelClass.find(relatedId);
12
+ };
13
+ }
14
+ function generateHasManyMethod(_sourceModelClass, config, targetModelClass, _dbEngine) {
15
+ return async function(paginationArgs) {
16
+ const {
17
+ limit,
18
+ afterCursor,
19
+ beforeCursor,
20
+ direction = "forward"
21
+ } = paginationArgs || {};
22
+ const {
23
+ relatedIdField,
24
+ orderByField = "id",
25
+ orderDirection = "ASC"
26
+ } = config;
27
+ const targetSchema = targetModelClass.getSchema();
28
+ if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {
29
+ Logger.error(
30
+ `[RelationshipManager] Target model ${targetModelClass.name} for hasMany relationship has no valid schema name.`
31
+ );
32
+ return { data: [], nextCursor: null, prevCursor: null };
33
+ }
34
+ const filter = { [relatedIdField]: this.id };
35
+ const queryOptions = {
36
+ sort: { [orderByField]: orderDirection === "ASC" ? 1 : -1 }
37
+ };
38
+ if (limit !== void 0) {
39
+ queryOptions.limit = limit + 1;
40
+ }
41
+ if (direction === "forward" && afterCursor) {
42
+ filter[orderByField] = {
43
+ [orderDirection === "ASC" ? "$gt" : "$lt"]: afterCursor
44
+ };
45
+ } else if (direction === "backward") {
46
+ if (beforeCursor) {
47
+ filter[orderByField] = {
48
+ [orderDirection === "ASC" ? "$lt" : "$gt"]: beforeCursor
49
+ };
50
+ }
51
+ queryOptions.sort = { [orderByField]: orderDirection === "ASC" ? -1 : 1 };
52
+ }
53
+ const result = await targetModelClass.query(filter, queryOptions);
54
+ const results = result.data;
55
+ let nextCursor = null;
56
+ let prevCursor = null;
57
+ const isFirstPage = direction === "forward" && !afterCursor;
58
+ if (limit !== void 0) {
59
+ if (direction === "forward") {
60
+ if (results.length > limit) {
61
+ nextCursor = results[limit - 1][orderByField];
62
+ results.pop();
63
+ }
64
+ if (results.length > 0 && !isFirstPage) {
65
+ prevCursor = results[0][orderByField];
66
+ }
67
+ } else {
68
+ if (results.length > limit) {
69
+ prevCursor = results[limit - 1][orderByField];
70
+ results.pop();
71
+ }
72
+ results.reverse();
73
+ if (results.length > 0 && beforeCursor) {
74
+ nextCursor = results[results.length - 1][orderByField];
75
+ }
76
+ if (results.length > 0 && !beforeCursor) {
77
+ if (results.length === limit) {
78
+ prevCursor = results[0][orderByField];
79
+ }
80
+ }
81
+ }
82
+ }
83
+ return { data: results, nextCursor, prevCursor };
84
+ };
85
+ }
86
+ function generateHasManyThroughMethod(_sourceModelClass, config, targetModelClass, joinModelClass, _dbEngine) {
87
+ return async function(paginationArgs) {
88
+ const {
89
+ limit,
90
+ afterCursor,
91
+ beforeCursor,
92
+ direction = "forward"
93
+ } = paginationArgs || {};
94
+ const joinSchema = joinModelClass.getSchema();
95
+ const targetSchema = targetModelClass.getSchema();
96
+ if (!joinSchema || !joinSchema.options || !joinSchema.options.name) {
97
+ Logger.error(
98
+ `[RelationshipManager] Join model ${joinModelClass.name} for hasManyThrough relationship has no valid schema name.`
99
+ );
100
+ return { data: [], nextCursor: null, prevCursor: null };
101
+ }
102
+ if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {
103
+ Logger.error(
104
+ `[RelationshipManager] Target model ${targetModelClass.name} for hasManyThrough relationship has no valid schema name.`
105
+ );
106
+ return { data: [], nextCursor: null, prevCursor: null };
107
+ }
108
+ const {
109
+ joinModelLocalField,
110
+ joinModelRelatedField,
111
+ joinModelOrderByField = "id",
112
+ joinModelOrderDirection = "ASC"
113
+ } = config;
114
+ const joinFilter = { [joinModelLocalField]: this.id };
115
+ const joinQueryOptions = {
116
+ sort: {
117
+ [joinModelOrderByField]: joinModelOrderDirection === "ASC" ? 1 : -1
118
+ },
119
+ projection: { [joinModelRelatedField]: 1, [joinModelOrderByField]: 1 }
120
+ };
121
+ if (limit !== void 0) {
122
+ joinQueryOptions.limit = limit + 1;
123
+ }
124
+ if (direction === "forward" && afterCursor) {
125
+ joinFilter[joinModelOrderByField] = {
126
+ [joinModelOrderDirection === "ASC" ? "$gt" : "$lt"]: afterCursor
127
+ };
128
+ } else if (direction === "backward") {
129
+ if (beforeCursor) {
130
+ joinFilter[joinModelOrderByField] = {
131
+ [joinModelOrderDirection === "ASC" ? "$lt" : "$gt"]: beforeCursor
132
+ };
133
+ }
134
+ joinQueryOptions.sort = {
135
+ [joinModelOrderByField]: joinModelOrderDirection === "ASC" ? -1 : 1
136
+ };
137
+ }
138
+ const joinResult = await joinModelClass.query(
139
+ joinFilter,
140
+ joinQueryOptions
141
+ );
142
+ const joinResults = joinResult.data;
143
+ let nextCursorFromJoin = null;
144
+ let prevCursorFromJoin = null;
145
+ const isFirstPage = direction === "forward" && !afterCursor;
146
+ if (limit !== void 0) {
147
+ if (direction === "forward") {
148
+ if (joinResults.length > limit) {
149
+ nextCursorFromJoin = joinResults[limit - 1][joinModelOrderByField];
150
+ joinResults.pop();
151
+ }
152
+ if (joinResults.length > 0 && !isFirstPage) {
153
+ prevCursorFromJoin = joinResults[0][joinModelOrderByField];
154
+ }
155
+ } else {
156
+ if (joinResults.length > limit) {
157
+ prevCursorFromJoin = joinResults[limit - 1][joinModelOrderByField];
158
+ joinResults.pop();
159
+ }
160
+ joinResults.reverse();
161
+ if (joinResults.length > 0 && beforeCursor) {
162
+ nextCursorFromJoin = joinResults[joinResults.length - 1][joinModelOrderByField];
163
+ }
164
+ if (joinResults.length > 0 && !beforeCursor) {
165
+ if (joinResults.length === limit) {
166
+ prevCursorFromJoin = joinResults[0][joinModelOrderByField];
167
+ }
168
+ }
169
+ }
170
+ }
171
+ const relatedIds = joinResults.map((r) => r[joinModelRelatedField]).filter((id) => id != null && typeof id === "string");
172
+ if (relatedIds.length === 0)
173
+ return { data: [], nextCursor: null, prevCursor: null };
174
+ const targetResult = await targetModelClass.query({
175
+ id: { $in: relatedIds }
176
+ });
177
+ return {
178
+ data: targetResult.data,
179
+ nextCursor: nextCursorFromJoin,
180
+ prevCursor: prevCursorFromJoin
181
+ };
182
+ };
183
+ }
184
+ function generateHasManyThroughAddMethod(_sourceModelClass, config, _targetModelClass, joinModelClass) {
185
+ return async function(targetInstanceOrId) {
186
+ const targetId = typeof targetInstanceOrId === "string" ? targetInstanceOrId : targetInstanceOrId.id;
187
+ if (!targetId) {
188
+ Logger.error("[RelationshipManager.add] Target ID is missing.");
189
+ throw new Error("Target ID is missing for add operation.");
190
+ }
191
+ const joinData = {};
192
+ joinData[config.joinModelLocalField] = this.id;
193
+ joinData[config.joinModelRelatedField] = targetId;
194
+ let yDoc = null;
195
+ let targetDocId = null;
196
+ const sourceModelConstructor = this.constructor;
197
+ const connectedDocuments = sourceModelConstructor.connectedDocuments;
198
+ if (this._metaDocId && connectedDocuments) {
199
+ targetDocId = this._metaDocId;
200
+ if (targetDocId) {
201
+ const documentInfo = connectedDocuments.get(targetDocId);
202
+ if (documentInfo) {
203
+ yDoc = documentInfo.yDoc;
204
+ }
205
+ }
206
+ }
207
+ if (!yDoc) {
208
+ const legacyDocId = "__legacy_default__";
209
+ const legacyDocInfo = joinModelClass.connectedDocuments?.get(
210
+ legacyDocId
211
+ );
212
+ if (legacyDocInfo) {
213
+ yDoc = legacyDocInfo.yDoc;
214
+ }
215
+ }
216
+ if (!yDoc) {
217
+ throw new Error(
218
+ `[${joinModelClass.name}] No Y.Doc is connected for this join model. Connect a document via initJsBao(...).connectDocument or call initializeForDocument(yDoc, db, docId, permissionHint) before managing relationships.`
219
+ );
220
+ }
221
+ await yDoc.transact(async () => {
222
+ const newJoinInstance = new joinModelClass(joinData);
223
+ if (targetDocId) {
224
+ await newJoinInstance.save({ targetDocument: targetDocId });
225
+ } else {
226
+ await newJoinInstance.save();
227
+ }
228
+ Logger.debug(
229
+ `[RelationshipManager.add] Created join entry in ${config.joinModel}:`,
230
+ newJoinInstance.toJSON()
231
+ );
232
+ }, `add-join-${config.joinModel}-${this.id}-${targetId}`);
233
+ };
234
+ }
235
+ function generateHasManyThroughRemoveMethod(_sourceModelClass, config, _targetModelClass, joinModelClass) {
236
+ return async function(targetInstanceOrId) {
237
+ const targetId = typeof targetInstanceOrId === "string" ? targetInstanceOrId : targetInstanceOrId.id;
238
+ if (!targetId) {
239
+ Logger.error("[RelationshipManager.remove] Target ID is missing.");
240
+ throw new Error("Target ID is missing for remove operation.");
241
+ }
242
+ let yDoc = null;
243
+ let targetDocId = null;
244
+ const sourceModelConstructor = this.constructor;
245
+ const connectedDocuments = sourceModelConstructor.connectedDocuments;
246
+ if (this._metaDocId && connectedDocuments) {
247
+ targetDocId = this._metaDocId;
248
+ if (targetDocId) {
249
+ const documentInfo = connectedDocuments.get(targetDocId);
250
+ if (documentInfo) {
251
+ yDoc = documentInfo.yDoc;
252
+ }
253
+ }
254
+ }
255
+ if (!yDoc) {
256
+ const legacyDocId = "__legacy_default__";
257
+ const legacyDocInfo = joinModelClass.connectedDocuments?.get(
258
+ legacyDocId
259
+ );
260
+ if (legacyDocInfo) {
261
+ yDoc = legacyDocInfo.yDoc;
262
+ }
263
+ }
264
+ if (!yDoc) {
265
+ throw new Error(
266
+ `[${joinModelClass.name}] No Y.Doc is connected for this join model. Connect a document via initJsBao(...).connectDocument or call initializeForDocument(yDoc, db, docId, permissionHint) before managing relationships.`
267
+ );
268
+ }
269
+ await yDoc.transact(async () => {
270
+ const joinRecordsResult = await joinModelClass.query(
271
+ {
272
+ [config.joinModelLocalField]: this.id,
273
+ [config.joinModelRelatedField]: targetId
274
+ },
275
+ {
276
+ limit: 1,
277
+ projection: { id: 1 }
278
+ }
279
+ );
280
+ if (joinRecordsResult.data.length > 0) {
281
+ for (const record of joinRecordsResult.data) {
282
+ const instanceToDelete = await joinModelClass.find(
283
+ record.id
284
+ );
285
+ if (instanceToDelete) {
286
+ await instanceToDelete.delete();
287
+ Logger.debug(
288
+ `[RelationshipManager.remove] Deleted join entry from ${config.joinModel} with ID: ${record.id}`
289
+ );
290
+ } else {
291
+ Logger.warn(
292
+ `[RelationshipManager.remove] Join entry with ID ${record.id} found by query but not in YMap for deletion.`
293
+ );
294
+ }
295
+ }
296
+ } else {
297
+ Logger.debug(
298
+ `[RelationshipManager.remove] No join entry found in ${config.joinModel} for localId: ${this.id}, relatedId: ${targetId}. No action taken.`
299
+ );
300
+ }
301
+ }, `remove-join-${config.joinModel}-${this.id}-${targetId}`);
302
+ };
303
+ }
304
+
305
+ // src/models/ModelRegistry.ts
306
+ var ModelRegistry = class _ModelRegistry {
307
+ static instance;
308
+ // Stores globally registered model classes by their name (from @Model decorator)
309
+ models = /* @__PURE__ */ new Map();
310
+ // Stores options for globally registered models (from @Model decorator)
311
+ modelOptions = /* @__PURE__ */ new Map();
312
+ // Stores fields for globally registered models (from @Model decorator, or a static getter on class)
313
+ // For simplicity, let's assume fields can be derived or are less critical for this registry part
314
+ // private modelFields: Map<string, Map<string, FieldOptions>> = new Map();
315
+ // Holds the subset of models explicitly set for the current initialization session
316
+ activeSessionModels = null;
317
+ dbEngine = null;
318
+ // Store dbEngine for relationship methods
319
+ constructor() {
320
+ }
321
+ static getInstance() {
322
+ if (!_ModelRegistry.instance) {
323
+ _ModelRegistry.instance = new _ModelRegistry();
324
+ }
325
+ return _ModelRegistry.instance;
326
+ }
327
+ registerModel(modelClass, options, fields) {
328
+ if (!options.name) {
329
+ throw new Error(
330
+ `[ModelRegistry] Model class is missing a name in its @Model options. Ensure the @Model decorator includes a 'name' property.`
331
+ );
332
+ }
333
+ if (this.models.has(options.name)) {
334
+ console.warn(
335
+ `[ModelRegistry] Model "${options.name}" is already registered. Overwriting.`
336
+ );
337
+ }
338
+ this.models.set(options.name, modelClass);
339
+ if (fields) {
340
+ BaseModel.attachFieldAccessors(modelClass, fields);
341
+ }
342
+ this.modelOptions.set(options.name, options);
343
+ console.log(
344
+ `[ModelRegistry] Model "${options.name}" registered successfully.`
345
+ );
346
+ }
347
+ // Gets the class for a globally registered model
348
+ getModelClass(name) {
349
+ return this.models.get(name);
350
+ }
351
+ getModelOptions(name) {
352
+ return this.modelOptions.get(name);
353
+ }
354
+ // This method might need to be adapted based on how fields are ultimately managed
355
+ getModelInfo(modelName) {
356
+ const modelClass = this.models.get(modelName);
357
+ const options = this.modelOptions.get(modelName);
358
+ if (modelClass && options) {
359
+ const fields = modelClass.getSchema ? modelClass.getSchema().fields : /* @__PURE__ */ new Map();
360
+ return { class: modelClass, options, fields };
361
+ }
362
+ return void 0;
363
+ }
364
+ getAllRegisteredModelsInfo() {
365
+ const infos = [];
366
+ for (const modelName of this.models.keys()) {
367
+ const info = this.getModelInfo(modelName);
368
+ if (info) {
369
+ infos.push(info);
370
+ }
371
+ }
372
+ return infos;
373
+ }
374
+ // Helper to get model name from class (assuming static property from @Model decorator)
375
+ getModelNameFromClass(modelClass) {
376
+ return modelClass.modelName;
377
+ }
378
+ setExplicitModelsForSession(modelClasses) {
379
+ if (modelClasses && modelClasses.length > 0) {
380
+ this.activeSessionModels = /* @__PURE__ */ new Map();
381
+ modelClasses.forEach((modelClass) => {
382
+ const modelName = this.getModelNameFromClass(modelClass);
383
+ if (!modelName) {
384
+ console.warn(
385
+ `[ModelRegistry] A model class provided to setExplicitModelsForSession does not have a static 'modelName' property or it's undefined. It will be ignored. Ensure @Model decorator sets this.`
386
+ );
387
+ return;
388
+ }
389
+ if (!this.models.has(modelName) || this.models.get(modelName) !== modelClass) {
390
+ console.warn(
391
+ `[ModelRegistry] Model class with name ${modelName} provided to setExplicitModelsForSession was not found in the global decorator-based registry or does not match. It will be ignored. Ensure the model file is imported and the @Model decorator has run correctly.`
392
+ );
393
+ return;
394
+ }
395
+ if (this.activeSessionModels) {
396
+ this.activeSessionModels.set(modelName, modelClass);
397
+ }
398
+ });
399
+ let sessionModelNamesMessage = "none (no models were successfully added or session map is null)";
400
+ if (this.activeSessionModels) {
401
+ const currentSessionModelKeys = Array.from(
402
+ this.activeSessionModels.keys()
403
+ );
404
+ if (currentSessionModelKeys.length > 0) {
405
+ sessionModelNamesMessage = currentSessionModelKeys.join(", ");
406
+ } else {
407
+ sessionModelNamesMessage = "none (session map initialized but no models added)";
408
+ }
409
+ }
410
+ Logger.debug(
411
+ `[ModelRegistry] Explicit models set for session: ${sessionModelNamesMessage}`
412
+ );
413
+ } else if (modelClasses && modelClasses.length === 0) {
414
+ this.activeSessionModels = /* @__PURE__ */ new Map();
415
+ Logger.debug(
416
+ "[ModelRegistry] Explicitly no models for session (empty array passed)."
417
+ );
418
+ } else {
419
+ this.activeSessionModels = null;
420
+ console.log(
421
+ "[ModelRegistry] No explicit models specified for session (undefined), will use all decorator-registered models."
422
+ );
423
+ }
424
+ this.validateSessionModels();
425
+ }
426
+ async initializeAll(yDoc, dbEngine) {
427
+ Logger.debug("[ModelRegistry] Attempting to initialize models...");
428
+ this.dbEngine = dbEngine;
429
+ const modelsToInitialize = this.activeSessionModels || this.models;
430
+ if (modelsToInitialize.size === 0) {
431
+ console.warn(
432
+ "[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via @Model decorator)."
433
+ );
434
+ return;
435
+ }
436
+ console.log(
437
+ `[ModelRegistry] Initializing models: ${Array.from(
438
+ modelsToInitialize.keys()
439
+ ).join(", ")}`
440
+ );
441
+ for (const [modelName, modelClass] of modelsToInitialize.entries()) {
442
+ if (modelClass && typeof modelClass.initialize === "function") {
443
+ Logger.debug(`[ModelRegistry] Initializing model: ${modelName}`);
444
+ await modelClass.initialize(yDoc, dbEngine);
445
+ } else {
446
+ const staticModelName = modelClass?.modelName || "unknown";
447
+ console.warn(
448
+ `[ModelRegistry] Model ${staticModelName} (class name: ${modelClass?.name}) does not have a static initialize method or class is not defined.`
449
+ );
450
+ }
451
+ }
452
+ Logger.debug("[ModelRegistry] Model initialization phase complete.");
453
+ }
454
+ // New method to initialize models for a specific document
455
+ async initializeAllForDocument(yDoc, dbEngine, docId, permissionHint) {
456
+ Logger.debug(
457
+ `[ModelRegistry] Initializing models for document ${docId}...`
458
+ );
459
+ this.dbEngine = dbEngine;
460
+ const modelsToInitialize = this.activeSessionModels || this.models;
461
+ if (modelsToInitialize.size === 0) {
462
+ Logger.warn(
463
+ "[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via @Model decorator)."
464
+ );
465
+ return;
466
+ }
467
+ Logger.debug(
468
+ `[ModelRegistry] Initializing models for document ${docId}: ${Array.from(
469
+ modelsToInitialize.keys()
470
+ ).join(", ")}`
471
+ );
472
+ for (const [modelName, modelClass] of modelsToInitialize.entries()) {
473
+ if (modelClass && typeof modelClass.initializeForDocument === "function") {
474
+ Logger.debug(
475
+ `[ModelRegistry] Initializing model ${modelName} for document ${docId}`
476
+ );
477
+ await modelClass.initializeForDocument(
478
+ yDoc,
479
+ dbEngine,
480
+ docId,
481
+ permissionHint
482
+ );
483
+ } else {
484
+ const staticModelName = modelClass?.modelName || "unknown";
485
+ console.warn(
486
+ `[ModelRegistry] Model ${staticModelName} (class name: ${modelClass?.name}) does not have a static initializeForDocument method or class is not defined.`
487
+ );
488
+ }
489
+ }
490
+ await this.initializeRelationships();
491
+ Logger.debug(
492
+ `[ModelRegistry] Model initialization complete for document ${docId}`
493
+ );
494
+ }
495
+ // New method to remove data from a disconnected document
496
+ async removeDocumentData(docId, dbEngine) {
497
+ Logger.debug(`[ModelRegistry] Removing data for document ${docId}...`);
498
+ const modelsToCleanup = this.activeSessionModels || this.models;
499
+ if (modelsToCleanup.size === 0) {
500
+ console.warn(
501
+ "[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via @Model decorator)."
502
+ );
503
+ return;
504
+ }
505
+ for (const [modelName, modelClass] of modelsToCleanup.entries()) {
506
+ try {
507
+ Logger.debug(
508
+ `[ModelRegistry] Removing ${modelName} data for document ${docId}`
509
+ );
510
+ await dbEngine.deleteByDocumentId(modelName, docId);
511
+ if (modelClass && typeof modelClass.cleanupDocumentData === "function") {
512
+ await modelClass.cleanupDocumentData(docId);
513
+ }
514
+ } catch (error) {
515
+ console.error(
516
+ `[ModelRegistry] Error removing ${modelName} data for document ${docId}:`,
517
+ error
518
+ );
519
+ }
520
+ }
521
+ Logger.debug(`[ModelRegistry] Data removal complete for document ${docId}`);
522
+ }
523
+ // New method to initialize relationships
524
+ async initializeRelationships() {
525
+ if (!this.dbEngine) {
526
+ console.error(
527
+ "[ModelRegistry] DB engine not available for initializing relationships. Ensure initializeAll has been called."
528
+ );
529
+ return;
530
+ }
531
+ const dbEngine = this.dbEngine;
532
+ Logger.debug(
533
+ "[ModelRegistry] Initializing relationships for active models..."
534
+ );
535
+ const activeModels = this.getActiveModels();
536
+ for (const [modelName, modelClass] of activeModels.entries()) {
537
+ const modelSchema = modelClass.getSchema ? modelClass.getSchema() : null;
538
+ const relationshipsConfig = modelSchema?.options?.relationships;
539
+ if (relationshipsConfig) {
540
+ Logger.debug(
541
+ `[ModelRegistry] Setting up relationships for ${modelName}`
542
+ );
543
+ for (const relName in relationshipsConfig) {
544
+ const config = relationshipsConfig[relName];
545
+ if (!config.model) {
546
+ throw new Error(
547
+ `[ModelRegistry] Relationship "${relName}" on model "${modelName}" is missing a target model name.`
548
+ );
549
+ }
550
+ const targetModelClass = this.getModelClass(config.model);
551
+ if (!targetModelClass) {
552
+ throw new Error(
553
+ `[ModelRegistry] Relationship "${relName}" on model "${modelName}" refers to an unknown model "${config.model}". Ensure "${config.model}" is registered and included in the session.`
554
+ );
555
+ }
556
+ if (typeof targetModelClass.getSchema !== "function") {
557
+ throw new Error(
558
+ `[ModelRegistry] Target model "${config.model}" for relationship "${relName}" on "${modelName}" does not have a getSchema method.`
559
+ );
560
+ }
561
+ switch (config.type) {
562
+ case "refersTo":
563
+ Logger.debug(
564
+ ` - Adding '${relName}' (refersTo ${config.model}) to ${modelName}`
565
+ );
566
+ const refersToMethod = generateRefersToMethod(
567
+ modelClass,
568
+ config,
569
+ targetModelClass
570
+ );
571
+ this.addPrototypeMethod(modelClass, relName, refersToMethod);
572
+ break;
573
+ case "hasMany":
574
+ Logger.debug(
575
+ ` - Adding '${relName}' (hasMany ${config.model}) to ${modelName}`
576
+ );
577
+ const hasManyMethod = generateHasManyMethod(
578
+ modelClass,
579
+ config,
580
+ targetModelClass,
581
+ dbEngine
582
+ );
583
+ this.addPrototypeMethod(modelClass, relName, hasManyMethod);
584
+ break;
585
+ case "hasManyThrough":
586
+ const joinModelName = config.joinModel;
587
+ const joinModelClass = this.getModelClass(joinModelName);
588
+ if (!joinModelClass) {
589
+ throw new Error(
590
+ `[ModelRegistry] Join model "${joinModelName}" for relationship "${relName}" on model "${modelName}" not found. Ensure it is registered and included in the session.`
591
+ );
592
+ }
593
+ if (typeof joinModelClass.getSchema !== "function") {
594
+ throw new Error(
595
+ `[ModelRegistry] Join model "${joinModelName}" for relationship "${relName}" on "${modelName}" does not have a getSchema method.`
596
+ );
597
+ }
598
+ Logger.debug(
599
+ ` - Adding '${relName}' (hasManyThrough ${config.model} via ${joinModelName}) to ${modelName}`
600
+ );
601
+ const hasManyThroughFetchMethod = generateHasManyThroughMethod(
602
+ modelClass,
603
+ config,
604
+ targetModelClass,
605
+ joinModelClass,
606
+ dbEngine
607
+ );
608
+ this.addPrototypeMethod(
609
+ modelClass,
610
+ relName,
611
+ hasManyThroughFetchMethod
612
+ );
613
+ const relNameSingular = config.model.endsWith("s") ? config.model.slice(0, -1) : config.model;
614
+ const capitalizedSingularRelName = relNameSingular.charAt(0).toUpperCase() + relNameSingular.slice(1);
615
+ const addMethodName = `add${capitalizedSingularRelName}`;
616
+ const addMethodLogic = generateHasManyThroughAddMethod(
617
+ modelClass,
618
+ config,
619
+ targetModelClass,
620
+ joinModelClass
621
+ );
622
+ this.addPrototypeMethod(
623
+ modelClass,
624
+ addMethodName,
625
+ addMethodLogic
626
+ );
627
+ Logger.debug(
628
+ ` - Adding '${addMethodName}' helper to ${modelName} (for relationship ${relName})`
629
+ );
630
+ const removeMethodName = `remove${capitalizedSingularRelName}`;
631
+ const removeMethodLogic = generateHasManyThroughRemoveMethod(
632
+ modelClass,
633
+ config,
634
+ targetModelClass,
635
+ joinModelClass
636
+ );
637
+ this.addPrototypeMethod(
638
+ modelClass,
639
+ removeMethodName,
640
+ removeMethodLogic
641
+ );
642
+ Logger.debug(
643
+ ` - Adding '${removeMethodName}' helper to ${modelName} (for relationship ${relName})`
644
+ );
645
+ break;
646
+ default:
647
+ console.warn(
648
+ `[ModelRegistry] Unknown relationship type "${config.type}" for ${relName} on ${modelName}. Skipping.`
649
+ );
650
+ }
651
+ }
652
+ }
653
+ }
654
+ Logger.debug("[ModelRegistry] Relationship initialization phase complete.");
655
+ }
656
+ // Helper to add methods to prototype
657
+ addPrototypeMethod(modelClass, methodName, methodLogic) {
658
+ Object.defineProperty(modelClass.prototype, methodName, {
659
+ value: methodLogic,
660
+ writable: true,
661
+ enumerable: false,
662
+ // Keep it clean, like other prototype methods
663
+ configurable: true
664
+ });
665
+ }
666
+ clearSessionState() {
667
+ this.activeSessionModels = null;
668
+ Logger.debug(
669
+ "[ModelRegistry] Session state cleared (activeSessionModels reset)."
670
+ );
671
+ }
672
+ getActiveModels() {
673
+ return this.activeSessionModels || this.models;
674
+ }
675
+ validateSessionModels() {
676
+ const activeModels = this.getActiveModels();
677
+ if (!activeModels || activeModels.size === 0) {
678
+ return;
679
+ }
680
+ for (const [modelName, modelClass] of activeModels.entries()) {
681
+ const modelSchema = modelClass.getSchema ? modelClass.getSchema() : null;
682
+ const relationships = modelSchema?.options?.relationships;
683
+ if (relationships) {
684
+ for (const relName in relationships) {
685
+ const config = relationships[relName];
686
+ const targetModelName = config.model;
687
+ if (!activeModels.has(targetModelName)) {
688
+ throw new Error(
689
+ `[ModelRegistry] Validation Error: Model "${modelName}" has a relationship "${relName}" that refers to model "${targetModelName}", but "${targetModelName}" is not active in the current session. Please include it in the 'models' array during initialization.`
690
+ );
691
+ }
692
+ if (config.type === "hasManyThrough") {
693
+ const joinModelName = config.joinModel;
694
+ if (!activeModels.has(joinModelName)) {
695
+ throw new Error(
696
+ `[ModelRegistry] Validation Error: Model "${modelName}" has a relationship "${relName}" that uses join model "${joinModelName}", but "${joinModelName}" is not active in the current session. Please include it in the 'models' array during initialization.`
697
+ );
698
+ }
699
+ }
700
+ }
701
+ }
702
+ }
703
+ }
704
+ };
705
+
706
+ export {
707
+ ModelRegistry
708
+ };
709
+ //# sourceMappingURL=chunk-65G2P4GL.js.map