@abraca/dabra 2.19.0 → 2.21.0

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.
@@ -2801,8 +2801,8 @@ var AbracadabraBaseProvider = class extends EventEmitter {
2801
2801
  this.configuration.websocketProvider.on("destroy", this.configuration.onDestroy);
2802
2802
  this.configuration.websocketProvider.on("destroy", this.forwardDestroy);
2803
2803
  this.configuration.websocketProvider.on("rateLimited", this.forwardRateLimited);
2804
- this.configuration.websocketProvider.attach(this);
2805
2804
  this._isAttached = true;
2805
+ this.configuration.websocketProvider.attach(this);
2806
2806
  }
2807
2807
  permissionDeniedHandler(reason) {
2808
2808
  this.emit("authenticationFailed", { reason });
@@ -2854,9 +2854,12 @@ function txPromise$2(store, request) {
2854
2854
  var OfflineStore = class {
2855
2855
  /**
2856
2856
  * @param docId The document UUID.
2857
- * @param serverOrigin Hostname of the server (e.g. "abra.cou.sh").
2858
- * When provided the IndexedDB database is namespaced
2859
- * per-server, preventing cross-server data contamination.
2857
+ * @param serverOrigin Host of the server, including a non-default port
2858
+ * (e.g. "abra.cou.sh", "localhost:3001"). When provided
2859
+ * the IndexedDB database is namespaced per-server,
2860
+ * preventing cross-server data contamination — the port
2861
+ * matters because two same-host servers sharing the
2862
+ * default root_doc_id would otherwise collide.
2860
2863
  */
2861
2864
  constructor(docId, serverOrigin) {
2862
2865
  this.db = null;
@@ -3063,6 +3066,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3063
3066
  }
3064
3067
  super(resolved);
3065
3068
  this.effectiveRole = null;
3069
+ this._writeDropWarned = false;
3066
3070
  this.childProviders = /* @__PURE__ */ new Map();
3067
3071
  this.pendingLoads = /* @__PURE__ */ new Map();
3068
3072
  this.childAccessTimes = /* @__PURE__ */ new Map();
@@ -3093,7 +3097,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3093
3097
  static deriveServerOrigin(config, client) {
3094
3098
  try {
3095
3099
  const url = config.url ?? config.websocketProvider?.url ?? client?.wsUrl;
3096
- if (url) return new URL(url).hostname;
3100
+ if (url) return new URL(url).host;
3097
3101
  } catch {}
3098
3102
  }
3099
3103
  /**
@@ -3119,7 +3123,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3119
3123
  }
3120
3124
  authenticatedHandler(scope) {
3121
3125
  super.authenticatedHandler(scope);
3122
- this.effectiveRole = {
3126
+ const roleMap = {
3123
3127
  service: "service",
3124
3128
  admin: "admin",
3125
3129
  owner: "owner",
@@ -3128,8 +3132,16 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3128
3132
  observer: "observer",
3129
3133
  "read-write": "editor",
3130
3134
  readonly: "viewer"
3131
- }[scope] ?? "observer";
3135
+ };
3136
+ const couldWrite = this.canWrite;
3137
+ this.effectiveRole = roleMap[scope] ?? "observer";
3132
3138
  this.offlineStore?.savePermissionSnapshot(this.effectiveRole);
3139
+ if (this.canWrite) this._writeDropWarned = false;
3140
+ this.emit("roleChanged", {
3141
+ role: this.effectiveRole,
3142
+ canWrite: this.canWrite
3143
+ });
3144
+ if (!couldWrite && this.canWrite && this.isSynced) this.flushPendingUpdates().catch(() => null);
3133
3145
  }
3134
3146
  /**
3135
3147
  * Override sendToken to send a pubkey-only identity declaration instead of a
@@ -3180,7 +3192,13 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3180
3192
  async restorePermissionSnapshot() {
3181
3193
  if (!this.offlineStore) return;
3182
3194
  const role = await this.offlineStore.getPermissionSnapshot();
3183
- if (role && !this.effectiveRole) this.effectiveRole = role;
3195
+ if (role && !this.effectiveRole) {
3196
+ this.effectiveRole = role;
3197
+ this.emit("roleChanged", {
3198
+ role: this.effectiveRole,
3199
+ canWrite: this.canWrite
3200
+ });
3201
+ }
3184
3202
  }
3185
3203
  get canWrite() {
3186
3204
  return this.effectiveRole != null && this.effectiveRole !== "viewer" && this.effectiveRole !== "observer";
@@ -3387,7 +3405,19 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3387
3405
  if (origin === this) return;
3388
3406
  if (this.offlineStore !== null && origin === this.offlineStore) return;
3389
3407
  this.offlineStore?.persistUpdate(update).catch(() => null);
3390
- if (!this.canWrite) return;
3408
+ if (!this.canWrite) {
3409
+ if (!this._writeDropWarned) {
3410
+ this._writeDropWarned = true;
3411
+ try {
3412
+ console.warn(`[abra:write-drop] dropping wire-send for doc "${this.configuration?.name}" — effectiveRole=${this.effectiveRole ?? "null"} (canWrite=false). Edits are persisted to IndexedDB only; the server will NOT receive them until this doc regains write access.`);
3413
+ } catch {}
3414
+ }
3415
+ this.emit("writeDropped", {
3416
+ name: this.configuration?.name,
3417
+ role: this.effectiveRole ?? null
3418
+ });
3419
+ return;
3420
+ }
3391
3421
  super.documentUpdateHandler(update, origin);
3392
3422
  }
3393
3423
  /**
@@ -16119,7 +16149,7 @@ var BackgroundSyncManager = class extends EventEmitter {
16119
16149
  };
16120
16150
  let serverOrigin = "default";
16121
16151
  try {
16122
- serverOrigin = new URL(client.baseUrl ?? "").hostname;
16152
+ serverOrigin = new URL(client.baseUrl ?? "").host;
16123
16153
  } catch {}
16124
16154
  this.persistence = new BackgroundSyncPersistence(serverOrigin);
16125
16155
  this.semaphore = new Semaphore(this.opts.concurrency);
@@ -16266,7 +16296,7 @@ var BackgroundSyncManager = class extends EventEmitter {
16266
16296
  for (const docId of treeMap.keys()) docIds.add(docId);
16267
16297
  let serverOrigin;
16268
16298
  try {
16269
- serverOrigin = new URL(this.client.baseUrl ?? "").hostname;
16299
+ serverOrigin = new URL(this.client.baseUrl ?? "").host;
16270
16300
  } catch {}
16271
16301
  const clearPromises = Array.from(docIds).map(async (docId) => {
16272
16302
  try {