@palantir/pack.state.core 0.0.1-beta.1
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.
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-transpileBrowser.log +5 -0
- package/.turbo/turbo-transpileCjs.log +5 -0
- package/.turbo/turbo-transpileEsm.log +5 -0
- package/.turbo/turbo-transpileTypes.log +5 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/LICENSE.txt +13 -0
- package/README.md +55 -0
- package/build/browser/index.js +1257 -0
- package/build/browser/index.js.map +1 -0
- package/build/cjs/index.cjs +1298 -0
- package/build/cjs/index.cjs.map +1 -0
- package/build/cjs/index.d.cts +272 -0
- package/build/esm/index.js +1257 -0
- package/build/esm/index.js.map +1 -0
- package/build/types/DocumentServiceModule.d.ts +6 -0
- package/build/types/DocumentServiceModule.d.ts.map +1 -0
- package/build/types/__tests__/DocumentStatusTracking.test.d.ts +1 -0
- package/build/types/__tests__/DocumentStatusTracking.test.d.ts.map +1 -0
- package/build/types/__tests__/RefStability.test.d.ts +1 -0
- package/build/types/__tests__/RefStability.test.d.ts.map +1 -0
- package/build/types/__tests__/StateModule.integration.test.d.ts +1 -0
- package/build/types/__tests__/StateModule.integration.test.d.ts.map +1 -0
- package/build/types/__tests__/testUtils.d.ts +7 -0
- package/build/types/__tests__/testUtils.d.ts.map +1 -0
- package/build/types/index.d.ts +11 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/service/BaseYjsDocumentService.d.ts +155 -0
- package/build/types/service/BaseYjsDocumentService.d.ts.map +1 -0
- package/build/types/service/InMemoryDocumentService.d.ts +12 -0
- package/build/types/service/InMemoryDocumentService.d.ts.map +1 -0
- package/build/types/service/YjsSchemaMapper.d.ts +9 -0
- package/build/types/service/YjsSchemaMapper.d.ts.map +1 -0
- package/build/types/types/DocumentRefImpl.d.ts +5 -0
- package/build/types/types/DocumentRefImpl.d.ts.map +1 -0
- package/build/types/types/DocumentService.d.ts +62 -0
- package/build/types/types/DocumentService.d.ts.map +1 -0
- package/build/types/types/DocumentServiceConfig.d.ts +5 -0
- package/build/types/types/DocumentServiceConfig.d.ts.map +1 -0
- package/build/types/types/RecordCollectionRefImpl.d.ts +5 -0
- package/build/types/types/RecordCollectionRefImpl.d.ts.map +1 -0
- package/build/types/types/RecordRefImpl.d.ts +5 -0
- package/build/types/types/RecordRefImpl.d.ts.map +1 -0
- package/build/types/types/StateModule.d.ts +59 -0
- package/build/types/types/StateModule.d.ts.map +1 -0
- package/package.json +71 -0
- package/src/DocumentServiceModule.ts +53 -0
- package/src/__tests__/DocumentStatusTracking.test.ts +229 -0
- package/src/__tests__/RefStability.test.ts +441 -0
- package/src/__tests__/StateModule.integration.test.ts +1187 -0
- package/src/__tests__/testUtils.ts +106 -0
- package/src/index.ts +38 -0
- package/src/service/BaseYjsDocumentService.ts +1277 -0
- package/src/service/InMemoryDocumentService.ts +162 -0
- package/src/service/YjsSchemaMapper.ts +194 -0
- package/src/types/DocumentRefImpl.ts +98 -0
- package/src/types/DocumentService.ts +210 -0
- package/src/types/DocumentServiceConfig.ts +22 -0
- package/src/types/RecordCollectionRefImpl.ts +124 -0
- package/src/types/RecordRefImpl.ts +106 -0
- package/src/types/StateModule.ts +329 -0
- package/tsconfig.json +21 -0
- package/vitest.config.mjs +26 -0
|
@@ -0,0 +1,1298 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pack_documentSchema_modelTypes = require('@palantir/pack.document-schema.model-types');
|
|
4
|
+
var remeda = require('remeda');
|
|
5
|
+
var invariant = require('tiny-invariant');
|
|
6
|
+
var Y = require('yjs');
|
|
7
|
+
var pack_core = require('@palantir/pack.core');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function (k) {
|
|
16
|
+
if (k !== 'default') {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return e[k]; }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var invariant__default = /*#__PURE__*/_interopDefault(invariant);
|
|
30
|
+
var Y__namespace = /*#__PURE__*/_interopNamespace(Y);
|
|
31
|
+
|
|
32
|
+
// src/DocumentServiceModule.ts
|
|
33
|
+
var DOCUMENT_SERVICE_MODULE_KEY = {
|
|
34
|
+
key: Symbol("DocumentService"),
|
|
35
|
+
initModule: initDocumentService
|
|
36
|
+
};
|
|
37
|
+
function getDocumentService(app) {
|
|
38
|
+
return app.getModule(DOCUMENT_SERVICE_MODULE_KEY);
|
|
39
|
+
}
|
|
40
|
+
function createDocumentServiceConfig(init, config) {
|
|
41
|
+
return [DOCUMENT_SERVICE_MODULE_KEY, {
|
|
42
|
+
...config,
|
|
43
|
+
init
|
|
44
|
+
}];
|
|
45
|
+
}
|
|
46
|
+
function initDocumentService(app, config) {
|
|
47
|
+
if (config == null) {
|
|
48
|
+
throw new Error("DocumentServiceConfig is required to initialize DocumentService");
|
|
49
|
+
}
|
|
50
|
+
return config.init(app, config);
|
|
51
|
+
}
|
|
52
|
+
var STATE_MODULE_ACCESSOR = "state";
|
|
53
|
+
var STATE_MODULE_KEY = {
|
|
54
|
+
appMemberName: STATE_MODULE_ACCESSOR,
|
|
55
|
+
key: Symbol.for("pack.state"),
|
|
56
|
+
initModule: (app) => {
|
|
57
|
+
const documentService = app.getModule(DOCUMENT_SERVICE_MODULE_KEY);
|
|
58
|
+
return new StateModuleImpl(documentService);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var StateModuleImpl = class {
|
|
62
|
+
constructor(documentService) {
|
|
63
|
+
this.documentService = documentService;
|
|
64
|
+
}
|
|
65
|
+
createDocRef(id, schema) {
|
|
66
|
+
return this.documentService.createDocRef(id, schema);
|
|
67
|
+
}
|
|
68
|
+
createRecordRef(docRef, id, model) {
|
|
69
|
+
return this.documentService.getCreateRecordRef(docRef, id, model);
|
|
70
|
+
}
|
|
71
|
+
async createDocument(metadata, schema) {
|
|
72
|
+
return this.documentService.createDocument(metadata, schema);
|
|
73
|
+
}
|
|
74
|
+
async getDocumentSnapshot(docRef) {
|
|
75
|
+
return this.documentService.getDocumentSnapshot(docRef);
|
|
76
|
+
}
|
|
77
|
+
onMetadataChange(docRef, cb) {
|
|
78
|
+
return this.documentService.onMetadataChange(docRef, cb);
|
|
79
|
+
}
|
|
80
|
+
onStateChange(docRef, cb) {
|
|
81
|
+
return this.documentService.onStateChange(docRef, cb);
|
|
82
|
+
}
|
|
83
|
+
async getRecordSnapshot(recordRef) {
|
|
84
|
+
return this.documentService.getRecordSnapshot(recordRef);
|
|
85
|
+
}
|
|
86
|
+
async setRecord(recordRef, state) {
|
|
87
|
+
return this.documentService.setRecord(recordRef, state);
|
|
88
|
+
}
|
|
89
|
+
async updateRecord(recordRef, partialState) {
|
|
90
|
+
return this.documentService.updateRecord(recordRef, partialState);
|
|
91
|
+
}
|
|
92
|
+
// Collection methods
|
|
93
|
+
getCreateRecordCollectionRef(docRef, model) {
|
|
94
|
+
return this.documentService.getCreateRecordCollectionRef(docRef, model);
|
|
95
|
+
}
|
|
96
|
+
// FIXME: confusing vs createRecordRef
|
|
97
|
+
getRecord(collection, id) {
|
|
98
|
+
return this.documentService.getRecord(collection, id);
|
|
99
|
+
}
|
|
100
|
+
hasRecord(collection, id) {
|
|
101
|
+
return this.documentService.hasRecord(collection, id);
|
|
102
|
+
}
|
|
103
|
+
async setCollectionRecord(collection, id, state) {
|
|
104
|
+
return this.documentService.setCollectionRecord(collection, id, state);
|
|
105
|
+
}
|
|
106
|
+
getCollectionSize(collection) {
|
|
107
|
+
return this.documentService.getCollectionSize(collection);
|
|
108
|
+
}
|
|
109
|
+
getCollectionRecords(collection) {
|
|
110
|
+
return this.documentService.getCollectionRecords(collection);
|
|
111
|
+
}
|
|
112
|
+
onRecordChanged(record, callback) {
|
|
113
|
+
return this.documentService.onRecordChanged(record, callback);
|
|
114
|
+
}
|
|
115
|
+
onRecordDeleted(record, callback) {
|
|
116
|
+
return this.documentService.onRecordDeleted(record, callback);
|
|
117
|
+
}
|
|
118
|
+
onCollectionItemsAdded(collection, callback) {
|
|
119
|
+
return this.documentService.onCollectionItemsAdded(collection, callback);
|
|
120
|
+
}
|
|
121
|
+
onCollectionItemsChanged(collection, callback) {
|
|
122
|
+
return this.documentService.onCollectionItemsChanged(collection, callback);
|
|
123
|
+
}
|
|
124
|
+
onCollectionItemsDeleted(collection, callback) {
|
|
125
|
+
return this.documentService.onCollectionItemsDeleted(collection, callback);
|
|
126
|
+
}
|
|
127
|
+
// Status methods implementation
|
|
128
|
+
getDocumentStatus(docRef) {
|
|
129
|
+
return this.documentService.getDocumentStatus(docRef);
|
|
130
|
+
}
|
|
131
|
+
onStatusChange(docRef, callback) {
|
|
132
|
+
return this.documentService.onStatusChange(docRef, callback);
|
|
133
|
+
}
|
|
134
|
+
async waitForMetadataLoad(docRef) {
|
|
135
|
+
return this.documentService.waitForMetadataLoad(docRef);
|
|
136
|
+
}
|
|
137
|
+
async waitForDataLoad(docRef) {
|
|
138
|
+
return this.documentService.waitForDataLoad(docRef);
|
|
139
|
+
}
|
|
140
|
+
async deleteRecord(record) {
|
|
141
|
+
return this.documentService.deleteRecord(record);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
function getStateModule(app) {
|
|
145
|
+
pack_core.assertIsAppInternal(app);
|
|
146
|
+
return app.getModule(STATE_MODULE_KEY);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/types/DocumentRefImpl.ts
|
|
150
|
+
var INVALID_DOC_REF_ID = "INVALID_DOC_REF";
|
|
151
|
+
var INVALID_DOC_REF = Object.freeze({
|
|
152
|
+
id: INVALID_DOC_REF_ID,
|
|
153
|
+
schema: {},
|
|
154
|
+
[pack_documentSchema_modelTypes.DocumentRefBrand]: pack_documentSchema_modelTypes.DocumentRefBrand,
|
|
155
|
+
getDocSnapshot: () => Promise.reject(new Error("Invalid document reference")),
|
|
156
|
+
getRecords: () => {
|
|
157
|
+
throw new Error("Invalid document reference");
|
|
158
|
+
},
|
|
159
|
+
onMetadataChange: () => () => {
|
|
160
|
+
},
|
|
161
|
+
onStateChange: () => () => {
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
var createDocRef = (app, id, schema) => {
|
|
165
|
+
return new DocumentRefImpl(app, id, schema);
|
|
166
|
+
};
|
|
167
|
+
function invalidDocRef() {
|
|
168
|
+
return INVALID_DOC_REF;
|
|
169
|
+
}
|
|
170
|
+
function isValidDocRef(docRef) {
|
|
171
|
+
return docRef.id !== INVALID_DOC_REF_ID && docRef.id !== "";
|
|
172
|
+
}
|
|
173
|
+
var DocumentRefImpl = class {
|
|
174
|
+
id;
|
|
175
|
+
schema;
|
|
176
|
+
#stateModule;
|
|
177
|
+
constructor(app, id, schema) {
|
|
178
|
+
this.#stateModule = getStateModule(app);
|
|
179
|
+
this.id = id;
|
|
180
|
+
this.schema = schema;
|
|
181
|
+
}
|
|
182
|
+
async getDocSnapshot() {
|
|
183
|
+
return this.#stateModule.getDocumentSnapshot(this);
|
|
184
|
+
}
|
|
185
|
+
getRecords(model) {
|
|
186
|
+
return this.#stateModule.getCreateRecordCollectionRef(this, model);
|
|
187
|
+
}
|
|
188
|
+
onMetadataChange(cb) {
|
|
189
|
+
return this.#stateModule.onMetadataChange(this, cb);
|
|
190
|
+
}
|
|
191
|
+
onStateChange(callback) {
|
|
192
|
+
return this.#stateModule.onStateChange(this, callback);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// src/types/DocumentService.ts
|
|
197
|
+
var DocumentLoadStatus = {
|
|
198
|
+
UNLOADED: "unloaded",
|
|
199
|
+
// Not yet loaded
|
|
200
|
+
LOADING: "loading",
|
|
201
|
+
// Initial load in progress
|
|
202
|
+
LOADED: "loaded",
|
|
203
|
+
// Successfully loaded
|
|
204
|
+
ERROR: "error"
|
|
205
|
+
// Load failed
|
|
206
|
+
};
|
|
207
|
+
var DocumentLiveStatus = {
|
|
208
|
+
DISCONNECTED: "disconnected",
|
|
209
|
+
// Not syncing
|
|
210
|
+
CONNECTING: "connecting",
|
|
211
|
+
// Establishing connection
|
|
212
|
+
CONNECTED: "connected",
|
|
213
|
+
// Live syncing active
|
|
214
|
+
ERROR: "error"
|
|
215
|
+
// Connection error
|
|
216
|
+
};
|
|
217
|
+
var INVALID_RECORD_COLLECTION_REF = Object.freeze({
|
|
218
|
+
docRef: invalidDocRef(),
|
|
219
|
+
model: {},
|
|
220
|
+
[pack_documentSchema_modelTypes.RecordCollectionRefBrand]: pack_documentSchema_modelTypes.RecordCollectionRefBrand,
|
|
221
|
+
get: () => void 0,
|
|
222
|
+
has: () => false,
|
|
223
|
+
set: () => Promise.reject(new Error("Invalid record collection reference")),
|
|
224
|
+
delete: () => Promise.reject(new Error("Invalid record collection reference")),
|
|
225
|
+
size: 0,
|
|
226
|
+
[Symbol.iterator]: () => ({
|
|
227
|
+
next: () => ({
|
|
228
|
+
done: true,
|
|
229
|
+
value: void 0
|
|
230
|
+
})
|
|
231
|
+
}),
|
|
232
|
+
onItemsAdded: () => () => {
|
|
233
|
+
},
|
|
234
|
+
onItemsChanged: () => () => {
|
|
235
|
+
},
|
|
236
|
+
onItemsDeleted: () => () => {
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
var createRecordCollectionRef = (documentService, docRef, model) => {
|
|
240
|
+
return new RecordCollectionRefImpl(documentService, docRef, model);
|
|
241
|
+
};
|
|
242
|
+
function invalidRecordCollectionRef() {
|
|
243
|
+
return INVALID_RECORD_COLLECTION_REF;
|
|
244
|
+
}
|
|
245
|
+
function isValidRecordCollectionRef(collectionRef) {
|
|
246
|
+
return collectionRef !== INVALID_RECORD_COLLECTION_REF;
|
|
247
|
+
}
|
|
248
|
+
var RecordCollectionRefImpl = class {
|
|
249
|
+
docRef;
|
|
250
|
+
model;
|
|
251
|
+
#documentService;
|
|
252
|
+
constructor(documentService, docRef, model) {
|
|
253
|
+
this.docRef = docRef;
|
|
254
|
+
this.model = model;
|
|
255
|
+
this.#documentService = documentService;
|
|
256
|
+
}
|
|
257
|
+
get(id) {
|
|
258
|
+
return this.#documentService.getRecord(this, id);
|
|
259
|
+
}
|
|
260
|
+
has(id) {
|
|
261
|
+
return this.#documentService.hasRecord(this, id);
|
|
262
|
+
}
|
|
263
|
+
async set(id, state) {
|
|
264
|
+
return this.#documentService.setCollectionRecord(this, id, state);
|
|
265
|
+
}
|
|
266
|
+
delete(id) {
|
|
267
|
+
const recordRefInstance = this.#documentService.getRecord(this, id);
|
|
268
|
+
if (recordRefInstance) {
|
|
269
|
+
return this.#documentService.deleteRecord(recordRefInstance);
|
|
270
|
+
}
|
|
271
|
+
return Promise.reject(new Error(`Unknown record`));
|
|
272
|
+
}
|
|
273
|
+
get size() {
|
|
274
|
+
return this.#documentService.getCollectionSize(this);
|
|
275
|
+
}
|
|
276
|
+
[Symbol.iterator]() {
|
|
277
|
+
return this.#documentService.getCollectionRecords(this)[Symbol.iterator]();
|
|
278
|
+
}
|
|
279
|
+
onItemsAdded = (callback) => {
|
|
280
|
+
return this.#documentService.onCollectionItemsAdded(this, callback);
|
|
281
|
+
};
|
|
282
|
+
onItemsChanged = (callback) => {
|
|
283
|
+
return this.#documentService.onCollectionItemsChanged(this, callback);
|
|
284
|
+
};
|
|
285
|
+
onItemsDeleted = (callback) => {
|
|
286
|
+
return this.#documentService.onCollectionItemsDeleted(this, callback);
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
var INVALID_RECORD_ID = "INVALID_RECORD_REF";
|
|
290
|
+
var INVALID_RECORD_REF = Object.freeze({
|
|
291
|
+
docRef: invalidDocRef(),
|
|
292
|
+
id: INVALID_RECORD_ID,
|
|
293
|
+
model: {},
|
|
294
|
+
[pack_documentSchema_modelTypes.RecordRefBrand]: pack_documentSchema_modelTypes.RecordRefBrand,
|
|
295
|
+
getSnapshot: () => Promise.reject(new Error("Invalid record reference")),
|
|
296
|
+
set: () => Promise.reject(new Error("Invalid record reference")),
|
|
297
|
+
onChange: () => () => {
|
|
298
|
+
},
|
|
299
|
+
onDeleted: () => () => {
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
var createRecordRef = (documentService, docRef, id, model) => {
|
|
303
|
+
return new RecordRefImpl(documentService, docRef, id, model);
|
|
304
|
+
};
|
|
305
|
+
function invalidRecordRef() {
|
|
306
|
+
return INVALID_RECORD_REF;
|
|
307
|
+
}
|
|
308
|
+
function isValidRecordRef(recordRef) {
|
|
309
|
+
return recordRef.id !== INVALID_RECORD_ID;
|
|
310
|
+
}
|
|
311
|
+
var RecordRefImpl = class {
|
|
312
|
+
docRef;
|
|
313
|
+
id;
|
|
314
|
+
model;
|
|
315
|
+
#documentService;
|
|
316
|
+
constructor(documentService, docRef, id, model) {
|
|
317
|
+
this.#documentService = documentService;
|
|
318
|
+
this.docRef = docRef;
|
|
319
|
+
this.id = id;
|
|
320
|
+
this.model = model;
|
|
321
|
+
}
|
|
322
|
+
async getSnapshot() {
|
|
323
|
+
return this.#documentService.getRecordSnapshot(this);
|
|
324
|
+
}
|
|
325
|
+
onChange(callback) {
|
|
326
|
+
return this.#documentService.onRecordChanged(this, callback);
|
|
327
|
+
}
|
|
328
|
+
onDeleted(callback) {
|
|
329
|
+
return this.#documentService.onRecordDeleted(this, callback);
|
|
330
|
+
}
|
|
331
|
+
delete() {
|
|
332
|
+
return this.#documentService.deleteRecord(this);
|
|
333
|
+
}
|
|
334
|
+
set(record) {
|
|
335
|
+
return this.#documentService.setRecord(this, record);
|
|
336
|
+
}
|
|
337
|
+
update(partialRecord) {
|
|
338
|
+
return this.#documentService.updateRecord(this, partialRecord);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
function initializeDocumentStructure(yDoc, schema) {
|
|
342
|
+
Object.values(schema).forEach((modelEntry) => {
|
|
343
|
+
yDoc.getMap(pack_documentSchema_modelTypes.getMetadata(modelEntry).name);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function getRecordsMap(yDoc, storageName) {
|
|
347
|
+
return yDoc.getMap(storageName);
|
|
348
|
+
}
|
|
349
|
+
function getRecordData(yDoc, storageName, recordId) {
|
|
350
|
+
const recordsCollection = getRecordsMap(yDoc, storageName);
|
|
351
|
+
return recordsCollection.get(recordId);
|
|
352
|
+
}
|
|
353
|
+
function setRecord(yDoc, storageName, recordId, state) {
|
|
354
|
+
const recordsCollection = getRecordsMap(yDoc, storageName);
|
|
355
|
+
const currentRecord = recordsCollection.get(recordId);
|
|
356
|
+
const wasExisting = currentRecord != null;
|
|
357
|
+
yDoc.transact(() => {
|
|
358
|
+
if (currentRecord != null) {
|
|
359
|
+
currentRecord.clear();
|
|
360
|
+
populateYMapFromState(currentRecord, state);
|
|
361
|
+
} else {
|
|
362
|
+
const newRecord = new Y__namespace.Map();
|
|
363
|
+
populateYMapFromState(newRecord, state);
|
|
364
|
+
recordsCollection.set(recordId, newRecord);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
return wasExisting;
|
|
368
|
+
}
|
|
369
|
+
function getRecordSnapshot(yDoc, storageName, recordId) {
|
|
370
|
+
const data = getRecordData(yDoc, storageName, recordId);
|
|
371
|
+
if (!data) {
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
return yMapToState(data);
|
|
375
|
+
}
|
|
376
|
+
function updateRecord(yDoc, storageName, recordId, partialState) {
|
|
377
|
+
const recordsCollection = getRecordsMap(yDoc, storageName);
|
|
378
|
+
const currentRecord = recordsCollection.get(recordId);
|
|
379
|
+
if (currentRecord == null) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
yDoc.transact(() => {
|
|
383
|
+
updateYMapFromPartialState(currentRecord, partialState);
|
|
384
|
+
});
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
function getAllRecordIds(yDoc, storageName) {
|
|
388
|
+
const recordsCollection = getRecordsMap(yDoc, storageName);
|
|
389
|
+
return Array.from(recordsCollection.keys()).map((key) => key);
|
|
390
|
+
}
|
|
391
|
+
function populateYMapFromState(yMap, state) {
|
|
392
|
+
if (state != null && typeof state === "object") {
|
|
393
|
+
Object.entries(state).forEach(([key, value]) => {
|
|
394
|
+
if (value === void 0) return;
|
|
395
|
+
if (Array.isArray(value)) {
|
|
396
|
+
const yArray = new Y__namespace.Array();
|
|
397
|
+
value.forEach((item) => {
|
|
398
|
+
yArray.push([item]);
|
|
399
|
+
});
|
|
400
|
+
yMap.set(key, yArray);
|
|
401
|
+
} else if (typeof value === "object" && value != null) {
|
|
402
|
+
const nestedMap = new Y__namespace.Map();
|
|
403
|
+
populateYMapFromState(nestedMap, value);
|
|
404
|
+
yMap.set(key, nestedMap);
|
|
405
|
+
} else {
|
|
406
|
+
yMap.set(key, value);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function updateYMapFromPartialState(yMap, partialState) {
|
|
412
|
+
if (typeof partialState === "object") {
|
|
413
|
+
Object.entries(partialState).forEach(([key, value]) => {
|
|
414
|
+
if (value === void 0) {
|
|
415
|
+
yMap.delete(key);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (Array.isArray(value)) {
|
|
419
|
+
const yArray = new Y__namespace.Array();
|
|
420
|
+
value.forEach((item) => {
|
|
421
|
+
yArray.push([item]);
|
|
422
|
+
});
|
|
423
|
+
yMap.set(key, yArray);
|
|
424
|
+
} else if (typeof value === "object" && value != null) {
|
|
425
|
+
const existingValue = yMap.get(key);
|
|
426
|
+
if (existingValue instanceof Y__namespace.Map) {
|
|
427
|
+
updateYMapFromPartialState(existingValue, value);
|
|
428
|
+
} else {
|
|
429
|
+
const nestedMap = new Y__namespace.Map();
|
|
430
|
+
populateYMapFromState(nestedMap, value);
|
|
431
|
+
yMap.set(key, nestedMap);
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
yMap.set(key, value);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function yMapToState(yMap) {
|
|
440
|
+
const state = {};
|
|
441
|
+
yMap.forEach((value, key) => {
|
|
442
|
+
if (value instanceof Y__namespace.Array) {
|
|
443
|
+
state[key] = value.toArray();
|
|
444
|
+
} else if (value instanceof Y__namespace.Map) {
|
|
445
|
+
state[key] = yMapToState(value);
|
|
446
|
+
} else {
|
|
447
|
+
state[key] = value;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
return state;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/service/BaseYjsDocumentService.ts
|
|
454
|
+
var BaseYjsDocumentService = class {
|
|
455
|
+
documents = /* @__PURE__ */ new Map();
|
|
456
|
+
constructor(app, logger) {
|
|
457
|
+
this.app = app;
|
|
458
|
+
this.logger = logger;
|
|
459
|
+
}
|
|
460
|
+
createDocRef = (id, schema) => {
|
|
461
|
+
const temporaryRef = createDocRef(this.app, id, schema);
|
|
462
|
+
const {
|
|
463
|
+
internalDocRef
|
|
464
|
+
} = this.getCreateInternalDoc(temporaryRef);
|
|
465
|
+
return internalDocRef;
|
|
466
|
+
};
|
|
467
|
+
getCreateRecordCollectionRef = (docRef, model) => {
|
|
468
|
+
const {
|
|
469
|
+
internalDoc
|
|
470
|
+
} = this.getCreateInternalDoc(docRef);
|
|
471
|
+
const modelName = pack_documentSchema_modelTypes.getMetadata(model).name;
|
|
472
|
+
const existingRef = internalDoc.collectionRefs.get(modelName)?.deref();
|
|
473
|
+
if (existingRef != null) {
|
|
474
|
+
return existingRef;
|
|
475
|
+
}
|
|
476
|
+
const newRef = createRecordCollectionRef(this, docRef, model);
|
|
477
|
+
internalDoc.collectionRefs.set(modelName, new WeakRef(newRef));
|
|
478
|
+
return newRef;
|
|
479
|
+
};
|
|
480
|
+
getCreateRecordRef = (docRef, id, model) => {
|
|
481
|
+
const {
|
|
482
|
+
internalDoc
|
|
483
|
+
} = this.getCreateInternalDoc(docRef);
|
|
484
|
+
const modelName = pack_documentSchema_modelTypes.getMetadata(model).name;
|
|
485
|
+
let modelMap = internalDoc.recordRefs.get(modelName);
|
|
486
|
+
if (!modelMap) {
|
|
487
|
+
modelMap = /* @__PURE__ */ new Map();
|
|
488
|
+
internalDoc.recordRefs.set(modelName, modelMap);
|
|
489
|
+
}
|
|
490
|
+
const existingRef = modelMap.get(id)?.deref();
|
|
491
|
+
if (existingRef != null) {
|
|
492
|
+
return existingRef;
|
|
493
|
+
}
|
|
494
|
+
const newRef = createRecordRef(this, docRef, id, model);
|
|
495
|
+
modelMap.set(id, new WeakRef(newRef));
|
|
496
|
+
return newRef;
|
|
497
|
+
};
|
|
498
|
+
/**
|
|
499
|
+
* Called when the first metadata subscription is opened for a document.
|
|
500
|
+
* Implementation must:
|
|
501
|
+
* - Set status to LOADING immediately
|
|
502
|
+
* - Load/validate metadata asynchronously
|
|
503
|
+
* - Set status to LOADED or ERROR when complete
|
|
504
|
+
* - Handle all errors internally (never throw/reject)
|
|
505
|
+
*/
|
|
506
|
+
/**
|
|
507
|
+
* Called when the first data subscription is opened for a document.
|
|
508
|
+
* Implementation must:
|
|
509
|
+
* - Set status to LOADING immediately
|
|
510
|
+
* - Set up data synchronization asynchronously
|
|
511
|
+
* - Set status to LOADED or ERROR when ready
|
|
512
|
+
* - Handle all errors internally (never throw/reject)
|
|
513
|
+
*/
|
|
514
|
+
/**
|
|
515
|
+
* Called when the last metadata subscription is closed for a document.
|
|
516
|
+
* Implementation should clean up any resources related to metadata loading.
|
|
517
|
+
*/
|
|
518
|
+
/**
|
|
519
|
+
* Called when the last data subscription is closed for a document.
|
|
520
|
+
* Implementation should clean up any resources related to data synchronization.
|
|
521
|
+
*/
|
|
522
|
+
createBaseInternalDoc = (ref, metadata, yDoc) => {
|
|
523
|
+
const schema = ref.schema;
|
|
524
|
+
return {
|
|
525
|
+
ref: new WeakRef(ref),
|
|
526
|
+
metadata,
|
|
527
|
+
schema,
|
|
528
|
+
metadataStatus: {
|
|
529
|
+
load: metadata ? DocumentLoadStatus.LOADED : DocumentLoadStatus.UNLOADED,
|
|
530
|
+
live: DocumentLiveStatus.DISCONNECTED
|
|
531
|
+
},
|
|
532
|
+
dataStatus: {
|
|
533
|
+
load: DocumentLoadStatus.UNLOADED,
|
|
534
|
+
live: DocumentLiveStatus.DISCONNECTED
|
|
535
|
+
},
|
|
536
|
+
metadataError: void 0,
|
|
537
|
+
dataError: void 0,
|
|
538
|
+
statusSubscribers: /* @__PURE__ */ new Set(),
|
|
539
|
+
hasMetadataSubscriptions: false,
|
|
540
|
+
hasDataSubscriptions: false,
|
|
541
|
+
collectionRefs: /* @__PURE__ */ new Map(),
|
|
542
|
+
recordRefs: /* @__PURE__ */ new Map(),
|
|
543
|
+
collectionSubscriptions: /* @__PURE__ */ new Map(),
|
|
544
|
+
docStateSubscribers: /* @__PURE__ */ new Set(),
|
|
545
|
+
metadataSubscribers: /* @__PURE__ */ new Set(),
|
|
546
|
+
recordSubscriptions: /* @__PURE__ */ new Map(),
|
|
547
|
+
yDoc: yDoc || this.initializeYDoc(schema),
|
|
548
|
+
yDocUpdateHandler: void 0,
|
|
549
|
+
yjsCollectionHandlers: /* @__PURE__ */ new Map()
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
hasSubscriptions(internalDoc) {
|
|
553
|
+
if (internalDoc.metadataSubscribers.size > 0 || internalDoc.docStateSubscribers.size > 0) {
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
for (const subs of internalDoc.recordSubscriptions.values()) {
|
|
557
|
+
if (!subs.changed?.size || !subs.deleted?.size) {
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
// Status helper methods
|
|
564
|
+
notifyStatusSubscribers(internalDoc, docRef) {
|
|
565
|
+
const status = {
|
|
566
|
+
metadata: internalDoc.metadataStatus,
|
|
567
|
+
data: internalDoc.dataStatus,
|
|
568
|
+
metadataError: internalDoc.metadataError,
|
|
569
|
+
dataError: internalDoc.dataError
|
|
570
|
+
};
|
|
571
|
+
for (const callback of internalDoc.statusSubscribers) {
|
|
572
|
+
callback(docRef, status);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
updateMetadataStatus(internalDoc, docRef, update) {
|
|
576
|
+
if (update.load != null || update.live != null) {
|
|
577
|
+
internalDoc.metadataStatus = {
|
|
578
|
+
load: update.load ?? internalDoc.metadataStatus.load,
|
|
579
|
+
live: update.live ?? internalDoc.metadataStatus.live
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
if (update.error != null) {
|
|
583
|
+
internalDoc.metadataError = update.error;
|
|
584
|
+
} else if (update.load === DocumentLoadStatus.LOADED) {
|
|
585
|
+
internalDoc.metadataError = void 0;
|
|
586
|
+
}
|
|
587
|
+
this.notifyStatusSubscribers(internalDoc, docRef);
|
|
588
|
+
}
|
|
589
|
+
updateDataStatus(internalDoc, docRef, update) {
|
|
590
|
+
if (update.load != null || update.live != null) {
|
|
591
|
+
internalDoc.dataStatus = {
|
|
592
|
+
load: update.load ?? internalDoc.dataStatus.load,
|
|
593
|
+
live: update.live ?? internalDoc.dataStatus.live
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
if (update.error != null) {
|
|
597
|
+
internalDoc.dataError = update.error;
|
|
598
|
+
} else if (update.load === DocumentLoadStatus.LOADED) {
|
|
599
|
+
internalDoc.dataError = void 0;
|
|
600
|
+
}
|
|
601
|
+
this.notifyStatusSubscribers(internalDoc, docRef);
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Hook method called after a record is set. Subclasses can override to handle
|
|
605
|
+
* backend synchronization, logging, or other side effects.
|
|
606
|
+
*/
|
|
607
|
+
/**
|
|
608
|
+
* Initialize a Y.Doc with the given schema
|
|
609
|
+
*/
|
|
610
|
+
initializeYDoc(schema) {
|
|
611
|
+
const yDoc = new Y__namespace.Doc();
|
|
612
|
+
initializeDocumentStructure(yDoc, schema);
|
|
613
|
+
return yDoc;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Get existing internal doc or create one with placeholder metadata for lazy initialization
|
|
617
|
+
*/
|
|
618
|
+
getCreateInternalDoc(ref, metadata, initialYDoc) {
|
|
619
|
+
const {
|
|
620
|
+
id,
|
|
621
|
+
schema
|
|
622
|
+
} = ref;
|
|
623
|
+
const existingDoc = this.documents.get(id);
|
|
624
|
+
if (existingDoc != null) {
|
|
625
|
+
!(existingDoc.schema === schema || remeda.isDeepEqual(existingDoc.schema, schema)) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, "Schema mismatch for existing document") : invariant__default.default(false) : void 0;
|
|
626
|
+
const existingRef = existingDoc.ref.deref();
|
|
627
|
+
if (existingRef == null) {
|
|
628
|
+
existingDoc.ref = new WeakRef(ref);
|
|
629
|
+
}
|
|
630
|
+
return {
|
|
631
|
+
internalDocRef: existingRef ?? ref,
|
|
632
|
+
internalDoc: existingDoc,
|
|
633
|
+
wasExisting: true
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
const internalDoc = this.createInternalDoc(ref, metadata, initialYDoc);
|
|
637
|
+
this.documents.set(id, internalDoc);
|
|
638
|
+
return {
|
|
639
|
+
internalDocRef: ref,
|
|
640
|
+
internalDoc,
|
|
641
|
+
wasExisting: false
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
getDocumentSnapshot = (docRef) => {
|
|
645
|
+
const {
|
|
646
|
+
internalDoc
|
|
647
|
+
} = this.getCreateInternalDoc(docRef);
|
|
648
|
+
return Promise.resolve(internalDoc.yDoc);
|
|
649
|
+
};
|
|
650
|
+
getRecordSnapshot = (recordRef) => {
|
|
651
|
+
const {
|
|
652
|
+
internalDoc
|
|
653
|
+
} = this.getCreateInternalDoc(recordRef.docRef);
|
|
654
|
+
const snapshot = this.getRecordSnapshotInternal(internalDoc, recordRef);
|
|
655
|
+
if (snapshot == null) {
|
|
656
|
+
return Promise.reject(new Error(`Record not found: ${recordRef.id}`));
|
|
657
|
+
}
|
|
658
|
+
return Promise.resolve(snapshot);
|
|
659
|
+
};
|
|
660
|
+
getRecordSnapshotInternal(internalDoc, recordRef) {
|
|
661
|
+
return getRecordSnapshot(internalDoc.yDoc, pack_documentSchema_modelTypes.getMetadata(recordRef.model).name, recordRef.id);
|
|
662
|
+
}
|
|
663
|
+
setRecord = (recordRef, state) => {
|
|
664
|
+
const internalDoc = this.documents.get(recordRef.docRef.id);
|
|
665
|
+
!(internalDoc != null) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, `Cannot set record as document not found: ${recordRef.docRef.id}`) : invariant__default.default(false) : void 0;
|
|
666
|
+
setRecord(internalDoc.yDoc, pack_documentSchema_modelTypes.getMetadata(recordRef.model).name, recordRef.id, state);
|
|
667
|
+
this.onRecordSet?.(recordRef, state);
|
|
668
|
+
return Promise.resolve();
|
|
669
|
+
};
|
|
670
|
+
updateRecord = (recordRef, partialState) => {
|
|
671
|
+
const internalDoc = this.documents.get(recordRef.docRef.id);
|
|
672
|
+
!(internalDoc != null) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, `Cannot update record as document not found: ${recordRef.docRef.id}`) : invariant__default.default(false) : void 0;
|
|
673
|
+
const wasUpdated = updateRecord(internalDoc.yDoc, pack_documentSchema_modelTypes.getMetadata(recordRef.model).name, recordRef.id, partialState);
|
|
674
|
+
if (!wasUpdated) {
|
|
675
|
+
return Promise.reject(new Error(`Record not found for update: ${recordRef.id}`));
|
|
676
|
+
}
|
|
677
|
+
this.onRecordSet?.(recordRef, partialState);
|
|
678
|
+
return Promise.resolve();
|
|
679
|
+
};
|
|
680
|
+
onMetadataChange(docRef, callback) {
|
|
681
|
+
const {
|
|
682
|
+
internalDoc,
|
|
683
|
+
internalDocRef
|
|
684
|
+
} = this.getCreateInternalDoc(docRef);
|
|
685
|
+
const isFirstSubscription = !internalDoc.hasMetadataSubscriptions;
|
|
686
|
+
internalDoc.metadataSubscribers.add(callback);
|
|
687
|
+
internalDoc.hasMetadataSubscriptions = true;
|
|
688
|
+
if (isFirstSubscription && internalDoc.metadataStatus.load === DocumentLoadStatus.UNLOADED) {
|
|
689
|
+
this.onMetadataSubscriptionOpened(internalDoc, internalDocRef);
|
|
690
|
+
}
|
|
691
|
+
if (internalDoc.metadata != null) {
|
|
692
|
+
callback(docRef, internalDoc.metadata);
|
|
693
|
+
}
|
|
694
|
+
return () => {
|
|
695
|
+
const currentDoc = this.documents.get(docRef.id);
|
|
696
|
+
if (currentDoc) {
|
|
697
|
+
currentDoc.metadataSubscribers.delete(callback);
|
|
698
|
+
if (currentDoc.metadataSubscribers.size === 0) {
|
|
699
|
+
currentDoc.hasMetadataSubscriptions = false;
|
|
700
|
+
this.onMetadataSubscriptionClosed(currentDoc, internalDocRef);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
onStateChange = (docRef, callback) => {
|
|
706
|
+
const {
|
|
707
|
+
internalDoc,
|
|
708
|
+
internalDocRef
|
|
709
|
+
} = this.getCreateInternalDoc(docRef);
|
|
710
|
+
const isFirstDataSubscription = !internalDoc.hasDataSubscriptions;
|
|
711
|
+
const isFirstStateSubscription = internalDoc.docStateSubscribers.size === 0;
|
|
712
|
+
internalDoc.docStateSubscribers.add(callback);
|
|
713
|
+
internalDoc.hasDataSubscriptions = true;
|
|
714
|
+
if (isFirstDataSubscription && internalDoc.dataStatus.load === DocumentLoadStatus.UNLOADED) {
|
|
715
|
+
this.onDataSubscriptionOpened(internalDoc, internalDocRef);
|
|
716
|
+
}
|
|
717
|
+
if (isFirstStateSubscription && !internalDoc.yDocUpdateHandler) {
|
|
718
|
+
const updateHandler = () => {
|
|
719
|
+
this.notifyStateSubscribers(internalDoc, docRef);
|
|
720
|
+
};
|
|
721
|
+
internalDoc.yDoc.on("update", updateHandler);
|
|
722
|
+
internalDoc.yDocUpdateHandler = updateHandler;
|
|
723
|
+
}
|
|
724
|
+
callback(internalDocRef);
|
|
725
|
+
return () => {
|
|
726
|
+
const currentDoc = this.documents.get(docRef.id);
|
|
727
|
+
if (!currentDoc) return;
|
|
728
|
+
currentDoc.docStateSubscribers.delete(callback);
|
|
729
|
+
if (currentDoc.docStateSubscribers.size === 0 && currentDoc.yDocUpdateHandler) {
|
|
730
|
+
currentDoc.yDoc.off("update", currentDoc.yDocUpdateHandler);
|
|
731
|
+
currentDoc.yDocUpdateHandler = void 0;
|
|
732
|
+
}
|
|
733
|
+
const hasDataSubs = currentDoc.docStateSubscribers.size > 0 || currentDoc.recordSubscriptions.size > 0 || Array.from(currentDoc.collectionSubscriptions.values()).some((subs) => subs.added?.size || subs.changed?.size || subs.deleted?.size);
|
|
734
|
+
if (!hasDataSubs) {
|
|
735
|
+
currentDoc.hasDataSubscriptions = false;
|
|
736
|
+
this.onDataSubscriptionClosed(currentDoc, internalDocRef);
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
};
|
|
740
|
+
getDocumentRef(docId) {
|
|
741
|
+
const internalDoc = this.documents.get(docId);
|
|
742
|
+
if (!internalDoc) return null;
|
|
743
|
+
return createDocRef(this.app, docId, internalDoc.schema);
|
|
744
|
+
}
|
|
745
|
+
notifyMetadataSubscribers(internalDoc, docRef, metadata) {
|
|
746
|
+
for (const callback of internalDoc.metadataSubscribers) {
|
|
747
|
+
callback(docRef, metadata);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
notifyStateSubscribers(internalDoc, docRef) {
|
|
751
|
+
for (const callback of internalDoc.docStateSubscribers) {
|
|
752
|
+
callback(docRef);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
updateMetadata(docId, metadata) {
|
|
756
|
+
const internalDoc = this.documents.get(docId);
|
|
757
|
+
if (internalDoc) {
|
|
758
|
+
internalDoc.metadata = metadata;
|
|
759
|
+
const docRef = this.getDocumentRef(docId);
|
|
760
|
+
if (docRef) {
|
|
761
|
+
this.notifyMetadataSubscribers(internalDoc, docRef, metadata);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
notifyCollectionSubscribers(internalDoc, collection, recordId, changeType) {
|
|
766
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
767
|
+
const subs = internalDoc.collectionSubscriptions.get(storageName);
|
|
768
|
+
if (!subs) {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const subscribers = subs[changeType];
|
|
772
|
+
if (subscribers == null || subscribers.size === 0) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const recordRefInstance = this.getCreateRecordRef(collection.docRef, recordId, collection.model);
|
|
776
|
+
const records = [recordRefInstance];
|
|
777
|
+
for (const callback of subscribers) {
|
|
778
|
+
callback(records);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
notifyRecordSubscribers(recordRef, changeType) {
|
|
782
|
+
const internalDoc = this.documents.get(recordRef.docRef.id);
|
|
783
|
+
!(internalDoc != null) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, "Document not found for record notifications") : invariant__default.default(false) : void 0;
|
|
784
|
+
const recordSubs = internalDoc.recordSubscriptions.get(recordRef.id);
|
|
785
|
+
if (recordSubs == null) {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
!(pack_documentSchema_modelTypes.getMetadata(recordSubs.ref.model).name === pack_documentSchema_modelTypes.getMetadata(recordRef.model).name) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, `Model mismatch when notifying record subscribers for ${recordRef.id}: expected ${pack_documentSchema_modelTypes.getMetadata(recordSubs.ref.model).name}, got ${pack_documentSchema_modelTypes.getMetadata(recordRef.model).name}`) : invariant__default.default(false) : void 0;
|
|
789
|
+
switch (changeType) {
|
|
790
|
+
case "changed": {
|
|
791
|
+
const snapshot = this.getRecordSnapshotInternal(internalDoc, recordRef);
|
|
792
|
+
for (const callback of recordSubs.changed ?? []) {
|
|
793
|
+
try {
|
|
794
|
+
callback(snapshot, recordRef);
|
|
795
|
+
} catch (e) {
|
|
796
|
+
console.error("Record onChanged callback threw unhandled error", e, {
|
|
797
|
+
model: pack_documentSchema_modelTypes.getMetadata(recordRef.model).name,
|
|
798
|
+
id: recordRef.id
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
case "deleted": {
|
|
805
|
+
for (const callback of recordSubs.deleted ?? []) {
|
|
806
|
+
try {
|
|
807
|
+
callback(recordRef);
|
|
808
|
+
} catch (e) {
|
|
809
|
+
console.error("Record onDeleted callback threw unhandled error", e, {
|
|
810
|
+
model: pack_documentSchema_modelTypes.getMetadata(recordRef.model).name,
|
|
811
|
+
id: recordRef.id
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// Collection methods implementation
|
|
820
|
+
getRecord = (collection, id) => {
|
|
821
|
+
const internalDoc = this.documents.get(collection.docRef.id);
|
|
822
|
+
if (!internalDoc) return void 0;
|
|
823
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
824
|
+
const recordExists = getRecordData(internalDoc.yDoc, storageName, id);
|
|
825
|
+
return recordExists ? this.getCreateRecordRef(collection.docRef, id, collection.model) : void 0;
|
|
826
|
+
};
|
|
827
|
+
hasRecord = (collection, id) => {
|
|
828
|
+
const internalDoc = this.documents.get(collection.docRef.id);
|
|
829
|
+
if (!internalDoc) return false;
|
|
830
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
831
|
+
return getRecordData(internalDoc.yDoc, storageName, id) != null;
|
|
832
|
+
};
|
|
833
|
+
setCollectionRecord = (collection, id, state) => {
|
|
834
|
+
const recordRefInstance = this.getCreateRecordRef(collection.docRef, id, collection.model);
|
|
835
|
+
return this.setRecord(recordRefInstance, state);
|
|
836
|
+
};
|
|
837
|
+
deleteRecord = (record) => {
|
|
838
|
+
const internalDoc = this.documents.get(record.docRef.id);
|
|
839
|
+
if (!internalDoc) {
|
|
840
|
+
return Promise.resolve();
|
|
841
|
+
}
|
|
842
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(record.model).name;
|
|
843
|
+
const recordsCollection = getRecordsMap(internalDoc.yDoc, storageName);
|
|
844
|
+
const existed = recordsCollection.has(record.id);
|
|
845
|
+
if (existed) {
|
|
846
|
+
recordsCollection.delete(record.id);
|
|
847
|
+
}
|
|
848
|
+
return Promise.resolve();
|
|
849
|
+
};
|
|
850
|
+
getCollectionSize = (collection) => {
|
|
851
|
+
const internalDoc = this.documents.get(collection.docRef.id);
|
|
852
|
+
if (!internalDoc) return 0;
|
|
853
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
854
|
+
return getAllRecordIds(internalDoc.yDoc, storageName).length;
|
|
855
|
+
};
|
|
856
|
+
getCollectionRecords = (collection) => {
|
|
857
|
+
const internalDoc = this.documents.get(collection.docRef.id);
|
|
858
|
+
if (!internalDoc) return [];
|
|
859
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
860
|
+
const recordIds = getAllRecordIds(internalDoc.yDoc, storageName);
|
|
861
|
+
return recordIds.map((id) => this.getCreateRecordRef(collection.docRef, id, collection.model));
|
|
862
|
+
};
|
|
863
|
+
onCollectionItemsAdded = (collection, callback) => {
|
|
864
|
+
const {
|
|
865
|
+
internalDoc,
|
|
866
|
+
internalDocRef
|
|
867
|
+
} = this.getCreateInternalDoc(collection.docRef);
|
|
868
|
+
return this.subscribeToCollectionChanges(internalDoc, internalDocRef, collection, "added", callback);
|
|
869
|
+
};
|
|
870
|
+
onCollectionItemsChanged = (collection, callback) => {
|
|
871
|
+
const {
|
|
872
|
+
internalDoc,
|
|
873
|
+
internalDocRef
|
|
874
|
+
} = this.getCreateInternalDoc(collection.docRef);
|
|
875
|
+
return this.subscribeToCollectionChanges(internalDoc, internalDocRef, collection, "changed", callback);
|
|
876
|
+
};
|
|
877
|
+
onCollectionItemsDeleted = (collection, callback) => {
|
|
878
|
+
const {
|
|
879
|
+
internalDoc,
|
|
880
|
+
internalDocRef
|
|
881
|
+
} = this.getCreateInternalDoc(collection.docRef);
|
|
882
|
+
return this.subscribeToCollectionChanges(internalDoc, internalDocRef, collection, "deleted", callback);
|
|
883
|
+
};
|
|
884
|
+
// TODO: clearer naming of subscription vs handlers etc.
|
|
885
|
+
onRecordChanged = (record, callback) => {
|
|
886
|
+
const {
|
|
887
|
+
internalDoc,
|
|
888
|
+
internalDocRef
|
|
889
|
+
} = this.getCreateInternalDoc(record.docRef);
|
|
890
|
+
const isFirstDataSubscription = !internalDoc.hasDataSubscriptions;
|
|
891
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(record.model).name;
|
|
892
|
+
const collectionRef = this.getCreateRecordCollectionRef(record.docRef, record.model);
|
|
893
|
+
const needsCollectionListener = !internalDoc.yjsCollectionHandlers.has(storageName);
|
|
894
|
+
const recordSubs = this.getCreateRecordSubscriptions(internalDoc, record);
|
|
895
|
+
(recordSubs.changed ??= /* @__PURE__ */ new Set()).add(callback);
|
|
896
|
+
internalDoc.hasDataSubscriptions = true;
|
|
897
|
+
if (isFirstDataSubscription && internalDoc.dataStatus.load === DocumentLoadStatus.UNLOADED) {
|
|
898
|
+
this.onDataSubscriptionOpened(internalDoc, internalDocRef);
|
|
899
|
+
}
|
|
900
|
+
if (needsCollectionListener) {
|
|
901
|
+
this.getCreateCollectionSubscriptions(internalDoc, collectionRef);
|
|
902
|
+
this.setupCollectionListener(internalDoc, collectionRef);
|
|
903
|
+
}
|
|
904
|
+
const snapshot = this.getRecordSnapshotInternal(internalDoc, record);
|
|
905
|
+
if (snapshot != null) {
|
|
906
|
+
callback(snapshot, record);
|
|
907
|
+
}
|
|
908
|
+
return () => {
|
|
909
|
+
recordSubs.changed?.delete(callback);
|
|
910
|
+
const currentDoc = this.documents.get(record.docRef.id);
|
|
911
|
+
if (!currentDoc) return;
|
|
912
|
+
if (isRecordSubscriptionsEmpty(recordSubs)) {
|
|
913
|
+
currentDoc.recordSubscriptions.delete(record.id);
|
|
914
|
+
}
|
|
915
|
+
this.cleanupCollectionListenerIfUnused(currentDoc, record.docRef.id, storageName);
|
|
916
|
+
const hasDataSubs = currentDoc.docStateSubscribers.size > 0 || currentDoc.recordSubscriptions.size > 0 || Array.from(currentDoc.collectionSubscriptions.values()).some((subs) => subs.added?.size || subs.changed?.size || subs.deleted?.size);
|
|
917
|
+
if (!hasDataSubs) {
|
|
918
|
+
currentDoc.hasDataSubscriptions = false;
|
|
919
|
+
this.onDataSubscriptionClosed(currentDoc, internalDocRef);
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
};
|
|
923
|
+
onRecordDeleted = (record, callback) => {
|
|
924
|
+
const {
|
|
925
|
+
internalDoc,
|
|
926
|
+
internalDocRef
|
|
927
|
+
} = this.getCreateInternalDoc(record.docRef);
|
|
928
|
+
const isFirstDataSubscription = !internalDoc.hasDataSubscriptions;
|
|
929
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(record.model).name;
|
|
930
|
+
const collectionRef = this.getCreateRecordCollectionRef(record.docRef, record.model);
|
|
931
|
+
const needsCollectionListener = !internalDoc.yjsCollectionHandlers.has(storageName);
|
|
932
|
+
const recordSubs = this.getCreateRecordSubscriptions(internalDoc, record);
|
|
933
|
+
(recordSubs.deleted ??= /* @__PURE__ */ new Set()).add(callback);
|
|
934
|
+
internalDoc.hasDataSubscriptions = true;
|
|
935
|
+
if (isFirstDataSubscription && internalDoc.dataStatus.load === DocumentLoadStatus.UNLOADED) {
|
|
936
|
+
this.onDataSubscriptionOpened(internalDoc, internalDocRef);
|
|
937
|
+
}
|
|
938
|
+
if (needsCollectionListener) {
|
|
939
|
+
this.getCreateCollectionSubscriptions(internalDoc, collectionRef);
|
|
940
|
+
this.setupCollectionListener(internalDoc, collectionRef);
|
|
941
|
+
}
|
|
942
|
+
return () => {
|
|
943
|
+
recordSubs.deleted?.delete(callback);
|
|
944
|
+
const currentDoc = this.documents.get(record.docRef.id);
|
|
945
|
+
if (!currentDoc) return;
|
|
946
|
+
if (isRecordSubscriptionsEmpty(recordSubs)) {
|
|
947
|
+
currentDoc.recordSubscriptions.delete(record.id);
|
|
948
|
+
}
|
|
949
|
+
this.cleanupCollectionListenerIfUnused(currentDoc, record.docRef.id, storageName);
|
|
950
|
+
const hasDataSubs = currentDoc.docStateSubscribers.size > 0 || currentDoc.recordSubscriptions.size > 0 || Array.from(currentDoc.collectionSubscriptions.values()).some((subs) => subs.added?.size || subs.changed?.size || subs.deleted?.size);
|
|
951
|
+
if (!hasDataSubs) {
|
|
952
|
+
currentDoc.hasDataSubscriptions = false;
|
|
953
|
+
this.onDataSubscriptionClosed(currentDoc, internalDocRef);
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
};
|
|
957
|
+
getCreateCollectionSubscriptions(internalDoc, collection) {
|
|
958
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
959
|
+
const docCollectionSubs = internalDoc.collectionSubscriptions.get(storageName) ?? internalDoc.collectionSubscriptions.set(storageName, {}).get(storageName);
|
|
960
|
+
return docCollectionSubs;
|
|
961
|
+
}
|
|
962
|
+
getCreateRecordSubscriptions(internalDoc, record) {
|
|
963
|
+
let recordSubs = internalDoc.recordSubscriptions.get(record.id);
|
|
964
|
+
if (!recordSubs) {
|
|
965
|
+
recordSubs = {
|
|
966
|
+
ref: record
|
|
967
|
+
};
|
|
968
|
+
internalDoc.recordSubscriptions.set(record.id, recordSubs);
|
|
969
|
+
} else {
|
|
970
|
+
if (pack_documentSchema_modelTypes.getMetadata(recordSubs.ref.model).name !== pack_documentSchema_modelTypes.getMetadata(record.model).name) {
|
|
971
|
+
throw new Error(`Model mismatch for record ${record.id}: expected ${pack_documentSchema_modelTypes.getMetadata(recordSubs.ref.model).name}, got ${pack_documentSchema_modelTypes.getMetadata(record.model).name}`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return recordSubs;
|
|
975
|
+
}
|
|
976
|
+
subscribeToCollectionChanges(internalDoc, internalDocRef, collection, changeType, callback) {
|
|
977
|
+
const isFirstDataSubscription = !internalDoc.hasDataSubscriptions;
|
|
978
|
+
const modelSubscriptions = this.getCreateCollectionSubscriptions(internalDoc, collection);
|
|
979
|
+
const wasEmpty = isCollectionSubscriptionsEmpty(modelSubscriptions);
|
|
980
|
+
(modelSubscriptions[changeType] ??= /* @__PURE__ */ new Set()).add(callback);
|
|
981
|
+
internalDoc.hasDataSubscriptions = true;
|
|
982
|
+
if (isFirstDataSubscription && internalDoc.dataStatus.load === DocumentLoadStatus.UNLOADED) {
|
|
983
|
+
this.onDataSubscriptionOpened(internalDoc, internalDocRef);
|
|
984
|
+
}
|
|
985
|
+
if (wasEmpty) {
|
|
986
|
+
this.setupCollectionListener(internalDoc, collection);
|
|
987
|
+
}
|
|
988
|
+
return () => {
|
|
989
|
+
modelSubscriptions[changeType]?.delete(callback);
|
|
990
|
+
const currentDoc = this.documents.get(collection.docRef.id);
|
|
991
|
+
if (!currentDoc) return;
|
|
992
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
993
|
+
this.cleanupCollectionListenerIfUnused(currentDoc, collection.docRef.id, storageName);
|
|
994
|
+
const hasDataSubs = currentDoc.docStateSubscribers.size > 0 || currentDoc.recordSubscriptions.size > 0 || Array.from(currentDoc.collectionSubscriptions.values()).some((subs) => subs.added?.size || subs.changed?.size || subs.deleted?.size);
|
|
995
|
+
if (!hasDataSubs) {
|
|
996
|
+
currentDoc.hasDataSubscriptions = false;
|
|
997
|
+
this.onDataSubscriptionClosed(currentDoc, internalDocRef);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
setupCollectionListener(internalDoc, collection) {
|
|
1002
|
+
const docId = collection.docRef.id;
|
|
1003
|
+
const storageName = pack_documentSchema_modelTypes.getMetadata(collection.model).name;
|
|
1004
|
+
const yCollection = internalDoc.yDoc.getMap(storageName);
|
|
1005
|
+
this.logger.debug("Setting up collection listener", {
|
|
1006
|
+
docId,
|
|
1007
|
+
storageName,
|
|
1008
|
+
existingKeys: Array.from(yCollection.keys()),
|
|
1009
|
+
allDocMaps: Array.from(internalDoc.yDoc.share.keys())
|
|
1010
|
+
});
|
|
1011
|
+
const eventHandler = (events) => {
|
|
1012
|
+
this.logger.debug("Y.Map observeDeep fired", {
|
|
1013
|
+
docId,
|
|
1014
|
+
storageName,
|
|
1015
|
+
eventCount: events.length
|
|
1016
|
+
});
|
|
1017
|
+
const currentDoc = this.documents.get(docId);
|
|
1018
|
+
if (!currentDoc) return;
|
|
1019
|
+
const subs = currentDoc.collectionSubscriptions.get(storageName);
|
|
1020
|
+
if (!subs) return;
|
|
1021
|
+
const addedKeys = /* @__PURE__ */ new Set();
|
|
1022
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
1023
|
+
const deletedKeys = /* @__PURE__ */ new Set();
|
|
1024
|
+
for (const event of events) {
|
|
1025
|
+
if (event.target === yCollection) {
|
|
1026
|
+
for (const [key, change] of event.changes.keys) {
|
|
1027
|
+
switch (change.action) {
|
|
1028
|
+
case "add":
|
|
1029
|
+
addedKeys.add(key);
|
|
1030
|
+
break;
|
|
1031
|
+
case "update":
|
|
1032
|
+
changedKeys.add(key);
|
|
1033
|
+
break;
|
|
1034
|
+
case "delete":
|
|
1035
|
+
deletedKeys.add(key);
|
|
1036
|
+
break;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
} else {
|
|
1040
|
+
const recordId = event.path[0];
|
|
1041
|
+
if (recordId != null) {
|
|
1042
|
+
changedKeys.add(recordId);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
if (addedKeys.size > 0) {
|
|
1047
|
+
const addedRecords = Array.from(addedKeys).map((id) => this.getCreateRecordRef(collection.docRef, id, collection.model));
|
|
1048
|
+
if (subs.added != null) {
|
|
1049
|
+
for (const callback of subs.added) {
|
|
1050
|
+
callback(addedRecords);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
for (const record of addedRecords) {
|
|
1054
|
+
this.notifyRecordSubscribers(record, "changed");
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
if (changedKeys.size > 0) {
|
|
1058
|
+
const changedRecords = Array.from(changedKeys).map((id) => this.getCreateRecordRef(collection.docRef, id, collection.model));
|
|
1059
|
+
if (subs.changed != null) {
|
|
1060
|
+
for (const callback of subs.changed) {
|
|
1061
|
+
callback(changedRecords);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
for (const record of changedRecords) {
|
|
1065
|
+
this.notifyRecordSubscribers(record, "changed");
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
if (deletedKeys.size > 0) {
|
|
1069
|
+
const deletedRecords = Array.from(deletedKeys).map((id) => this.getCreateRecordRef(collection.docRef, id, collection.model));
|
|
1070
|
+
if (subs.deleted?.size) {
|
|
1071
|
+
for (const callback of subs.deleted) {
|
|
1072
|
+
callback(deletedRecords);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
for (const record of deletedRecords) {
|
|
1076
|
+
this.notifyRecordSubscribers(record, "deleted");
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
yCollection.observeDeep(eventHandler);
|
|
1081
|
+
internalDoc.yjsCollectionHandlers.set(storageName, () => {
|
|
1082
|
+
yCollection.unobserveDeep(eventHandler);
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
cleanupCollectionListener(docId, storageName) {
|
|
1086
|
+
const internalDoc = this.documents.get(docId);
|
|
1087
|
+
if (internalDoc == null) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const cleanup = internalDoc.yjsCollectionHandlers.get(storageName);
|
|
1091
|
+
if (cleanup != null) {
|
|
1092
|
+
cleanup();
|
|
1093
|
+
internalDoc.yjsCollectionHandlers.delete(storageName);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
cleanupCollectionListenerIfUnused(internalDoc, docId, storageName) {
|
|
1097
|
+
const collectionSubs = internalDoc.collectionSubscriptions.get(storageName);
|
|
1098
|
+
const hasCollectionSubs = collectionSubs != null && (collectionSubs.added?.size || collectionSubs.changed?.size || collectionSubs.deleted?.size);
|
|
1099
|
+
const hasRecordSubs = Array.from(internalDoc.recordSubscriptions.values()).some((recordSubs) => pack_documentSchema_modelTypes.getMetadata(recordSubs.ref.model).name === storageName && !isRecordSubscriptionsEmpty(recordSubs));
|
|
1100
|
+
if (!hasCollectionSubs && !hasRecordSubs) {
|
|
1101
|
+
this.cleanupCollectionListener(docId, storageName);
|
|
1102
|
+
if (collectionSubs != null) {
|
|
1103
|
+
internalDoc.collectionSubscriptions.delete(storageName);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
// DocumentService status methods implementation
|
|
1108
|
+
getDocumentStatus = (docRef) => {
|
|
1109
|
+
const {
|
|
1110
|
+
internalDoc
|
|
1111
|
+
} = this.getCreateInternalDoc(docRef);
|
|
1112
|
+
return {
|
|
1113
|
+
metadata: internalDoc.metadataStatus,
|
|
1114
|
+
data: internalDoc.dataStatus,
|
|
1115
|
+
metadataError: internalDoc.metadataError,
|
|
1116
|
+
dataError: internalDoc.dataError
|
|
1117
|
+
};
|
|
1118
|
+
};
|
|
1119
|
+
onStatusChange = (docRef, callback) => {
|
|
1120
|
+
const {
|
|
1121
|
+
internalDoc
|
|
1122
|
+
} = this.getCreateInternalDoc(docRef);
|
|
1123
|
+
internalDoc.statusSubscribers.add(callback);
|
|
1124
|
+
const status = {
|
|
1125
|
+
metadata: internalDoc.metadataStatus,
|
|
1126
|
+
data: internalDoc.dataStatus,
|
|
1127
|
+
metadataError: internalDoc.metadataError,
|
|
1128
|
+
dataError: internalDoc.dataError
|
|
1129
|
+
};
|
|
1130
|
+
callback(docRef, status);
|
|
1131
|
+
return () => {
|
|
1132
|
+
const currentDoc = this.documents.get(docRef.id);
|
|
1133
|
+
if (currentDoc) {
|
|
1134
|
+
currentDoc.statusSubscribers.delete(callback);
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
};
|
|
1138
|
+
waitForMetadataLoad = async (docRef) => {
|
|
1139
|
+
const {
|
|
1140
|
+
internalDoc
|
|
1141
|
+
} = this.getCreateInternalDoc(docRef);
|
|
1142
|
+
if (internalDoc.metadataStatus.load === DocumentLoadStatus.LOADED) {
|
|
1143
|
+
return Promise.resolve();
|
|
1144
|
+
}
|
|
1145
|
+
if (internalDoc.metadataStatus.load === DocumentLoadStatus.ERROR) {
|
|
1146
|
+
return Promise.reject(new Error("Metadata load error", {
|
|
1147
|
+
cause: internalDoc.metadataError
|
|
1148
|
+
}));
|
|
1149
|
+
}
|
|
1150
|
+
return new Promise((resolve, reject) => {
|
|
1151
|
+
const unsubscribe = this.onStatusChange(docRef, (_, status) => {
|
|
1152
|
+
if (status.metadata.load === DocumentLoadStatus.LOADED) {
|
|
1153
|
+
unsubscribe();
|
|
1154
|
+
resolve();
|
|
1155
|
+
} else if (status.metadata.load === DocumentLoadStatus.ERROR) {
|
|
1156
|
+
unsubscribe();
|
|
1157
|
+
reject(new Error("Metadata load error", {
|
|
1158
|
+
cause: status.metadataError
|
|
1159
|
+
}));
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
};
|
|
1164
|
+
waitForDataLoad = async (docRef) => {
|
|
1165
|
+
const {
|
|
1166
|
+
internalDoc
|
|
1167
|
+
} = this.getCreateInternalDoc(docRef);
|
|
1168
|
+
if (internalDoc.dataStatus.load === DocumentLoadStatus.LOADED) {
|
|
1169
|
+
return Promise.resolve();
|
|
1170
|
+
}
|
|
1171
|
+
if (internalDoc.dataStatus.load === DocumentLoadStatus.ERROR) {
|
|
1172
|
+
return Promise.reject(new Error("Data load error", {
|
|
1173
|
+
cause: internalDoc.dataError
|
|
1174
|
+
}));
|
|
1175
|
+
}
|
|
1176
|
+
return new Promise((resolve, reject) => {
|
|
1177
|
+
const unsubscribe = this.onStatusChange(docRef, (_, status) => {
|
|
1178
|
+
if (status.data.load === DocumentLoadStatus.LOADED) {
|
|
1179
|
+
unsubscribe();
|
|
1180
|
+
resolve();
|
|
1181
|
+
} else if (status.data.load === DocumentLoadStatus.ERROR) {
|
|
1182
|
+
unsubscribe();
|
|
1183
|
+
reject(new Error("Data load error", {
|
|
1184
|
+
cause: status.dataError
|
|
1185
|
+
}));
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
});
|
|
1189
|
+
};
|
|
1190
|
+
// FIXME: don't expose in production builds
|
|
1191
|
+
/**
|
|
1192
|
+
* @internal
|
|
1193
|
+
*/
|
|
1194
|
+
getYDocForTesting(docId) {
|
|
1195
|
+
const internalDoc = this.documents.get(docId);
|
|
1196
|
+
return internalDoc ? internalDoc.yDoc : null;
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
function isCollectionSubscriptionsEmpty(subs) {
|
|
1200
|
+
return !subs.added?.size && !subs.changed?.size && !subs.deleted?.size;
|
|
1201
|
+
}
|
|
1202
|
+
function isRecordSubscriptionsEmpty(subs) {
|
|
1203
|
+
return !subs.changed?.size && !subs.deleted?.size;
|
|
1204
|
+
}
|
|
1205
|
+
function createInMemoryDocumentServiceConfig({
|
|
1206
|
+
autoCreateDocuments = true
|
|
1207
|
+
} = {}) {
|
|
1208
|
+
const config = {
|
|
1209
|
+
autoCreateDocuments
|
|
1210
|
+
};
|
|
1211
|
+
return createDocumentServiceConfig(internalCreateInMemoryDocumentService, config);
|
|
1212
|
+
}
|
|
1213
|
+
function internalCreateInMemoryDocumentService(app, options) {
|
|
1214
|
+
return new InMemoryDocumentService(app, options);
|
|
1215
|
+
}
|
|
1216
|
+
var InMemoryDocumentService = class extends BaseYjsDocumentService {
|
|
1217
|
+
constructor(app, config) {
|
|
1218
|
+
super(app, app.config.logger.child({}, {
|
|
1219
|
+
level: "debug",
|
|
1220
|
+
msgPrefix: "InMemoryDocumentService"
|
|
1221
|
+
}));
|
|
1222
|
+
this.config = config;
|
|
1223
|
+
}
|
|
1224
|
+
createInternalDoc(ref, metadata, yDoc) {
|
|
1225
|
+
return this.createBaseInternalDoc(ref, metadata, yDoc);
|
|
1226
|
+
}
|
|
1227
|
+
get hasMetadataSubscriptions() {
|
|
1228
|
+
return Array.from(this.documents.values()).some((doc) => this.hasSubscriptions(doc) && doc.metadataSubscribers.size > 0);
|
|
1229
|
+
}
|
|
1230
|
+
get hasStateSubscriptions() {
|
|
1231
|
+
return Array.from(this.documents.values()).some((doc) => this.hasSubscriptions(doc) && doc.docStateSubscribers.size > 0);
|
|
1232
|
+
}
|
|
1233
|
+
createDocument = (metadata, schema) => {
|
|
1234
|
+
const id = generateDocumentId();
|
|
1235
|
+
const docRef = createDocRef(this.app, id, schema);
|
|
1236
|
+
const yDoc = this.initializeYDoc(schema);
|
|
1237
|
+
this.getCreateInternalDoc(docRef, metadata, yDoc);
|
|
1238
|
+
return Promise.resolve(docRef);
|
|
1239
|
+
};
|
|
1240
|
+
// Lifecycle method implementations
|
|
1241
|
+
onMetadataSubscriptionOpened(internalDoc, docRef) {
|
|
1242
|
+
this.updateMetadataStatus(internalDoc, docRef, {
|
|
1243
|
+
load: DocumentLoadStatus.LOADING
|
|
1244
|
+
});
|
|
1245
|
+
if (this.config.autoCreateDocuments === false && internalDoc.metadata == null) {
|
|
1246
|
+
this.updateMetadataStatus(internalDoc, docRef, {
|
|
1247
|
+
error: new Error("Document not found and autoCreateDocuments is disabled"),
|
|
1248
|
+
load: DocumentLoadStatus.ERROR
|
|
1249
|
+
});
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
this.updateMetadataStatus(internalDoc, docRef, {
|
|
1253
|
+
load: DocumentLoadStatus.LOADED
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
onDataSubscriptionOpened(internalDoc, docRef) {
|
|
1257
|
+
this.updateDataStatus(internalDoc, docRef, {
|
|
1258
|
+
load: DocumentLoadStatus.LOADING
|
|
1259
|
+
});
|
|
1260
|
+
if (this.config.autoCreateDocuments === false && internalDoc.metadata == null) {
|
|
1261
|
+
this.updateDataStatus(internalDoc, docRef, {
|
|
1262
|
+
error: new Error("Document not found and autoCreateDocuments is disabled"),
|
|
1263
|
+
load: DocumentLoadStatus.ERROR
|
|
1264
|
+
});
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
this.updateDataStatus(internalDoc, docRef, {
|
|
1268
|
+
load: DocumentLoadStatus.LOADED
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
onMetadataSubscriptionClosed(_internalDoc, _docRef) {
|
|
1272
|
+
}
|
|
1273
|
+
onDataSubscriptionClosed(_internalDoc, _docRef) {
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
function generateDocumentId() {
|
|
1277
|
+
return pack_core.generateId();
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
exports.BaseYjsDocumentService = BaseYjsDocumentService;
|
|
1281
|
+
exports.DocumentLiveStatus = DocumentLiveStatus;
|
|
1282
|
+
exports.DocumentLoadStatus = DocumentLoadStatus;
|
|
1283
|
+
exports.STATE_MODULE_ACCESSOR = STATE_MODULE_ACCESSOR;
|
|
1284
|
+
exports.createDocRef = createDocRef;
|
|
1285
|
+
exports.createDocumentServiceConfig = createDocumentServiceConfig;
|
|
1286
|
+
exports.createInMemoryDocumentServiceConfig = createInMemoryDocumentServiceConfig;
|
|
1287
|
+
exports.createRecordCollectionRef = createRecordCollectionRef;
|
|
1288
|
+
exports.createRecordRef = createRecordRef;
|
|
1289
|
+
exports.getDocumentService = getDocumentService;
|
|
1290
|
+
exports.getStateModule = getStateModule;
|
|
1291
|
+
exports.invalidDocRef = invalidDocRef;
|
|
1292
|
+
exports.invalidRecordCollectionRef = invalidRecordCollectionRef;
|
|
1293
|
+
exports.invalidRecordRef = invalidRecordRef;
|
|
1294
|
+
exports.isValidDocRef = isValidDocRef;
|
|
1295
|
+
exports.isValidRecordCollectionRef = isValidRecordCollectionRef;
|
|
1296
|
+
exports.isValidRecordRef = isValidRecordRef;
|
|
1297
|
+
//# sourceMappingURL=index.cjs.map
|
|
1298
|
+
//# sourceMappingURL=index.cjs.map
|