@abraca/dabra 2.6.0 → 2.8.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.
- package/dist/abracadabra-provider.cjs +65 -7
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +65 -8
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +32 -4
- package/package.json +2 -2
- package/src/AbracadabraBaseProvider.ts +15 -0
- package/src/ContentManager.ts +8 -6
- package/src/DocUtils.ts +62 -3
- package/src/index.ts +1 -0
|
@@ -2328,6 +2328,21 @@ var QueryClient = class extends EventEmitter {
|
|
|
2328
2328
|
}
|
|
2329
2329
|
};
|
|
2330
2330
|
|
|
2331
|
+
//#endregion
|
|
2332
|
+
//#region packages/provider/src/OutgoingMessages/QueryAwarenessMessage.ts
|
|
2333
|
+
var QueryAwarenessMessage = class extends OutgoingMessage {
|
|
2334
|
+
constructor(..._args) {
|
|
2335
|
+
super(..._args);
|
|
2336
|
+
this.type = MessageType.QueryAwareness;
|
|
2337
|
+
this.description = "Queries awareness states";
|
|
2338
|
+
}
|
|
2339
|
+
get(args) {
|
|
2340
|
+
writeVarString(this.encoder, args.documentName);
|
|
2341
|
+
writeVarUint(this.encoder, this.type);
|
|
2342
|
+
return this.encoder;
|
|
2343
|
+
}
|
|
2344
|
+
};
|
|
2345
|
+
|
|
2331
2346
|
//#endregion
|
|
2332
2347
|
//#region packages/provider/src/OutgoingMessages/SyncStepOneMessage.ts
|
|
2333
2348
|
var SyncStepOneMessage = class extends OutgoingMessage {
|
|
@@ -2610,6 +2625,7 @@ var AbracadabraBaseProvider = class extends EventEmitter {
|
|
|
2610
2625
|
clients: [this.document.clientID],
|
|
2611
2626
|
documentName: this.configuration.name
|
|
2612
2627
|
});
|
|
2628
|
+
if (this.awareness) this.send(QueryAwarenessMessage, { documentName: this.configuration.name });
|
|
2613
2629
|
}
|
|
2614
2630
|
send(message, args) {
|
|
2615
2631
|
if (!this._isAttached) return;
|
|
@@ -15699,6 +15715,19 @@ function makeEntryMap(fields) {
|
|
|
15699
15715
|
return m;
|
|
15700
15716
|
}
|
|
15701
15717
|
/**
|
|
15718
|
+
* A label is a "placeholder" — i.e. carries no real user title — when it is
|
|
15719
|
+
* empty/whitespace, null/undefined, or the literal `"Untitled"` sentinel
|
|
15720
|
+
* (case-insensitive, so `"untitled"` from a `labelToFilename` round-trip is
|
|
15721
|
+
* caught too). The whole tree-label corruption class boils down to a
|
|
15722
|
+
* placeholder being allowed to overwrite a real title; `patchEntry` refuses
|
|
15723
|
+
* exactly that. Mirrors cou-sh's `isEmptyTreeLabel`.
|
|
15724
|
+
*/
|
|
15725
|
+
function isPlaceholderLabel(label) {
|
|
15726
|
+
if (typeof label !== "string") return label == null;
|
|
15727
|
+
const t = label.trim();
|
|
15728
|
+
return t === "" || t.toLowerCase() === "untitled";
|
|
15729
|
+
}
|
|
15730
|
+
/**
|
|
15702
15731
|
* Patch an EXISTING entry's fields per-key on its nested `Y.Map`, so a
|
|
15703
15732
|
* concurrent edit to a *different* field by a peer is preserved instead
|
|
15704
15733
|
* of being clobbered by a whole-entry write — the whole-entry-LWW fix
|
|
@@ -15713,21 +15742,44 @@ function makeEntryMap(fields) {
|
|
|
15713
15742
|
* Self-transacting: it batches its writes in one `Y.Doc` transaction
|
|
15714
15743
|
* (a safe reentrant no-op join when already inside one), so callers
|
|
15715
15744
|
* don't need to pass or own a transaction.
|
|
15745
|
+
*
|
|
15746
|
+
* ── NO-DESTROY LABEL INVARIANT ──────────────────────────────────────────
|
|
15747
|
+
* A `label` patch that is a placeholder (empty/whitespace/"Untitled") is
|
|
15748
|
+
* DROPPED when the entry already holds a real (non-placeholder) label —
|
|
15749
|
+
* regardless of which consumer (cou-sh title-sync, fs-sync rename
|
|
15750
|
+
* detection, MCP, table renderers, a stale snapshot) tried it. This is the
|
|
15751
|
+
* source-of-truth guard against the "card title silently becomes Untitled
|
|
15752
|
+
* / files renamed to untitled.md" corruption: a placeholder must never win
|
|
15753
|
+
* over a real title. Creating a brand-new entry with an empty label (e.g.
|
|
15754
|
+
* a fresh kanban card) is still allowed — the guard only fires when a real
|
|
15755
|
+
* label already exists. Pass `{ allowLabelClear: true }` to override (the
|
|
15756
|
+
* single legitimate "user explicitly cleared it" path).
|
|
15716
15757
|
*/
|
|
15717
|
-
function patchEntry(treeMap, id, patch, removeKeys = []) {
|
|
15758
|
+
function patchEntry(treeMap, id, patch, removeKeys = [], opts = {}) {
|
|
15718
15759
|
const apply = () => {
|
|
15719
15760
|
const raw = treeMap.get(id);
|
|
15761
|
+
let effectivePatch = patch;
|
|
15762
|
+
if (!opts.allowLabelClear && Object.hasOwn(patch, "label") && isPlaceholderLabel(patch.label)) {
|
|
15763
|
+
let existingLabel;
|
|
15764
|
+
if (raw != null && typeof raw.get === "function") existingLabel = raw.get("label");
|
|
15765
|
+
else if (raw != null && typeof raw.toJSON === "function") existingLabel = raw.toJSON()?.label;
|
|
15766
|
+
else if (raw != null && typeof raw === "object") existingLabel = raw.label;
|
|
15767
|
+
if (!isPlaceholderLabel(existingLabel)) {
|
|
15768
|
+
const { label: _dropped, ...rest } = patch;
|
|
15769
|
+
effectivePatch = rest;
|
|
15770
|
+
}
|
|
15771
|
+
}
|
|
15720
15772
|
if (raw instanceof yjs.Map) {
|
|
15721
|
-
for (const [k, v] of Object.entries(
|
|
15773
|
+
for (const [k, v] of Object.entries(effectivePatch)) if (v === void 0) raw.delete(k);
|
|
15722
15774
|
else raw.set(k, v);
|
|
15723
15775
|
for (const k of removeKeys) raw.delete(k);
|
|
15724
15776
|
return;
|
|
15725
15777
|
}
|
|
15726
15778
|
const merged = {
|
|
15727
15779
|
...raw == null ? {} : toPlain(raw),
|
|
15728
|
-
...
|
|
15780
|
+
...effectivePatch
|
|
15729
15781
|
};
|
|
15730
|
-
for (const [k, v] of Object.entries(
|
|
15782
|
+
for (const [k, v] of Object.entries(effectivePatch)) if (v === void 0) delete merged[k];
|
|
15731
15783
|
for (const k of removeKeys) delete merged[k];
|
|
15732
15784
|
treeMap.set(id, makeEntryMap(merged));
|
|
15733
15785
|
};
|
|
@@ -20320,8 +20372,13 @@ var ContentManager = class {
|
|
|
20320
20372
|
}
|
|
20321
20373
|
/**
|
|
20322
20374
|
* Read document content as markdown.
|
|
20323
|
-
*
|
|
20324
|
-
* body, tree
|
|
20375
|
+
*
|
|
20376
|
+
* Returns the markdown body, tree-derived label/type/meta, and immediate
|
|
20377
|
+
* children. `title` mirrors `label` (the tree entry's display name) — it
|
|
20378
|
+
* is *not* derived from a TipTap `documentHeader`, and the markdown body
|
|
20379
|
+
* does NOT include YAML frontmatter. Callers that want frontmatter-style
|
|
20380
|
+
* round-tripping should serialise `meta`/`type` themselves on top of the
|
|
20381
|
+
* returned markdown.
|
|
20325
20382
|
*/
|
|
20326
20383
|
async read(docId) {
|
|
20327
20384
|
const fragment = (await this.dm.getChildProvider(docId)).document.getXmlFragment("default");
|
|
@@ -20356,7 +20413,7 @@ var ContentManager = class {
|
|
|
20356
20413
|
type,
|
|
20357
20414
|
meta
|
|
20358
20415
|
}));
|
|
20359
|
-
const markdown = yjsToMarkdown(fragment
|
|
20416
|
+
const { markdown } = yjsToMarkdown(fragment);
|
|
20360
20417
|
return {
|
|
20361
20418
|
label,
|
|
20362
20419
|
type,
|
|
@@ -20879,6 +20936,7 @@ exports.filenameToLabel = filenameToLabel;
|
|
|
20879
20936
|
exports.foldRecords = foldRecords;
|
|
20880
20937
|
exports.generateMnemonic = generateMnemonic;
|
|
20881
20938
|
exports.isEncryptedContent = isEncryptedContent;
|
|
20939
|
+
exports.isPlaceholderLabel = isPlaceholderLabel;
|
|
20882
20940
|
exports.makeEncryptedYMap = makeEncryptedYMap;
|
|
20883
20941
|
exports.makeEncryptedYText = makeEncryptedYText;
|
|
20884
20942
|
exports.makeEntryMap = makeEntryMap;
|