@abraca/dabra 1.0.10 → 1.0.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.
@@ -1733,14 +1733,17 @@ var AbracadabraWS = class extends EventEmitter {
1733
1733
  this.receivedOnOpenPayload = event;
1734
1734
  }
1735
1735
  attach(provider) {
1736
+ const existing = this.configuration.providerMap.get(provider.configuration.name);
1737
+ if (existing && existing !== provider) console.warn(`[AbracadabraWS] attach: overwriting provider for "${provider.configuration.name}". This may indicate a duplicate loadChild for the same document.`);
1736
1738
  this.configuration.providerMap.set(provider.configuration.name, provider);
1737
1739
  if (this.status === WebSocketStatus.Disconnected && this.shouldConnect) this.connect();
1738
1740
  if (this.receivedOnOpenPayload && this.status === WebSocketStatus.Connected) provider.onOpen(this.receivedOnOpenPayload);
1739
1741
  }
1740
1742
  detach(provider) {
1741
- if (this.configuration.providerMap.has(provider.configuration.name)) {
1742
- provider.send(CloseMessage, { documentName: provider.configuration.name });
1743
- this.configuration.providerMap.delete(provider.configuration.name);
1743
+ const name = provider.configuration.name;
1744
+ if (this.configuration.providerMap.get(name) === provider) {
1745
+ provider.send(CloseMessage, { documentName: name });
1746
+ this.configuration.providerMap.delete(name);
1744
1747
  }
1745
1748
  }
1746
1749
  setConfiguration(configuration = {}) {
@@ -3260,6 +3263,20 @@ var AbracadabraClient = class {
3260
3263
  if (this.cache) await this.cache.setPermissions(docId, res.permissions).catch(() => null);
3261
3264
  return res.permissions;
3262
3265
  }
3266
+ /** List effective permissions including inherited ones from ancestor documents. */
3267
+ async listEffectivePermissions(docId) {
3268
+ try {
3269
+ return await this.request("GET", `/docs/${encodeURIComponent(docId)}/effective-permissions`);
3270
+ } catch {
3271
+ return {
3272
+ permissions: (await this.listPermissions(docId)).map((p) => ({
3273
+ ...p,
3274
+ source: "direct"
3275
+ })),
3276
+ default_role: "viewer"
3277
+ };
3278
+ }
3279
+ }
3263
3280
  /** Grant or change a user's role on a document (requires Owner). */
3264
3281
  async setPermission(docId, opts) {
3265
3282
  await this.request("POST", `/docs/${encodeURIComponent(docId)}/permissions`, { body: opts });
@@ -7478,15 +7495,19 @@ function txPromise(store, request) {
7478
7495
  request.onerror = () => reject(request.error);
7479
7496
  });
7480
7497
  }
7481
- var FileBlobStore = class extends EventEmitter {
7498
+ var FileBlobStore = class FileBlobStore extends EventEmitter {
7499
+ static {
7500
+ this.NOT_FOUND_TTL = 300 * 1e3;
7501
+ }
7482
7502
  constructor(serverOrigin, client) {
7483
7503
  super();
7484
7504
  this.dbPromise = null;
7485
7505
  this.db = null;
7486
7506
  this.objectUrls = /* @__PURE__ */ new Map();
7507
+ this._notFound = /* @__PURE__ */ new Map();
7487
7508
  this._flushing = false;
7488
7509
  this.origin = serverOrigin;
7489
- this.client = client;
7510
+ this.client = client ?? null;
7490
7511
  this._onlineHandler = () => {
7491
7512
  this.flushQueue().catch(() => null);
7492
7513
  };
@@ -7524,10 +7545,14 @@ var FileBlobStore = class extends EventEmitter {
7524
7545
  return url;
7525
7546
  }
7526
7547
  }
7548
+ if (!this.client) return null;
7549
+ const nfTime = this._notFound.get(key);
7550
+ if (nfTime && Date.now() - nfTime < FileBlobStore.NOT_FOUND_TTL) return null;
7527
7551
  let blob;
7528
7552
  try {
7529
7553
  blob = await this.client.getUpload(docId, uploadId);
7530
- } catch {
7554
+ } catch (err) {
7555
+ if (err?.status === 404) this._notFound.set(key, Date.now());
7531
7556
  return null;
7532
7557
  }
7533
7558
  if (db) {
@@ -7551,6 +7576,7 @@ var FileBlobStore = class extends EventEmitter {
7551
7576
  async putBlob(docId, uploadId, blob, filename) {
7552
7577
  if (typeof window === "undefined") return URL.createObjectURL(blob);
7553
7578
  const key = this.blobKey(docId, uploadId);
7579
+ this._notFound.delete(key);
7554
7580
  const existing = this.objectUrls.get(key);
7555
7581
  if (existing) return existing;
7556
7582
  const db = await this.getDb();
@@ -7619,7 +7645,7 @@ var FileBlobStore = class extends EventEmitter {
7619
7645
  * Entries that fail are marked with status "error" and left in the queue.
7620
7646
  */
7621
7647
  async flushQueue() {
7622
- if (this._flushing) return;
7648
+ if (this._flushing || !this.client) return;
7623
7649
  this._flushing = true;
7624
7650
  try {
7625
7651
  const pending = (await this.getQueue()).filter((e) => e.status === "pending");