@abraca/dabra 2.7.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 +41 -4
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +41 -5
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +25 -2
- package/package.json +2 -2
- package/src/DocUtils.ts +62 -3
- package/src/index.ts +1 -0
|
@@ -15676,6 +15676,19 @@ function makeEntryMap(fields) {
|
|
|
15676
15676
|
return m;
|
|
15677
15677
|
}
|
|
15678
15678
|
/**
|
|
15679
|
+
* A label is a "placeholder" — i.e. carries no real user title — when it is
|
|
15680
|
+
* empty/whitespace, null/undefined, or the literal `"Untitled"` sentinel
|
|
15681
|
+
* (case-insensitive, so `"untitled"` from a `labelToFilename` round-trip is
|
|
15682
|
+
* caught too). The whole tree-label corruption class boils down to a
|
|
15683
|
+
* placeholder being allowed to overwrite a real title; `patchEntry` refuses
|
|
15684
|
+
* exactly that. Mirrors cou-sh's `isEmptyTreeLabel`.
|
|
15685
|
+
*/
|
|
15686
|
+
function isPlaceholderLabel(label) {
|
|
15687
|
+
if (typeof label !== "string") return label == null;
|
|
15688
|
+
const t = label.trim();
|
|
15689
|
+
return t === "" || t.toLowerCase() === "untitled";
|
|
15690
|
+
}
|
|
15691
|
+
/**
|
|
15679
15692
|
* Patch an EXISTING entry's fields per-key on its nested `Y.Map`, so a
|
|
15680
15693
|
* concurrent edit to a *different* field by a peer is preserved instead
|
|
15681
15694
|
* of being clobbered by a whole-entry write — the whole-entry-LWW fix
|
|
@@ -15690,21 +15703,44 @@ function makeEntryMap(fields) {
|
|
|
15690
15703
|
* Self-transacting: it batches its writes in one `Y.Doc` transaction
|
|
15691
15704
|
* (a safe reentrant no-op join when already inside one), so callers
|
|
15692
15705
|
* don't need to pass or own a transaction.
|
|
15706
|
+
*
|
|
15707
|
+
* ── NO-DESTROY LABEL INVARIANT ──────────────────────────────────────────
|
|
15708
|
+
* A `label` patch that is a placeholder (empty/whitespace/"Untitled") is
|
|
15709
|
+
* DROPPED when the entry already holds a real (non-placeholder) label —
|
|
15710
|
+
* regardless of which consumer (cou-sh title-sync, fs-sync rename
|
|
15711
|
+
* detection, MCP, table renderers, a stale snapshot) tried it. This is the
|
|
15712
|
+
* source-of-truth guard against the "card title silently becomes Untitled
|
|
15713
|
+
* / files renamed to untitled.md" corruption: a placeholder must never win
|
|
15714
|
+
* over a real title. Creating a brand-new entry with an empty label (e.g.
|
|
15715
|
+
* a fresh kanban card) is still allowed — the guard only fires when a real
|
|
15716
|
+
* label already exists. Pass `{ allowLabelClear: true }` to override (the
|
|
15717
|
+
* single legitimate "user explicitly cleared it" path).
|
|
15693
15718
|
*/
|
|
15694
|
-
function patchEntry(treeMap, id, patch, removeKeys = []) {
|
|
15719
|
+
function patchEntry(treeMap, id, patch, removeKeys = [], opts = {}) {
|
|
15695
15720
|
const apply = () => {
|
|
15696
15721
|
const raw = treeMap.get(id);
|
|
15722
|
+
let effectivePatch = patch;
|
|
15723
|
+
if (!opts.allowLabelClear && Object.hasOwn(patch, "label") && isPlaceholderLabel(patch.label)) {
|
|
15724
|
+
let existingLabel;
|
|
15725
|
+
if (raw != null && typeof raw.get === "function") existingLabel = raw.get("label");
|
|
15726
|
+
else if (raw != null && typeof raw.toJSON === "function") existingLabel = raw.toJSON()?.label;
|
|
15727
|
+
else if (raw != null && typeof raw === "object") existingLabel = raw.label;
|
|
15728
|
+
if (!isPlaceholderLabel(existingLabel)) {
|
|
15729
|
+
const { label: _dropped, ...rest } = patch;
|
|
15730
|
+
effectivePatch = rest;
|
|
15731
|
+
}
|
|
15732
|
+
}
|
|
15697
15733
|
if (raw instanceof Y.Map) {
|
|
15698
|
-
for (const [k, v] of Object.entries(
|
|
15734
|
+
for (const [k, v] of Object.entries(effectivePatch)) if (v === void 0) raw.delete(k);
|
|
15699
15735
|
else raw.set(k, v);
|
|
15700
15736
|
for (const k of removeKeys) raw.delete(k);
|
|
15701
15737
|
return;
|
|
15702
15738
|
}
|
|
15703
15739
|
const merged = {
|
|
15704
15740
|
...raw == null ? {} : toPlain(raw),
|
|
15705
|
-
...
|
|
15741
|
+
...effectivePatch
|
|
15706
15742
|
};
|
|
15707
|
-
for (const [k, v] of Object.entries(
|
|
15743
|
+
for (const [k, v] of Object.entries(effectivePatch)) if (v === void 0) delete merged[k];
|
|
15708
15744
|
for (const k of removeKeys) delete merged[k];
|
|
15709
15745
|
treeMap.set(id, makeEntryMap(merged));
|
|
15710
15746
|
};
|
|
@@ -20744,5 +20780,5 @@ var DocumentManager = class {
|
|
|
20744
20780
|
};
|
|
20745
20781
|
|
|
20746
20782
|
//#endregion
|
|
20747
|
-
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 };
|
|
20783
|
+
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, isPlaceholderLabel, makeEncryptedYMap, makeEncryptedYText, makeEntryMap, mnemonicToEd25519Seed, mnemonicToKeyPair, normalizeRootId, parseFrontmatter, patchEntry, populateYDocFromMarkdown, readAuthMessage, readBlocksFromFragment, recordFromYAny, resolvePageType, toPlain, unwrapSeed, validateMnemonic, waitForSync, withTimeout, wrapSeed, writeAuthenticated, writeAuthentication, writePermissionDenied, writeTokenSyncRequest, yjsToMarkdown };
|
|
20748
20784
|
//# sourceMappingURL=abracadabra-provider.esm.js.map
|