@abraca/dabra 2.3.0 → 2.5.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.
@@ -3251,22 +3251,23 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3251
3251
  * errors across async await boundaries.
3252
3252
  */
3253
3253
  async flushPendingUpdates() {
3254
- if (!this.canWrite) return;
3255
3254
  const store = this.offlineStore;
3256
3255
  if (!store) return;
3257
- const updates = await store.getPendingUpdates();
3258
- if (updates.length > 0) {
3259
- for (const update of updates) this.send(UpdateMessage, {
3260
- update,
3261
- documentName: this.configuration.name
3256
+ if (this.canWrite) {
3257
+ const updates = await store.getPendingUpdates();
3258
+ if (updates.length > 0) {
3259
+ for (const update of updates) this.send(UpdateMessage, {
3260
+ update,
3261
+ documentName: this.configuration.name
3262
+ });
3263
+ await store.clearPendingUpdates();
3264
+ }
3265
+ const pendingSubdocs = await store.getPendingSubdocs();
3266
+ for (const { childId } of pendingSubdocs) this.send(SubdocMessage, {
3267
+ documentName: this.configuration.name,
3268
+ childDocumentName: childId
3262
3269
  });
3263
- await store.clearPendingUpdates();
3264
3270
  }
3265
- const pendingSubdocs = await store.getPendingSubdocs();
3266
- for (const { childId } of pendingSubdocs) this.send(SubdocMessage, {
3267
- documentName: this.configuration.name,
3268
- childDocumentName: childId
3269
- });
3270
3271
  const snapshot = Y.encodeStateAsUpdate(this.document);
3271
3272
  await store.saveDocSnapshot(snapshot).catch(() => null);
3272
3273
  }
@@ -10336,6 +10337,7 @@ function fromBase64$3(b64) {
10336
10337
  }
10337
10338
  var AbracadabraClient = class {
10338
10339
  constructor(config) {
10340
+ this.rootListInflight = /* @__PURE__ */ new Map();
10339
10341
  this.baseUrl = config.url.replace(/\/+$/, "");
10340
10342
  this.persistAuth = config.persistAuth ?? typeof localStorage !== "undefined";
10341
10343
  this.storageKey = config.storageKey ?? "abracadabra:auth";
@@ -10739,11 +10741,21 @@ var AbracadabraClient = class {
10739
10741
  * recursive tree walks; callers that need it can read `meta.id` from
10740
10742
  * the returned metas.
10741
10743
  */
10742
- async listChildren(parentId) {
10743
- const path = parentId ? `/docs/${encodeURIComponent(parentId)}/children` : "/docs?root=true";
10744
- const res = await this.request("GET", path);
10745
- if (this.cache && parentId && res.children) await this.cache.setChildren(parentId, res.children).catch(() => null);
10746
- return res.documents;
10744
+ async listChildren(parentId, opts) {
10745
+ const kind = opts?.kind;
10746
+ if (parentId) {
10747
+ const res = await this.request("GET", `/docs/${encodeURIComponent(parentId)}/children`);
10748
+ if (this.cache && res.children) await this.cache.setChildren(parentId, res.children).catch(() => null);
10749
+ return kind ? res.documents.filter((d) => d.kind === kind) : res.documents;
10750
+ }
10751
+ const key = kind ?? "";
10752
+ const existing = this.rootListInflight.get(key);
10753
+ const docs = existing ? await existing : await (() => {
10754
+ const p = this.request("GET", kind ? `/docs?root=true&kind=${encodeURIComponent(kind)}` : "/docs?root=true").then((res) => res.documents).finally(() => this.rootListInflight.delete(key));
10755
+ this.rootListInflight.set(key, p);
10756
+ return p;
10757
+ })();
10758
+ return kind ? docs.filter((d) => d.kind === kind) : docs;
10747
10759
  }
10748
10760
  /**
10749
10761
  * Create a child document under a parent (requires write permission).
@@ -10872,7 +10884,7 @@ var AbracadabraClient = class {
10872
10884
  * spaces resolving to any role; anonymous users see public ones.
10873
10885
  */
10874
10886
  async listSpaces() {
10875
- return (await this.listChildren()).filter((d) => d.kind === Kind.Space);
10887
+ return this.listChildren(void 0, { kind: Kind.Space });
10876
10888
  }
10877
10889
  /**
10878
10890
  * Create a new top-level Space. Equivalent to a `POST /docs` with
@@ -10990,6 +11002,46 @@ var AbracadabraClient = class {
10990
11002
  return this.request("POST", "/admin/storage/repair");
10991
11003
  }
10992
11004
  /**
11005
+ * Admin one-shot: populate the `snapshot_files` table for snapshots
11006
+ * created before that migration ran, so `SnapshotMeta.file_count` and
11007
+ * upload-ref tracking become accurate. Idempotent (insert-or-ignore).
11008
+ * Requires elevated role.
11009
+ */
11010
+ async adminSnapshotsBackfillRefs() {
11011
+ return this.request("POST", "/admin/snapshots/backfill-refs");
11012
+ }
11013
+ /**
11014
+ * Admin one-shot: migrate pre-dedup inline snapshot data into the
11015
+ * content-addressed `snapshot_blobs` store. Idempotent (only migrates
11016
+ * rows with `data_hash IS NULL`). Requires elevated role.
11017
+ */
11018
+ async adminSnapshotsBackfillBlobs() {
11019
+ return this.request("POST", "/admin/snapshots/backfill-blobs");
11020
+ }
11021
+ /**
11022
+ * Admin: server-wide upload listing, joined with the owning document
11023
+ * (label is best-effort — labels live in the CRDT, not the SQL row)
11024
+ * and the content-addressed blob (`ref_count` exposes dedup).
11025
+ * Server-side paginated + filtered. Requires elevated role.
11026
+ */
11027
+ async adminListUploads(opts = {}) {
11028
+ const p = new URLSearchParams();
11029
+ if (opts.q) p.set("q", opts.q);
11030
+ if (opts.docId) p.set("doc_id", opts.docId);
11031
+ if (opts.limit != null) p.set("limit", String(opts.limit));
11032
+ if (opts.offset != null) p.set("offset", String(opts.offset));
11033
+ const qs = p.toString();
11034
+ return this.request("GET", `/admin/uploads${qs ? `?${qs}` : ""}`);
11035
+ }
11036
+ /**
11037
+ * Admin: aggregate storage figures. `logicalBytes` is what users
11038
+ * uploaded; `physicalBytes` is on-disk after content-addressed dedup;
11039
+ * `dedupSaved` is the difference. Requires elevated role.
11040
+ */
11041
+ async adminStorageStats() {
11042
+ return this.request("GET", "/admin/storage/stats");
11043
+ }
11044
+ /**
10993
11045
  * Clear the lockout state on a user account: zeroes the failed-login
10994
11046
  * counter and `locked_until`. Requires elevated role (Admin or
10995
11047
  * Service). The action is recorded in the audit log under
@@ -10999,6 +11051,17 @@ var AbracadabraClient = class {
10999
11051
  await this.request("POST", `/admin/users/${encodeURIComponent(userId)}/unlock`);
11000
11052
  }
11001
11053
  /**
11054
+ * Admin: every non-deleted document the user owns (`source: "owner"`)
11055
+ * or has an explicit permission grant on (`source: "grant"`, with
11056
+ * `role`). Answers "what does this identity touch" without an N+1
11057
+ * client tree walk. Labels are best-effort (they live in the CRDT).
11058
+ * Requires elevated role.
11059
+ */
11060
+ async adminUserDocs(userId, opts = {}) {
11061
+ const qs = opts.limit != null ? `?limit=${opts.limit}` : "";
11062
+ return this.request("GET", `/admin/users/${encodeURIComponent(userId)}/docs${qs}`);
11063
+ }
11064
+ /**
11002
11065
  * Page through the audit log. Filters AND-combine; `limit` defaults to
11003
11066
  * 100 server-side. Requires elevated role.
11004
11067
  */
@@ -11119,6 +11182,30 @@ var AbracadabraClient = class {
11119
11182
  async adminConfigEnvSnapshot() {
11120
11183
  return this.request("GET", "/admin/config/env-snapshot");
11121
11184
  }
11185
+ /**
11186
+ * List every route pattern that currently has at least one per-route
11187
+ * config override. Use {@link adminConfigGetRoute} to read individual
11188
+ * fields. Requires elevated role.
11189
+ */
11190
+ async adminConfigListRoutes() {
11191
+ return (await this.request("GET", "/admin/config/routes")).routes;
11192
+ }
11193
+ /**
11194
+ * Read a field's effective value scoped to `route`, falling back to
11195
+ * the global value when no per-route override exists. `origin_kind`
11196
+ * is `"route_override"` only when an override is actually set.
11197
+ */
11198
+ async adminConfigGetRoute(route, path) {
11199
+ return this.request("GET", `/admin/config/routes/${encodeURIComponent(route)}/fields/${encodeURIComponent(path)}`);
11200
+ }
11201
+ /** Set or replace a per-route override. Mirrors {@link adminConfigSet}. */
11202
+ async adminConfigSetRoute(route, path, value) {
11203
+ return this.request("PUT", `/admin/config/routes/${encodeURIComponent(route)}/fields/${encodeURIComponent(path)}`, { body: { value } });
11204
+ }
11205
+ /** Clear a per-route override (falls back to global). True if one existed. */
11206
+ async adminConfigUnsetRoute(route, path) {
11207
+ return (await this.request("DELETE", `/admin/config/routes/${encodeURIComponent(route)}/fields/${encodeURIComponent(path)}`)).existed;
11208
+ }
11122
11209
  /** List snapshot metadata for a document. */
11123
11210
  async listSnapshots(docId, opts) {
11124
11211
  const params = new URLSearchParams();
@@ -14630,6 +14717,10 @@ var FileBlobStore = class FileBlobStore extends EventEmitter {
14630
14717
  if (!idbAvailable$1()) return Promise.resolve(null);
14631
14718
  if (!this.dbPromise) this.dbPromise = openDb$1(this.origin).catch(() => null).then((db) => {
14632
14719
  this.db = db;
14720
+ if (db) db.onclose = () => {
14721
+ if (this.db === db) this.db = null;
14722
+ this.dbPromise = null;
14723
+ };
14633
14724
  return db;
14634
14725
  });
14635
14726
  return this.dbPromise;
@@ -14648,10 +14739,23 @@ var FileBlobStore = class FileBlobStore extends EventEmitter {
14648
14739
  const key = this.blobKey(docId, uploadId);
14649
14740
  const existing = this.objectUrls.get(key);
14650
14741
  if (existing) return existing;
14651
- const db = await this.getDb();
14742
+ let db = await this.getDb();
14652
14743
  if (db) {
14653
- const tx = db.transaction("blobs", "readonly");
14654
- const entry = await txPromise(tx.objectStore("blobs"), tx.objectStore("blobs").get(key));
14744
+ let entry;
14745
+ try {
14746
+ const tx = db.transaction("blobs", "readonly");
14747
+ entry = await txPromise(tx.objectStore("blobs"), tx.objectStore("blobs").get(key));
14748
+ } catch (err) {
14749
+ if (err?.name === "InvalidStateError") {
14750
+ if (this.db === db) this.db = null;
14751
+ this.dbPromise = null;
14752
+ db = await this.getDb();
14753
+ if (db) {
14754
+ const tx = db.transaction("blobs", "readonly");
14755
+ entry = await txPromise(tx.objectStore("blobs"), tx.objectStore("blobs").get(key));
14756
+ }
14757
+ } else throw err;
14758
+ }
14655
14759
  if (entry) {
14656
14760
  const url = URL.createObjectURL(entry.blob);
14657
14761
  this.objectUrls.set(key, url);
@@ -14902,6 +15006,7 @@ var FileBlobStore = class FileBlobStore extends EventEmitter {
14902
15006
  this.objectUrls.clear();
14903
15007
  this.db?.close();
14904
15008
  this.db = null;
15009
+ this.dbPromise = null;
14905
15010
  this.removeAllListeners();
14906
15011
  }
14907
15012
  };
@@ -15444,21 +15549,113 @@ var E2EAbracadabraProvider = class E2EAbracadabraProvider extends AbracadabraPro
15444
15549
  };
15445
15550
 
15446
15551
  //#endregion
15447
- //#region packages/provider/src/TreeTimestamps.ts
15552
+ //#region packages/provider/src/DocUtils.ts
15448
15553
  /**
15449
- * TreeTimestamps
15554
+ * Shared utilities for the DocumentManager ORM layer.
15450
15555
  *
15451
- * Attaches an afterUpdate observer on a child Y.Doc so that whenever a
15452
- * non-offline update is applied, the `updatedAt` timestamp on the
15453
- * corresponding entry in the root doc's `doc-tree` map is written.
15556
+ * These functions were previously duplicated across `mcp/src/utils.ts`,
15557
+ * `mcp/src/server.ts`, `cli/src/connection.ts`, and `mcp/src/tools/tree.ts`.
15558
+ */
15559
+ /**
15560
+ * Wait for a provider's `synced` event with a timeout.
15561
+ * Resolves immediately if the provider is already synced.
15562
+ */
15563
+ function waitForSync(provider, timeoutMs = 15e3) {
15564
+ if (provider.isSynced) return Promise.resolve();
15565
+ return new Promise((resolve, reject) => {
15566
+ const timer = setTimeout(() => {
15567
+ provider.off("synced", handler);
15568
+ reject(/* @__PURE__ */ new Error(`Sync timed out after ${timeoutMs}ms`));
15569
+ }, timeoutMs);
15570
+ function handler() {
15571
+ clearTimeout(timer);
15572
+ resolve();
15573
+ }
15574
+ provider.on("synced", handler);
15575
+ });
15576
+ }
15577
+ /**
15578
+ * Wrap a promise with a timeout.
15579
+ */
15580
+ function withTimeout(promise, timeoutMs, message) {
15581
+ return new Promise((resolve, reject) => {
15582
+ const timer = setTimeout(() => reject(new Error(message ?? `Operation timed out after ${timeoutMs}ms`)), timeoutMs);
15583
+ promise.then((val) => {
15584
+ clearTimeout(timer);
15585
+ resolve(val);
15586
+ }, (err) => {
15587
+ clearTimeout(timer);
15588
+ reject(err);
15589
+ });
15590
+ });
15591
+ }
15592
+ /**
15593
+ * Normalize a document ID so the hub/root doc ID is treated as the tree root
15594
+ * (null). This lets callers pass the hub doc_id from list_spaces as
15595
+ * parentId/rootId and get the expected root-level results instead of an empty
15596
+ * set.
15597
+ */
15598
+ function normalizeRootId(id, rootDocId) {
15599
+ if (id == null) return null;
15600
+ return id === rootDocId ? null : id;
15601
+ }
15602
+ /**
15603
+ * Safely read a tree map value, converting Y.Map to plain object if needed.
15604
+ */
15605
+ function toPlain(val) {
15606
+ return val instanceof Y.Map ? val.toJSON() : val;
15607
+ }
15608
+ /**
15609
+ * Build a tree/trash entry as a nested `Y.Map`. Use for a brand-new or
15610
+ * re-created key (create / duplicate / restore) where no concurrent
15611
+ * writer exists, so a whole-value write is safe. `undefined` fields are
15612
+ * omitted; `null` is kept (a real value, e.g. top-level `parentId`).
15613
+ */
15614
+ function makeEntryMap(fields) {
15615
+ const m = new Y.Map();
15616
+ for (const [k, v] of Object.entries(fields)) if (v !== void 0) m.set(k, v);
15617
+ return m;
15618
+ }
15619
+ /**
15620
+ * Patch an EXISTING entry's fields per-key on its nested `Y.Map`, so a
15621
+ * concurrent edit to a *different* field by a peer is preserved instead
15622
+ * of being clobbered by a whole-entry write — the whole-entry-LWW fix
15623
+ * (audit ⑦), the mirror of the Rust provider's `with_entry_mut`.
15454
15624
  *
15455
- * This propagates "last edited" timestamps to all peers via the root CRDT,
15456
- * without requiring any server-side changes.
15625
+ * - nested `Y.Map` entry set/delete only the touched keys in place;
15626
+ * - legacy opaque (plain-object) entry → migrated once to a `Y.Map`;
15627
+ * - missing entry → created from the patch (lenient; matches the prior
15628
+ * call-site behaviour of spreading `undefined`).
15457
15629
  *
15458
- * Leading-edge + trailing-edge throttle (default 5 s window): the first
15459
- * update flushes immediately so the "last edited" badge updates instantly;
15460
- * follow-up updates within the window are coalesced into one trailing flush.
15630
+ * A patch value of `undefined` deletes the key; `null` is written.
15631
+ * Self-transacting: it batches its writes in one `Y.Doc` transaction
15632
+ * (a safe reentrant no-op join when already inside one), so callers
15633
+ * don't need to pass or own a transaction.
15461
15634
  */
15635
+ function patchEntry(treeMap, id, patch, removeKeys = []) {
15636
+ const apply = () => {
15637
+ const raw = treeMap.get(id);
15638
+ if (raw instanceof Y.Map) {
15639
+ for (const [k, v] of Object.entries(patch)) if (v === void 0) raw.delete(k);
15640
+ else raw.set(k, v);
15641
+ for (const k of removeKeys) raw.delete(k);
15642
+ return;
15643
+ }
15644
+ const merged = {
15645
+ ...raw == null ? {} : toPlain(raw),
15646
+ ...patch
15647
+ };
15648
+ for (const [k, v] of Object.entries(patch)) if (v === void 0) delete merged[k];
15649
+ for (const k of removeKeys) delete merged[k];
15650
+ treeMap.set(id, makeEntryMap(merged));
15651
+ };
15652
+ const doc = treeMap.doc;
15653
+ if (doc) doc.transact(apply);
15654
+ else apply();
15655
+ }
15656
+
15657
+ //#endregion
15658
+ //#region packages/provider/src/TreeTimestamps.ts
15462
15659
  /**
15463
15660
  * Attach an observer that writes `updatedAt` to the root doc-tree entry for
15464
15661
  * `childDocId` whenever the child doc receives a non-offline update.
@@ -15480,13 +15677,8 @@ function attachUpdatedAtObserver(treeMap, childDocId, childDoc, offlineStore, op
15480
15677
  let pendingTs = 0;
15481
15678
  let timer = null;
15482
15679
  function writeTs(ts) {
15483
- const raw = treeMap.get(childDocId);
15484
- if (!raw) return;
15485
- const entry = raw instanceof Y.Map ? raw.toJSON() : raw;
15486
- treeMap.set(childDocId, {
15487
- ...entry,
15488
- updatedAt: ts
15489
- });
15680
+ if (!treeMap.get(childDocId)) return;
15681
+ patchEntry(treeMap, childDocId, { updatedAt: ts });
15490
15682
  lastFlushedAt = ts;
15491
15683
  }
15492
15684
  function flushPending() {
@@ -18113,64 +18305,6 @@ function resolvePageType(key) {
18113
18305
  return PAGE_TYPES[TYPE_ALIASES[key] ?? key];
18114
18306
  }
18115
18307
 
18116
- //#endregion
18117
- //#region packages/provider/src/DocUtils.ts
18118
- /**
18119
- * Shared utilities for the DocumentManager ORM layer.
18120
- *
18121
- * These functions were previously duplicated across `mcp/src/utils.ts`,
18122
- * `mcp/src/server.ts`, `cli/src/connection.ts`, and `mcp/src/tools/tree.ts`.
18123
- */
18124
- /**
18125
- * Wait for a provider's `synced` event with a timeout.
18126
- * Resolves immediately if the provider is already synced.
18127
- */
18128
- function waitForSync(provider, timeoutMs = 15e3) {
18129
- if (provider.isSynced) return Promise.resolve();
18130
- return new Promise((resolve, reject) => {
18131
- const timer = setTimeout(() => {
18132
- provider.off("synced", handler);
18133
- reject(/* @__PURE__ */ new Error(`Sync timed out after ${timeoutMs}ms`));
18134
- }, timeoutMs);
18135
- function handler() {
18136
- clearTimeout(timer);
18137
- resolve();
18138
- }
18139
- provider.on("synced", handler);
18140
- });
18141
- }
18142
- /**
18143
- * Wrap a promise with a timeout.
18144
- */
18145
- function withTimeout(promise, timeoutMs, message) {
18146
- return new Promise((resolve, reject) => {
18147
- const timer = setTimeout(() => reject(new Error(message ?? `Operation timed out after ${timeoutMs}ms`)), timeoutMs);
18148
- promise.then((val) => {
18149
- clearTimeout(timer);
18150
- resolve(val);
18151
- }, (err) => {
18152
- clearTimeout(timer);
18153
- reject(err);
18154
- });
18155
- });
18156
- }
18157
- /**
18158
- * Normalize a document ID so the hub/root doc ID is treated as the tree root
18159
- * (null). This lets callers pass the hub doc_id from list_spaces as
18160
- * parentId/rootId and get the expected root-level results instead of an empty
18161
- * set.
18162
- */
18163
- function normalizeRootId(id, rootDocId) {
18164
- if (id == null) return null;
18165
- return id === rootDocId ? null : id;
18166
- }
18167
- /**
18168
- * Safely read a tree map value, converting Y.Map to plain object if needed.
18169
- */
18170
- function toPlain(val) {
18171
- return val instanceof Y.Map ? val.toJSON() : val;
18172
- }
18173
-
18174
18308
  //#endregion
18175
18309
  //#region packages/provider/src/SchemaTypes.ts
18176
18310
  /**
@@ -18209,9 +18343,112 @@ function projectTreeEntry(entry, expectedType) {
18209
18343
 
18210
18344
  //#endregion
18211
18345
  //#region packages/provider/src/TreeManager.ts
18346
+ /**
18347
+ * Stable total order over tree siblings: `order` ascending, then `id`
18348
+ * ascending as a deterministic tiebreak. The legacy scan sorted by
18349
+ * `order` alone and left ties to insertion/iteration order — a superset
18350
+ * change that makes cursor pagination well-defined.
18351
+ */
18352
+ function cmpKey(oa, ia, ob, ib) {
18353
+ if (oa !== ob) return oa < ob ? -1 : 1;
18354
+ return ia < ib ? -1 : ia > ib ? 1 : 0;
18355
+ }
18356
+ function cmpEntry(a, b) {
18357
+ return cmpKey(a.order ?? 0, a.id, b.order ?? 0, b.id);
18358
+ }
18359
+ /** Opaque, dependency-free cursor over the (order,id) sibling order. */
18360
+ function encodeCursor(order, id) {
18361
+ return encodeURIComponent(JSON.stringify([order ?? 0, id]));
18362
+ }
18363
+ function decodeCursor(c) {
18364
+ try {
18365
+ const v = JSON.parse(decodeURIComponent(c));
18366
+ if (Array.isArray(v) && typeof v[0] === "number" && typeof v[1] === "string") return {
18367
+ order: v[0],
18368
+ id: v[1]
18369
+ };
18370
+ } catch {}
18371
+ return null;
18372
+ }
18212
18373
  var TreeManager = class {
18213
18374
  constructor(dm) {
18214
18375
  this.dm = dm;
18376
+ this._idxMap = null;
18377
+ this._idxObserver = null;
18378
+ this._idxDirty = true;
18379
+ this._byId = /* @__PURE__ */ new Map();
18380
+ this._childrenByParent = /* @__PURE__ */ new Map();
18381
+ }
18382
+ /**
18383
+ * Ensure the index is enabled, bound to the current root doc's tree
18384
+ * map, and fresh. Returns `false` when the index is disabled or there
18385
+ * is no tree map yet — callers then use the legacy scan path.
18386
+ */
18387
+ ensureIndex() {
18388
+ if (!this.dm.treeIndexEnabled) return false;
18389
+ const treeMap = this.dm.getTreeMap();
18390
+ if (!treeMap) {
18391
+ this.unbindIndex();
18392
+ return false;
18393
+ }
18394
+ if (treeMap !== this._idxMap) {
18395
+ this.unbindIndex();
18396
+ const obs = () => {
18397
+ this._idxDirty = true;
18398
+ };
18399
+ treeMap.observeDeep(obs);
18400
+ this._idxMap = treeMap;
18401
+ this._idxObserver = obs;
18402
+ this._idxDirty = true;
18403
+ }
18404
+ if (this._idxDirty) this.rebuildIndex(treeMap);
18405
+ return true;
18406
+ }
18407
+ unbindIndex() {
18408
+ if (this._idxMap && this._idxObserver) this._idxMap.unobserveDeep(this._idxObserver);
18409
+ this._idxMap = null;
18410
+ this._idxObserver = null;
18411
+ this._byId = /* @__PURE__ */ new Map();
18412
+ this._childrenByParent = /* @__PURE__ */ new Map();
18413
+ this._idxDirty = true;
18414
+ }
18415
+ rebuildIndex(treeMap) {
18416
+ const root = this.dm.rootDocId;
18417
+ const byId = /* @__PURE__ */ new Map();
18418
+ const childrenByParent = /* @__PURE__ */ new Map();
18419
+ treeMap.forEach((raw, id) => {
18420
+ const value = toPlain(raw);
18421
+ if (typeof value !== "object" || value === null) return;
18422
+ const entry = {
18423
+ id,
18424
+ label: value.label || "Untitled",
18425
+ parentId: normalizeRootId(value.parentId ?? null, root),
18426
+ order: value.order ?? 0,
18427
+ type: value.type,
18428
+ meta: value.meta,
18429
+ createdAt: value.createdAt,
18430
+ updatedAt: value.updatedAt
18431
+ };
18432
+ byId.set(id, entry);
18433
+ let bucket = childrenByParent.get(entry.parentId);
18434
+ if (!bucket) {
18435
+ bucket = [];
18436
+ childrenByParent.set(entry.parentId, bucket);
18437
+ }
18438
+ bucket.push(entry);
18439
+ });
18440
+ for (const bucket of childrenByParent.values()) bucket.sort(cmpEntry);
18441
+ this._byId = byId;
18442
+ this._childrenByParent = childrenByParent;
18443
+ this._idxDirty = false;
18444
+ }
18445
+ /**
18446
+ * Release the deep observer. Optional — the observer is auto-rebound
18447
+ * on space switch and becomes moot when the root Y.Doc is GC'd — but
18448
+ * available for consumers that want deterministic teardown.
18449
+ */
18450
+ dispose() {
18451
+ this.unbindIndex();
18215
18452
  }
18216
18453
  /** Read all tree entries as plain objects. */
18217
18454
  readEntries() {
@@ -18234,15 +18471,83 @@ var TreeManager = class {
18234
18471
  });
18235
18472
  return entries;
18236
18473
  }
18474
+ /**
18475
+ * Like {@link readEntries} but with every entry's *stored* parentId
18476
+ * run through {@link normalizeRootId} (parentId === rootDocId → null),
18477
+ * so a cou-sh / orphan-rescue top-level doc (parentId === spaceRoot)
18478
+ * resolves to top-level identically to a provider-created one
18479
+ * (parentId: null). Without this, the raw `parentId === spaceRoot`
18480
+ * form never matches the normalized `null` query and such docs are
18481
+ * silently invisible cross-client. Mirrors the Rust provider's
18482
+ * `normalized_entries`. readEntries/get keep raw values for
18483
+ * round-trip consumers; only tree-walk reads use this.
18484
+ */
18485
+ normalizedEntries() {
18486
+ if (this.ensureIndex()) return Array.from(this._byId.values());
18487
+ const root = this.dm.rootDocId;
18488
+ return this.readEntries().map((e) => ({
18489
+ ...e,
18490
+ parentId: normalizeRootId(e.parentId, root)
18491
+ }));
18492
+ }
18237
18493
  /** Get immediate children of a parent (sorted by order). */
18238
18494
  childrenOf(parentId) {
18239
18495
  const normalized = normalizeRootId(parentId, this.dm.rootDocId);
18240
- return this.readEntries().filter((e) => e.parentId === normalized).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
18496
+ if (this.ensureIndex()) {
18497
+ const bucket = this._childrenByParent.get(normalized);
18498
+ return bucket ? bucket.slice() : [];
18499
+ }
18500
+ return this.normalizedEntries().filter((e) => e.parentId === normalized).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
18501
+ }
18502
+ /**
18503
+ * Paginated immediate children — the Path-1 surface for large fan-out
18504
+ * parents. Walks the same stable (order,id) sibling order as
18505
+ * {@link childrenOf}; `cursor` is opaque (round-trip `nextCursor`).
18506
+ * `limit` defaults to 100. A stale/garbage cursor restarts from the
18507
+ * head rather than throwing. Cursor stability is exact when the index
18508
+ * is enabled; on the legacy scan path siblings with equal `order`
18509
+ * may shift between calls.
18510
+ */
18511
+ childrenOfPage(parentId, opts = {}) {
18512
+ const all = this.childrenOf(parentId);
18513
+ const limit = opts.limit != null && opts.limit > 0 ? Math.floor(opts.limit) : 100;
18514
+ let start = 0;
18515
+ if (opts.cursor) {
18516
+ const dec = decodeCursor(opts.cursor);
18517
+ if (dec) {
18518
+ const at = all.findIndex((e) => cmpKey(e.order ?? 0, e.id, dec.order, dec.id) > 0);
18519
+ start = at < 0 ? all.length : at;
18520
+ }
18521
+ }
18522
+ const entries = all.slice(start, start + limit);
18523
+ const last = entries[entries.length - 1];
18524
+ return {
18525
+ entries,
18526
+ nextCursor: last && start + limit < all.length ? encodeCursor(last.order ?? 0, last.id) : null
18527
+ };
18241
18528
  }
18242
18529
  /** Get all descendants recursively. */
18243
18530
  descendantsOf(parentId) {
18244
18531
  const normalized = normalizeRootId(parentId, this.dm.rootDocId);
18245
- const entries = this.readEntries();
18532
+ if (this.ensureIndex()) {
18533
+ const result = [];
18534
+ const visited = /* @__PURE__ */ new Set();
18535
+ const walk = (pid) => {
18536
+ if (pid !== null) {
18537
+ if (visited.has(pid)) return;
18538
+ visited.add(pid);
18539
+ }
18540
+ const bucket = this._childrenByParent.get(pid);
18541
+ if (!bucket) return;
18542
+ for (const child of bucket) {
18543
+ result.push(child);
18544
+ walk(child.id);
18545
+ }
18546
+ };
18547
+ walk(normalized);
18548
+ return result;
18549
+ }
18550
+ const entries = this.normalizedEntries();
18246
18551
  const result = [];
18247
18552
  const visited = /* @__PURE__ */ new Set();
18248
18553
  const collect = (pid) => {
@@ -18259,9 +18564,25 @@ var TreeManager = class {
18259
18564
  /** Build nested tree JSON. */
18260
18565
  buildTree(rootId, maxDepth = 3) {
18261
18566
  const normalized = normalizeRootId(rootId ?? null, this.dm.rootDocId);
18262
- const entries = this.readEntries();
18567
+ if (this.ensureIndex()) return this._buildTreeIndexed(normalized, maxDepth, 0, /* @__PURE__ */ new Set());
18568
+ const entries = this.normalizedEntries();
18263
18569
  return this._buildTree(entries, normalized, maxDepth, 0, /* @__PURE__ */ new Set());
18264
18570
  }
18571
+ _buildTreeIndexed(rootId, maxDepth, currentDepth, visited) {
18572
+ if (maxDepth >= 0 && currentDepth >= maxDepth) return [];
18573
+ return (this._childrenByParent.get(rootId) ?? []).filter((e) => !visited.has(e.id)).map((entry) => {
18574
+ const next = new Set(visited);
18575
+ next.add(entry.id);
18576
+ return {
18577
+ id: entry.id,
18578
+ label: entry.label,
18579
+ type: entry.type,
18580
+ meta: entry.meta,
18581
+ order: entry.order,
18582
+ children: this._buildTreeIndexed(entry.id, maxDepth, currentDepth + 1, next)
18583
+ };
18584
+ });
18585
+ }
18265
18586
  _buildTree(entries, rootId, maxDepth, currentDepth, visited) {
18266
18587
  if (maxDepth >= 0 && currentDepth >= maxDepth) return [];
18267
18588
  return entries.filter((e) => e.parentId === rootId).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)).filter((e) => !visited.has(e.id)).map((entry) => {
@@ -18312,7 +18633,7 @@ var TreeManager = class {
18312
18633
  }
18313
18634
  /** Search by label (case-insensitive substring match). */
18314
18635
  find(query, rootId) {
18315
- const entries = this.readEntries();
18636
+ const entries = this.normalizedEntries();
18316
18637
  const lowerQuery = query.toLowerCase();
18317
18638
  const normalized = normalizeRootId(rootId ?? null, this.dm.rootDocId);
18318
18639
  const matches = (normalized ? this.descendantsOf(normalized) : entries).filter((e) => e.label.toLowerCase().includes(lowerQuery));
@@ -18346,7 +18667,7 @@ var TreeManager = class {
18346
18667
  const normalizedParent = normalizeRootId(opts.parentId ?? null, this.dm.rootDocId);
18347
18668
  const now = Date.now();
18348
18669
  rootDoc.transact(() => {
18349
- treeMap.set(id, {
18670
+ treeMap.set(id, makeEntryMap({
18350
18671
  label: opts.label,
18351
18672
  parentId: normalizedParent,
18352
18673
  order: now,
@@ -18354,7 +18675,7 @@ var TreeManager = class {
18354
18675
  meta: opts.meta,
18355
18676
  createdAt: now,
18356
18677
  updatedAt: now
18357
- });
18678
+ }));
18358
18679
  });
18359
18680
  return {
18360
18681
  id,
@@ -18393,12 +18714,9 @@ var TreeManager = class {
18393
18714
  const treeMap = this.dm.getTreeMap();
18394
18715
  const rootDoc = this.dm.rootDocument;
18395
18716
  if (!treeMap || !rootDoc) throw new Error("Not connected");
18396
- const raw = treeMap.get(docId);
18397
- if (!raw) throw new Error(`Document ${docId} not found`);
18398
- const entry = toPlain(raw);
18717
+ if (!treeMap.get(docId)) throw new Error(`Document ${docId} not found`);
18399
18718
  rootDoc.transact(() => {
18400
- treeMap.set(docId, {
18401
- ...entry,
18719
+ patchEntry(treeMap, docId, {
18402
18720
  label,
18403
18721
  updatedAt: Date.now()
18404
18722
  });
@@ -18409,12 +18727,9 @@ var TreeManager = class {
18409
18727
  const treeMap = this.dm.getTreeMap();
18410
18728
  const rootDoc = this.dm.rootDocument;
18411
18729
  if (!treeMap || !rootDoc) throw new Error("Not connected");
18412
- const raw = treeMap.get(docId);
18413
- if (!raw) throw new Error(`Document ${docId} not found`);
18414
- const entry = toPlain(raw);
18730
+ if (!treeMap.get(docId)) throw new Error(`Document ${docId} not found`);
18415
18731
  rootDoc.transact(() => {
18416
- treeMap.set(docId, {
18417
- ...entry,
18732
+ patchEntry(treeMap, docId, {
18418
18733
  parentId: normalizeRootId(newParentId ?? null, this.dm.rootDocId),
18419
18734
  order: order ?? Date.now(),
18420
18735
  updatedAt: Date.now()
@@ -18426,12 +18741,9 @@ var TreeManager = class {
18426
18741
  const treeMap = this.dm.getTreeMap();
18427
18742
  const rootDoc = this.dm.rootDocument;
18428
18743
  if (!treeMap || !rootDoc) throw new Error("Not connected");
18429
- const raw = treeMap.get(docId);
18430
- if (!raw) throw new Error(`Document ${docId} not found`);
18431
- const entry = toPlain(raw);
18744
+ if (!treeMap.get(docId)) throw new Error(`Document ${docId} not found`);
18432
18745
  rootDoc.transact(() => {
18433
- treeMap.set(docId, {
18434
- ...entry,
18746
+ patchEntry(treeMap, docId, {
18435
18747
  type,
18436
18748
  updatedAt: Date.now()
18437
18749
  });
@@ -18446,10 +18758,12 @@ var TreeManager = class {
18446
18758
  const trashMap = this.dm.getTrashMap();
18447
18759
  const rootDoc = this.dm.rootDocument;
18448
18760
  if (!treeMap || !trashMap || !rootDoc) throw new Error("Not connected");
18449
- const entries = this.readEntries();
18450
- const toDelete = [docId, ...this._descendantIds(entries, docId)];
18451
18761
  const now = Date.now();
18762
+ let deletedCount = 0;
18452
18763
  rootDoc.transact(() => {
18764
+ const entries = this.readEntries();
18765
+ const toDelete = [docId, ...this._descendantIds(entries, docId)];
18766
+ deletedCount = toDelete.length;
18453
18767
  for (const nid of toDelete) {
18454
18768
  const raw = treeMap.get(nid);
18455
18769
  if (!raw) continue;
@@ -18465,7 +18779,7 @@ var TreeManager = class {
18465
18779
  treeMap.delete(nid);
18466
18780
  }
18467
18781
  });
18468
- return toDelete.length;
18782
+ return deletedCount;
18469
18783
  }
18470
18784
  /** Duplicate a document (shallow clone). Returns the new entry. */
18471
18785
  duplicate(docId) {
@@ -18477,13 +18791,13 @@ var TreeManager = class {
18477
18791
  const newId = crypto.randomUUID();
18478
18792
  const now = Date.now();
18479
18793
  const newLabel = (entry.label || "Untitled") + " (copy)";
18480
- treeMap.set(newId, {
18794
+ treeMap.set(newId, makeEntryMap({
18481
18795
  ...entry,
18482
18796
  label: newLabel,
18483
18797
  order: now,
18484
18798
  createdAt: now,
18485
18799
  updatedAt: now
18486
- });
18800
+ }));
18487
18801
  return {
18488
18802
  id: newId,
18489
18803
  label: newLabel,
@@ -18501,21 +18815,37 @@ var TreeManager = class {
18501
18815
  const trashMap = this.dm.getTrashMap();
18502
18816
  const rootDoc = this.dm.rootDocument;
18503
18817
  if (!treeMap || !trashMap || !rootDoc) throw new Error("Not connected");
18504
- const raw = trashMap.get(docId);
18505
- if (!raw) throw new Error(`Document ${docId} not found in trash`);
18506
- const entry = toPlain(raw);
18818
+ if (!trashMap.get(docId)) throw new Error(`Document ${docId} not found in trash`);
18507
18819
  const now = Date.now();
18508
18820
  rootDoc.transact(() => {
18509
- treeMap.set(docId, {
18510
- label: entry.label || "Untitled",
18511
- parentId: entry.parentId ?? null,
18512
- order: entry.order ?? now,
18513
- type: entry.type,
18514
- meta: entry.meta,
18515
- createdAt: entry.createdAt ?? now,
18516
- updatedAt: now
18821
+ const trashed = /* @__PURE__ */ new Map();
18822
+ trashMap.forEach((raw, id) => {
18823
+ const v = toPlain(raw);
18824
+ if (typeof v === "object" && v !== null) trashed.set(id, v);
18517
18825
  });
18518
- trashMap.delete(docId);
18826
+ const toRestore = [];
18827
+ const visited = /* @__PURE__ */ new Set();
18828
+ const collect = (id) => {
18829
+ if (visited.has(id)) return;
18830
+ visited.add(id);
18831
+ if (!trashed.has(id)) return;
18832
+ toRestore.push(id);
18833
+ for (const [cid, v] of trashed) if ((v.parentId ?? null) === id) collect(cid);
18834
+ };
18835
+ collect(docId);
18836
+ for (const id of toRestore) {
18837
+ const entry = trashed.get(id);
18838
+ treeMap.set(id, makeEntryMap({
18839
+ label: entry.label || "Untitled",
18840
+ parentId: entry.parentId ?? null,
18841
+ order: entry.order ?? now,
18842
+ type: entry.type,
18843
+ meta: entry.meta,
18844
+ createdAt: entry.createdAt ?? now,
18845
+ updatedAt: now
18846
+ }));
18847
+ trashMap.delete(id);
18848
+ }
18519
18849
  });
18520
18850
  }
18521
18851
  /** List trashed documents. */
@@ -19886,9 +20216,9 @@ var ContentManager = class {
19886
20216
  * body, tree metadata, and immediate children.
19887
20217
  */
19888
20218
  async read(docId) {
19889
- const { title, markdown } = yjsToMarkdown((await this.dm.getChildProvider(docId)).document.getXmlFragment("default"));
20219
+ const fragment = (await this.dm.getChildProvider(docId)).document.getXmlFragment("default");
19890
20220
  const treeMap = this.dm.getTreeMap();
19891
- let label = title;
20221
+ let label = "Untitled";
19892
20222
  let type;
19893
20223
  let meta;
19894
20224
  const childrenWithOrder = [];
@@ -19896,7 +20226,7 @@ var ContentManager = class {
19896
20226
  const raw = treeMap.get(docId);
19897
20227
  if (raw) {
19898
20228
  const entry = toPlain(raw);
19899
- label = entry.label || title;
20229
+ label = entry.label || label;
19900
20230
  type = entry.type;
19901
20231
  meta = entry.meta;
19902
20232
  }
@@ -19918,11 +20248,12 @@ var ContentManager = class {
19918
20248
  type,
19919
20249
  meta
19920
20250
  }));
20251
+ const markdown = yjsToMarkdown(fragment, label, meta, type);
19921
20252
  return {
19922
20253
  label,
19923
20254
  type,
19924
20255
  meta,
19925
- title,
20256
+ title: label,
19926
20257
  markdown,
19927
20258
  children
19928
20259
  };
@@ -19944,16 +20275,14 @@ var ContentManager = class {
19944
20275
  if (treeMap && rootDoc) {
19945
20276
  const entry = treeMap.get(docId);
19946
20277
  if (entry) rootDoc.transact(() => {
19947
- const updates = {
19948
- ...entry,
19949
- updatedAt: Date.now()
19950
- };
19951
- if (title) updates.label = title;
19952
- if (Object.keys(meta).length > 0) updates.meta = {
19953
- ...entry.meta ?? {},
20278
+ const cur = toPlain(entry);
20279
+ const patch = { updatedAt: Date.now() };
20280
+ if (title) patch.label = title;
20281
+ if (Object.keys(meta).length > 0) patch.meta = {
20282
+ ...cur.meta ?? {},
19954
20283
  ...meta
19955
20284
  };
19956
- treeMap.set(docId, updates);
20285
+ patchEntry(treeMap, docId, patch);
19957
20286
  });
19958
20287
  }
19959
20288
  }
@@ -20072,8 +20401,7 @@ var MetaManager = class {
20072
20401
  ...meta
20073
20402
  };
20074
20403
  this.validateOrThrow(docId, entry, mergedMeta);
20075
- treeMap.set(docId, {
20076
- ...entry,
20404
+ patchEntry(treeMap, docId, {
20077
20405
  meta: mergedMeta,
20078
20406
  updatedAt: Date.now()
20079
20407
  });
@@ -20092,8 +20420,7 @@ var MetaManager = class {
20092
20420
  if (!raw) throw new Error(`Document ${docId} not found`);
20093
20421
  const entry = toPlain(raw);
20094
20422
  this.validateOrThrow(docId, entry, meta);
20095
- treeMap.set(docId, {
20096
- ...entry,
20423
+ patchEntry(treeMap, docId, {
20097
20424
  meta,
20098
20425
  updatedAt: Date.now()
20099
20426
  });
@@ -20110,8 +20437,7 @@ var MetaManager = class {
20110
20437
  const updated = { ...entry.meta ?? {} };
20111
20438
  for (const key of keys) delete updated[key];
20112
20439
  this.validateOrThrow(docId, entry, updated);
20113
- treeMap.set(docId, {
20114
- ...entry,
20440
+ patchEntry(treeMap, docId, {
20115
20441
  meta: updated,
20116
20442
  updatedAt: Date.now()
20117
20443
  });
@@ -20218,6 +20544,13 @@ var DocumentManager = class {
20218
20544
  get rootDocId() {
20219
20545
  return this._rootDocId;
20220
20546
  }
20547
+ /**
20548
+ * Whether the TreeManager in-memory index is enabled (Path-1 prototype).
20549
+ * Off by default — see {@link DocumentManagerConfig.treeIndex}.
20550
+ */
20551
+ get treeIndexEnabled() {
20552
+ return this._config.treeIndex ?? false;
20553
+ }
20221
20554
  get rootDocument() {
20222
20555
  return this._rootDoc;
20223
20556
  }
@@ -20347,5 +20680,5 @@ var DocumentManager = class {
20347
20680
  };
20348
20681
 
20349
20682
  //#endregion
20350
- export { AbracadabraBaseProvider, AbracadabraClient, AbracadabraProvider, AbracadabraWS, AbracadabraWebRTC, AuthMessageType, AwarenessError, BackgroundSyncManager, BackgroundSyncPersistence, BroadcastChannelSync, CHANNEL_NAMES, ChannelKeyResolver, ChatClient, ConnectionTimeout, ContentManager, CryptoIdentityKeystore, DEFAULT_FILE_CHUNK_SIZE, DEFAULT_ICE_SERVERS, DataChannelRouter, DevicePairingChannel, DeviceRegistrationService, DocKeyManager, DocumentCache, DocumentManager, E2EAbracadabraProvider, E2EEChannel, E2EOfflineStore, EncryptedChatClient, EncryptedYMap, EncryptedYText, FileBlobStore, FileTransferChannel, FileTransferHandle, Forbidden, GEO_TYPE_META_SCHEMAS, HocuspocusProvider, HocuspocusProviderWebsocket, IdentityDocProvider, KEY_EXCHANGE_CHANNEL, Kind, LocalStorageDeviceSessionStorage, ManualSignaling, MessageTooBig, MessageType, MetaManager, MetaValidationError, NotificationsClient, OfflineStore, PAGE_TYPES, PeerConnection, QUERY_PREFIX, QueryClient, QueryError, RPC_PREFIX, ResetConnection, RpcClient, RpcError, SERVER_ROOT_ID, SearchIndex, SignalingSocket, SubdocMessage, TYPE_ALIASES, TokenManager, TreeManager, TypedDocTypeMismatchError, Unauthorized, WebSocketStatus, WsReadyStates, YjsDataChannel, attachUpdatedAtObserver, awarenessStatesToArray, wordlist as bip39Wordlist, buildBlockquoteElement, buildBlocksFromMarkdown, buildBulletListElement, buildCodeBlockElement, buildHeadingElement, buildHorizontalRuleElement, buildOrderedListElement, buildParagraphElement, buildTaskListElement, decryptChatContent, decryptField, deriveIdentityDocId, deriveSeedWrappingKey, encryptChatContent, encryptField, filenameToLabel, foldRecords, generateMnemonic, isEncryptedContent, makeEncryptedYMap, makeEncryptedYText, mnemonicToEd25519Seed, mnemonicToKeyPair, normalizeRootId, parseFrontmatter, populateYDocFromMarkdown, readAuthMessage, readBlocksFromFragment, recordFromYAny, resolvePageType, toPlain, unwrapSeed, validateMnemonic, waitForSync, withTimeout, wrapSeed, writeAuthenticated, writeAuthentication, writePermissionDenied, writeTokenSyncRequest, yjsToMarkdown };
20683
+ export { AbracadabraBaseProvider, AbracadabraClient, AbracadabraProvider, AbracadabraWS, AbracadabraWebRTC, AuthMessageType, AwarenessError, BackgroundSyncManager, BackgroundSyncPersistence, BroadcastChannelSync, CHANNEL_NAMES, ChannelKeyResolver, ChatClient, ConnectionTimeout, ContentManager, CryptoIdentityKeystore, DEFAULT_FILE_CHUNK_SIZE, DEFAULT_ICE_SERVERS, DataChannelRouter, DevicePairingChannel, DeviceRegistrationService, DocKeyManager, DocumentCache, DocumentManager, E2EAbracadabraProvider, E2EEChannel, E2EOfflineStore, EncryptedChatClient, EncryptedYMap, EncryptedYText, FileBlobStore, FileTransferChannel, FileTransferHandle, Forbidden, GEO_TYPE_META_SCHEMAS, HocuspocusProvider, HocuspocusProviderWebsocket, IdentityDocProvider, KEY_EXCHANGE_CHANNEL, Kind, LocalStorageDeviceSessionStorage, ManualSignaling, MessageTooBig, MessageType, MetaManager, MetaValidationError, NotificationsClient, OfflineStore, PAGE_TYPES, PeerConnection, QUERY_PREFIX, QueryClient, QueryError, RPC_PREFIX, ResetConnection, RpcClient, RpcError, SERVER_ROOT_ID, SearchIndex, SignalingSocket, SubdocMessage, TYPE_ALIASES, TokenManager, TreeManager, TypedDocTypeMismatchError, Unauthorized, WebSocketStatus, WsReadyStates, YjsDataChannel, attachUpdatedAtObserver, awarenessStatesToArray, wordlist as bip39Wordlist, buildBlockquoteElement, buildBlocksFromMarkdown, buildBulletListElement, buildCodeBlockElement, buildHeadingElement, buildHorizontalRuleElement, buildOrderedListElement, buildParagraphElement, buildTaskListElement, decryptChatContent, decryptField, deriveIdentityDocId, deriveSeedWrappingKey, encryptChatContent, encryptField, filenameToLabel, foldRecords, generateMnemonic, isEncryptedContent, makeEncryptedYMap, makeEncryptedYText, makeEntryMap, mnemonicToEd25519Seed, mnemonicToKeyPair, normalizeRootId, parseFrontmatter, patchEntry, populateYDocFromMarkdown, readAuthMessage, readBlocksFromFragment, recordFromYAny, resolvePageType, toPlain, unwrapSeed, validateMnemonic, waitForSync, withTimeout, wrapSeed, writeAuthenticated, writeAuthentication, writePermissionDenied, writeTokenSyncRequest, yjsToMarkdown };
20351
20684
  //# sourceMappingURL=abracadabra-provider.esm.js.map