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