dexie-cloud-addon 4.1.0-beta.42 → 4.1.0-beta.43

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.
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.1.0-beta.42, Tue Feb 04 2025
11
+ * Version 4.1.0-beta.43, Fri Feb 07 2025
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -4994,7 +4994,7 @@
4994
4994
  .toArray();
4995
4995
  }
4996
4996
 
4997
- function $Y$1(db) {
4997
+ function $Y(db) {
4998
4998
  const $Y = db.dx._options.Y;
4999
4999
  if (!$Y)
5000
5000
  throw new Error('Y library not supplied to Dexie constructor');
@@ -5024,7 +5024,7 @@
5024
5024
  for (const table of tablesToSync) {
5025
5025
  if (table.schema.yProps) {
5026
5026
  for (const yProp of table.schema.yProps) {
5027
- const Y = $Y$1(db); // This is how we retrieve the user-provided Y library
5027
+ const Y = $Y(db); // This is how we retrieve the user-provided Y library
5028
5028
  const yTable = db.table(yProp.updatesTable); // the updates-table for this combo of table+propName
5029
5029
  const syncState = (yield yTable.get(DEXIE_CLOUD_SYNCER_ID));
5030
5030
  // unsentFrom = the `i` value of updates that aren't yet sent to server (or at least not acked by the server yet)
@@ -8139,7 +8139,7 @@
8139
8139
  if (provider.destroyed || currentFlowId !== myFlow || !connected)
8140
8140
  return;
8141
8141
  if (serverUpdatesSinceLastSync.length > 0) {
8142
- const Y = $Y$1(db); // Get the Yjs library from Dexie constructor options
8142
+ const Y = $Y(db); // Get the Yjs library from Dexie constructor options
8143
8143
  const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
8144
8144
  const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
8145
8145
  docOpenMsg.sv = stateVector;
@@ -8159,8 +8159,68 @@
8159
8159
  }
8160
8160
 
8161
8161
  const ydocTriggers = {};
8162
- const docIsAlreadyHooked = new WeakSet();
8163
8162
  const middlewares = new WeakMap();
8163
+ const txRunner = TriggerRunner("tx");
8164
+ const unloadRunner = TriggerRunner("unload");
8165
+ function TriggerRunner(name) {
8166
+ let triggerExecPromise = null;
8167
+ let triggerScheduled = false;
8168
+ let registry = new Map();
8169
+ function execute(registryCopy) {
8170
+ return __awaiter(this, void 0, void 0, function* () {
8171
+ for (const { db, parentId, triggers, parentTable, prop, } of registryCopy.values()) {
8172
+ const yDoc = Dexie.DexieYProvider.getOrCreateDocument(db, parentTable, prop, parentId);
8173
+ try {
8174
+ Dexie.DexieYProvider.load(yDoc); // If doc is open, this would just be a ++refount
8175
+ yield yDoc.whenLoaded; // If doc is loaded, this would resolve immediately
8176
+ for (const trigger of triggers) {
8177
+ yield trigger(yDoc, parentId);
8178
+ }
8179
+ }
8180
+ catch (error) {
8181
+ console.error(`Error in YDocTrigger ${error}`);
8182
+ }
8183
+ finally {
8184
+ Dexie.DexieYProvider.release(yDoc);
8185
+ }
8186
+ }
8187
+ });
8188
+ }
8189
+ return {
8190
+ name,
8191
+ run() {
8192
+ return __awaiter(this, void 0, void 0, function* () {
8193
+ if (!triggerScheduled && registry.size > 0) {
8194
+ triggerScheduled = true;
8195
+ if (triggerExecPromise)
8196
+ yield triggerExecPromise.catch(() => { });
8197
+ setTimeout(() => {
8198
+ // setTimeout() is to escape from Promise.PSD zones and never run within liveQueries or transaction scopes
8199
+ triggerScheduled = false;
8200
+ const registryCopy = registry;
8201
+ registry = new Map();
8202
+ triggerExecPromise = execute(registryCopy).finally(() => (triggerExecPromise = null));
8203
+ }, 0);
8204
+ }
8205
+ });
8206
+ },
8207
+ enqueue(db, parentTable, parentId, prop, trigger) {
8208
+ const key = `${db.name}:${parentTable}:${parentId}:${prop}`;
8209
+ let entry = registry.get(key);
8210
+ if (!entry) {
8211
+ entry = {
8212
+ db,
8213
+ parentTable,
8214
+ parentId,
8215
+ prop,
8216
+ triggers: new Set(),
8217
+ };
8218
+ registry.set(key, entry);
8219
+ }
8220
+ entry.triggers.add(trigger);
8221
+ },
8222
+ };
8223
+ }
8164
8224
  const createMiddleware = (db) => ({
8165
8225
  stack: 'dbcore',
8166
8226
  level: 10,
@@ -8168,15 +8228,20 @@
8168
8228
  create: (down) => {
8169
8229
  return Object.assign(Object.assign({}, down), { transaction: (stores, mode, options) => {
8170
8230
  const idbtrans = down.transaction(stores, mode, options);
8231
+ if (mode === 'readonly')
8232
+ return idbtrans;
8233
+ if (!stores.some((store) => ydocTriggers[store]))
8234
+ return idbtrans;
8171
8235
  idbtrans.addEventListener('complete', onTransactionCommitted);
8172
8236
  return idbtrans;
8173
- }, table: (tblName) => {
8174
- const coreTable = down.table(tblName);
8175
- const triggerSpec = ydocTriggers[tblName];
8237
+ }, table: (updatesTable) => {
8238
+ const coreTable = down.table(updatesTable);
8239
+ const triggerSpec = ydocTriggers[updatesTable];
8176
8240
  if (!triggerSpec)
8177
8241
  return coreTable;
8178
8242
  const { trigger, parentTable, prop } = triggerSpec;
8179
8243
  return Object.assign(Object.assign({}, coreTable), { mutate(req) {
8244
+ var _a;
8180
8245
  switch (req.type) {
8181
8246
  case 'add': {
8182
8247
  for (const yUpdateRow of req.values) {
@@ -8184,15 +8249,10 @@
8184
8249
  continue; // A syncer or garbage collection state does not point to a key
8185
8250
  const primaryKey = yUpdateRow.k;
8186
8251
  const doc = Dexie.DexieYProvider.getDocCache(db).find(parentTable, primaryKey, prop);
8187
- if (doc) {
8188
- if (!docIsAlreadyHooked.has(doc)) {
8189
- hookToDoc(doc, primaryKey, trigger);
8190
- docIsAlreadyHooked.add(doc);
8191
- }
8192
- }
8193
- else {
8194
- enqueueTrigger(db, tblName, primaryKey, trigger);
8195
- }
8252
+ const runner = doc && ((_a = Dexie.DexieYProvider.for(doc)) === null || _a === void 0 ? void 0 : _a.refCount)
8253
+ ? unloadRunner // Document is open. Wait with trigger until it's closed.
8254
+ : txRunner; // Document is closed. Run trigger immediately after transaction commits.
8255
+ runner.enqueue(db, parentTable, primaryKey, prop, trigger);
8196
8256
  }
8197
8257
  break;
8198
8258
  }
@@ -8215,7 +8275,7 @@
8215
8275
  keySet.addKey(k);
8216
8276
  }
8217
8277
  for (const interval of keySet) {
8218
- enqueueTrigger(db, tblName, interval.from, trigger);
8278
+ txRunner.enqueue(db, parentTable, interval.from, prop, trigger);
8219
8279
  }
8220
8280
  });
8221
8281
  }
@@ -8226,74 +8286,11 @@
8226
8286
  } });
8227
8287
  },
8228
8288
  });
8229
- let triggerExecPromise = null;
8230
- let triggerScheduled = false;
8231
- let scheduledTriggers = [];
8232
- function $Y(db) {
8233
- const $Y = db._options.Y;
8234
- if (!$Y)
8235
- throw new Error('Y library not supplied to Dexie constructor');
8236
- return $Y;
8237
- }
8238
- function executeTriggers(triggersToRun) {
8239
- return __awaiter(this, void 0, void 0, function* () {
8240
- for (const { db, parentId, trigger, updatesTable } of triggersToRun) {
8241
- // Load entire document into an Y.Doc instance:
8242
- const updates = yield db
8243
- .table(updatesTable)
8244
- .where({ k: parentId })
8245
- .toArray();
8246
- const Y = $Y(db);
8247
- const yDoc = new Y.Doc();
8248
- for (const update of updates) {
8249
- Y.applyUpdateV2(yDoc, update.u);
8250
- }
8251
- try {
8252
- yield trigger(yDoc, parentId);
8253
- }
8254
- catch (error) {
8255
- console.error(`Error in YDocTrigger ${error}`);
8256
- }
8257
- }
8258
- });
8259
- }
8260
- function enqueueTrigger(db, updatesTable, parentId, trigger) {
8261
- scheduledTriggers.push({
8262
- db,
8263
- updatesTable,
8264
- parentId,
8265
- trigger,
8266
- });
8267
- }
8268
8289
  function onTransactionCommitted() {
8269
- return __awaiter(this, void 0, void 0, function* () {
8270
- if (!triggerScheduled && scheduledTriggers.length > 0) {
8271
- triggerScheduled = true;
8272
- if (triggerExecPromise)
8273
- yield triggerExecPromise.catch(() => { });
8274
- setTimeout(() => {
8275
- // setTimeout() is to escape from Promise.PSD zones and never run within liveQueries or transaction scopes
8276
- triggerScheduled = false;
8277
- const triggersToRun = scheduledTriggers;
8278
- scheduledTriggers = [];
8279
- triggerExecPromise = executeTriggers(triggersToRun).finally(() => (triggerExecPromise = null));
8280
- }, 0);
8281
- }
8282
- });
8290
+ txRunner.run();
8283
8291
  }
8284
- function hookToDoc(doc, parentId, trigger) {
8285
- // From now on, keep listening to doc updates and execute the trigger when it happens there instead
8286
- doc.on('updateV2', (update, origin) => {
8287
- //Dexie.ignoreTransaction(()=>{
8288
- trigger(doc, parentId);
8289
- //});
8290
- });
8291
- /*
8292
- NOT NEEDED because DexieYProvider's docCache will also listen to destroy and remove it from its cache:
8293
- doc.on('destroy', ()=>{
8294
- docIsAlreadyHooked.delete(doc);
8295
- })
8296
- */
8292
+ function beforeProviderUnload() {
8293
+ unloadRunner.run();
8297
8294
  }
8298
8295
  function defineYDocTrigger(table, prop, trigger) {
8299
8296
  var _a, _b;
@@ -8312,6 +8309,9 @@
8312
8309
  middlewares.set(db, mw);
8313
8310
  }
8314
8311
  db.use(mw);
8312
+ {
8313
+ Dexie.DexieYProvider.on('beforeunload', beforeProviderUnload);
8314
+ }
8315
8315
  }
8316
8316
 
8317
8317
  const DEFAULT_OPTIONS = {
@@ -8354,7 +8354,7 @@
8354
8354
  const syncComplete = new rxjs.Subject();
8355
8355
  dexie.cloud = {
8356
8356
  // @ts-ignore
8357
- version: "4.1.0-beta.42",
8357
+ version: "4.1.0-beta.43",
8358
8358
  options: Object.assign({}, DEFAULT_OPTIONS),
8359
8359
  schema: null,
8360
8360
  get currentUserId() {
@@ -8672,7 +8672,7 @@
8672
8672
  }
8673
8673
  }
8674
8674
  // @ts-ignore
8675
- dexieCloud.version = "4.1.0-beta.42";
8675
+ dexieCloud.version = "4.1.0-beta.43";
8676
8676
  Dexie.Cloud = dexieCloud;
8677
8677
 
8678
8678
  exports.default = dexieCloud;