@inkandswitch/patchwork-pkg-base 0.0.7 → 0.0.8
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/modules.json +4 -0
- package/package.json +1 -1
- package/packages/account-history/dist/assets/HistoryRecorder-HO_sxeuE.js +248 -0
- package/packages/account-history/dist/assets/HistoryRecorder-HO_sxeuE.js.map +1 -0
- package/packages/account-history/dist/assets/HistoryViewer-Ct5g7zek.js +308 -0
- package/packages/account-history/dist/assets/HistoryViewer-Ct5g7zek.js.map +1 -0
- package/packages/account-history/dist/assets/NotebookViewer-BkYJL6Jc.js +504 -0
- package/packages/account-history/dist/assets/NotebookViewer-BkYJL6Jc.js.map +1 -0
- package/packages/account-history/dist/assets/index-CFzuSuJg.js +148 -0
- package/packages/account-history/dist/assets/index-CFzuSuJg.js.map +1 -0
- package/packages/account-history/dist/assets/makeDocumentProjection-DXgEZYyv.js +706 -0
- package/packages/account-history/dist/assets/makeDocumentProjection-DXgEZYyv.js.map +1 -0
- package/packages/account-history/dist/assets/store-CRmRL4Cv.js +1079 -0
- package/packages/account-history/dist/assets/store-CRmRL4Cv.js.map +1 -0
- package/packages/account-history/dist/index.js +5 -0
- package/packages/account-history/dist/index.js.map +1 -0
- package/packages/account-history/package.json +33 -0
- package/packages/chat/dist/ChatRoot-BXsklgz7.js +6113 -0
- package/packages/chat/dist/context-tool-CenQrztX.js +107 -0
- package/packages/chat/dist/datatype-1niKKK-c.js +15 -0
- package/packages/chat/dist/index-DYFHDHZ9.js +368 -0
- package/packages/chat/dist/index.js +5 -0
- package/packages/chat/dist/tool-D9BTS5wc.js +38 -0
- package/packages/chat/package.json +42 -0
- package/packages/comments-view/dist/assets/comments-D9lwpHOh.js +50 -0
- package/packages/comments-view/dist/assets/comments-D9lwpHOh.js.map +1 -0
- package/packages/comments-view/dist/assets/datatype-C4SMwWiO.js +22 -0
- package/packages/comments-view/dist/assets/datatype-C4SMwWiO.js.map +1 -0
- package/packages/comments-view/dist/assets/main-C8GVksuY.js +2973 -0
- package/packages/comments-view/dist/assets/main-C8GVksuY.js.map +1 -0
- package/packages/comments-view/dist/index.js +115 -0
- package/packages/comments-view/dist/index.js.map +1 -0
- package/packages/comments-view/package.json +36 -0
- package/packages/drafts/dist/assets/DraftDatatype-Dn8VF6oC.js +14 -0
- package/packages/drafts/dist/assets/DraftDatatype-Dn8VF6oC.js.map +1 -0
- package/packages/drafts/dist/assets/DraftListProvider-DVhUGU1x.js +362 -0
- package/packages/drafts/dist/assets/DraftListProvider-DVhUGU1x.js.map +1 -0
- package/packages/drafts/dist/assets/DraftOverlayProvider-NMDqnpBV.js +123 -0
- package/packages/drafts/dist/assets/DraftOverlayProvider-NMDqnpBV.js.map +1 -0
- package/packages/drafts/dist/assets/clone-policy-D4XOfZxs.js +15 -0
- package/packages/drafts/dist/assets/clone-policy-D4XOfZxs.js.map +1 -0
- package/packages/drafts/dist/assets/index-DAqs20jZ.js +65 -0
- package/packages/drafts/dist/assets/index-DAqs20jZ.js.map +1 -0
- package/packages/drafts/dist/assets/main-Cdev7z-t.js +2366 -0
- package/packages/drafts/dist/assets/main-Cdev7z-t.js.map +1 -0
- package/packages/drafts/dist/index.js +140 -0
- package/packages/drafts/dist/index.js.map +1 -0
- package/packages/drafts/package.json +34 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./assets/main-C8GVksuY.js","./assets/comments-D9lwpHOh.js","./assets/datatype-C4SMwWiO.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
const scriptRel = "modulepreload";
|
|
3
|
+
const assetsURL = function(dep, importerUrl) {
|
|
4
|
+
return new URL(dep, importerUrl).href;
|
|
5
|
+
};
|
|
6
|
+
const seen = {};
|
|
7
|
+
const __vitePreload = function preload(baseModule, deps, importerUrl) {
|
|
8
|
+
let promise = Promise.resolve();
|
|
9
|
+
if (deps && deps.length > 0) {
|
|
10
|
+
let allSettled = function(promises$2) {
|
|
11
|
+
return Promise.all(promises$2.map((p) => Promise.resolve(p).then((value$1) => ({
|
|
12
|
+
status: "fulfilled",
|
|
13
|
+
value: value$1
|
|
14
|
+
}), (reason) => ({
|
|
15
|
+
status: "rejected",
|
|
16
|
+
reason
|
|
17
|
+
}))));
|
|
18
|
+
};
|
|
19
|
+
const links = document.getElementsByTagName("link");
|
|
20
|
+
const cspNonceMeta = document.querySelector("meta[property=csp-nonce]");
|
|
21
|
+
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
|
|
22
|
+
promise = allSettled(deps.map((dep) => {
|
|
23
|
+
dep = assetsURL(dep, importerUrl);
|
|
24
|
+
if (dep in seen) return;
|
|
25
|
+
seen[dep] = true;
|
|
26
|
+
const isCss = dep.endsWith(".css");
|
|
27
|
+
const cssSelector = isCss ? '[rel="stylesheet"]' : "";
|
|
28
|
+
if (!!importerUrl) for (let i$1 = links.length - 1; i$1 >= 0; i$1--) {
|
|
29
|
+
const link$1 = links[i$1];
|
|
30
|
+
if (link$1.href === dep && (!isCss || link$1.rel === "stylesheet")) return;
|
|
31
|
+
}
|
|
32
|
+
else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) return;
|
|
33
|
+
const link = document.createElement("link");
|
|
34
|
+
link.rel = isCss ? "stylesheet" : scriptRel;
|
|
35
|
+
if (!isCss) link.as = "script";
|
|
36
|
+
link.crossOrigin = "";
|
|
37
|
+
link.href = dep;
|
|
38
|
+
if (cspNonce) link.setAttribute("nonce", cspNonce);
|
|
39
|
+
document.head.appendChild(link);
|
|
40
|
+
if (isCss) return new Promise((res, rej) => {
|
|
41
|
+
link.addEventListener("load", res);
|
|
42
|
+
link.addEventListener("error", () => rej(/* @__PURE__ */ new Error(`Unable to preload CSS for ${dep}`)));
|
|
43
|
+
});
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
function handlePreloadError(err$2) {
|
|
47
|
+
const e$1 = new Event("vite:preloadError", { cancelable: true });
|
|
48
|
+
e$1.payload = err$2;
|
|
49
|
+
window.dispatchEvent(e$1);
|
|
50
|
+
if (!e$1.defaultPrevented) throw err$2;
|
|
51
|
+
}
|
|
52
|
+
return promise.then((res) => {
|
|
53
|
+
for (const item of res || []) {
|
|
54
|
+
if (item.status !== "rejected") continue;
|
|
55
|
+
handlePreloadError(item.reason);
|
|
56
|
+
}
|
|
57
|
+
return baseModule().catch(handlePreloadError);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const plugins = [
|
|
61
|
+
// A `patchwork:component` that takes no document: the render function
|
|
62
|
+
// ignores its handle (it reads everything off `element`), so we pass `null`
|
|
63
|
+
// and it can be slotted in without an account doc.
|
|
64
|
+
{
|
|
65
|
+
type: "patchwork:component",
|
|
66
|
+
id: "comments-view",
|
|
67
|
+
tags: ["context-tool"],
|
|
68
|
+
name: "Comments",
|
|
69
|
+
async load() {
|
|
70
|
+
const { renderCommentsView } = await __vitePreload(async () => {
|
|
71
|
+
const { renderCommentsView: renderCommentsView2 } = await import("./assets/main-C8GVksuY.js");
|
|
72
|
+
return { renderCommentsView: renderCommentsView2 };
|
|
73
|
+
}, true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
74
|
+
return (element) => renderCommentsView(null, element);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
// The datatype for a comment thread subdocument. Registering it lets a
|
|
78
|
+
// thread opened on its own (its `@patchwork.type` is `comment-thread`)
|
|
79
|
+
// resolve a title and, via `supportedDatatypes` below, a tool.
|
|
80
|
+
{
|
|
81
|
+
type: "patchwork:datatype",
|
|
82
|
+
id: "comment-thread",
|
|
83
|
+
name: "Comment Thread",
|
|
84
|
+
icon: "MessageSquare",
|
|
85
|
+
unlisted: true,
|
|
86
|
+
async load() {
|
|
87
|
+
const { CommentThreadDatatype } = await __vitePreload(async () => {
|
|
88
|
+
const { CommentThreadDatatype: CommentThreadDatatype2 } = await import("./assets/datatype-C4SMwWiO.js");
|
|
89
|
+
return { CommentThreadDatatype: CommentThreadDatatype2 };
|
|
90
|
+
}, true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
|
|
91
|
+
return CommentThreadDatatype;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
// Renders one comment thread from its subdocument url. It's mounted
|
|
95
|
+
// explicitly by `CommentsView` via `<patchwork-view>`, but now also
|
|
96
|
+
// declares support for the `comment-thread` datatype so it's the tool
|
|
97
|
+
// detected when a thread subdocument is opened on its own.
|
|
98
|
+
{
|
|
99
|
+
type: "patchwork:tool",
|
|
100
|
+
id: "comment-thread",
|
|
101
|
+
name: "Comment Thread",
|
|
102
|
+
supportedDatatypes: ["comment-thread"],
|
|
103
|
+
async load() {
|
|
104
|
+
const { renderCommentThread } = await __vitePreload(async () => {
|
|
105
|
+
const { renderCommentThread: renderCommentThread2 } = await import("./assets/main-C8GVksuY.js");
|
|
106
|
+
return { renderCommentThread: renderCommentThread2 };
|
|
107
|
+
}, true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
108
|
+
return renderCommentThread;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
export {
|
|
113
|
+
plugins
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEO,MAAM,UAAyB;AAAA;AAAA;AAAA;AAAA,EAIpC;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM,CAAC,cAAc;AAAA,IACrB,MAAM;AAAA,IACN,MAAM,OAAO;AACX,YAAM,EAAE,uBAAuB;AAAA,oCAAAA,oBAAA,UAAM,OAAO,2BAAQ;AAAA,qCAAAA,oBAAA;AAAA;AACpD,aAAO,CAAC,YAAyB,mBAAmB,MAAe,OAAO;AAAA,IAC5E;AAAA;AAAA;AAAA;AAAA;AAAA,EAKF;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,MAAM,OAAO;AACX,YAAM,EAAE,0BAA0B;AAAA,uCAAAC,uBAAA,UAAM,OAAO,+BAAY;AAAA,wCAAAA,uBAAA;AAAA;AAC3D,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,oBAAoB,CAAC,gBAAgB;AAAA,IACrC,MAAM,OAAO;AACX,YAAM,EAAE,wBAAwB;AAAA,qCAAAC,qBAAA,UAAM,OAAO,2BAAQ;AAAA,sCAAAA,qBAAA;AAAA;AACrD,aAAO;AAAA,IACT;AAAA;AAEJ","names":["renderCommentsView","CommentThreadDatatype","renderCommentThread"],"ignoreList":[],"sources":["../src/index.ts"],"sourcesContent":["import { Plugin, ToolElement } from \"@inkandswitch/patchwork-plugins\";\n\nexport const plugins: Plugin<any>[] = [\n // A `patchwork:component` that takes no document: the render function\n // ignores its handle (it reads everything off `element`), so we pass `null`\n // and it can be slotted in without an account doc.\n {\n type: \"patchwork:component\",\n id: \"comments-view\",\n tags: [\"context-tool\"],\n name: \"Comments\",\n async load() {\n const { renderCommentsView } = await import(\"./main\");\n return (element: ToolElement) => renderCommentsView(null as never, element);\n },\n },\n // The datatype for a comment thread subdocument. Registering it lets a\n // thread opened on its own (its `@patchwork.type` is `comment-thread`)\n // resolve a title and, via `supportedDatatypes` below, a tool.\n {\n type: \"patchwork:datatype\",\n id: \"comment-thread\",\n name: \"Comment Thread\",\n icon: \"MessageSquare\",\n unlisted: true,\n async load() {\n const { CommentThreadDatatype } = await import(\"./datatype\");\n return CommentThreadDatatype;\n },\n },\n // Renders one comment thread from its subdocument url. It's mounted\n // explicitly by `CommentsView` via `<patchwork-view>`, but now also\n // declares support for the `comment-thread` datatype so it's the tool\n // detected when a thread subdocument is opened on its own.\n {\n type: \"patchwork:tool\",\n id: \"comment-thread\",\n name: \"Comment Thread\",\n supportedDatatypes: [\"comment-thread\"],\n async load() {\n const { renderCommentThread } = await import(\"./main\");\n return renderCommentThread;\n },\n },\n];\n"],"file":"index.js"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tiny-patchwork/comments-view",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite build --watch",
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"sync": "vite build && pushwork sync",
|
|
11
|
+
"register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\""
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@automerge/automerge": "3.3.0-fragments.1",
|
|
15
|
+
"@automerge/automerge-repo": "^2.6.0-subduction.26",
|
|
16
|
+
"@inkandswitch/patchwork-elements": "1.0.0",
|
|
17
|
+
"@inkandswitch/patchwork-filesystem": "^0.0.8",
|
|
18
|
+
"@inkandswitch/patchwork-plugins": "^0.0.11",
|
|
19
|
+
"@inkandswitch/patchwork-providers": "0.3.0",
|
|
20
|
+
"@inkandswitch/patchwork-providers-solid": "0.2.3",
|
|
21
|
+
"cute.txt": "^0.0.7",
|
|
22
|
+
"solid-automerge": "^2.0.0",
|
|
23
|
+
"solid-js": "^1.9.9"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@eslint/js": "^9.37.0",
|
|
27
|
+
"@inkandswitch/patchwork-bootloader": "^0.2.8",
|
|
28
|
+
"@typescript-eslint/parser": "^8.40.0",
|
|
29
|
+
"eslint": "^9.34.0",
|
|
30
|
+
"globals": "^16.4.0",
|
|
31
|
+
"typescript-eslint": "^8.41.0",
|
|
32
|
+
"vite": "^7.1.9",
|
|
33
|
+
"vite-plugin-css-injected-by-js": "^3.5.2",
|
|
34
|
+
"vite-plugin-solid": "^2.11.10"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const DraftDatatype = {
|
|
2
|
+
init(doc) {
|
|
3
|
+
doc["@patchwork"] = { type: "draft" };
|
|
4
|
+
doc.drafts = [];
|
|
5
|
+
doc.clones = {};
|
|
6
|
+
},
|
|
7
|
+
getTitle() {
|
|
8
|
+
return "Draft";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
DraftDatatype
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=DraftDatatype-Dn8VF6oC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DraftDatatype-Dn8VF6oC.js","sources":["../../src/DraftDatatype.ts"],"sourcesContent":["import type { DatatypeImplementation } from \"@inkandswitch/patchwork-plugins\";\n\nimport type { DraftDoc } from \"./draft-types.js\";\n\nexport const DraftDatatype: DatatypeImplementation<DraftDoc> = {\n init(doc: DraftDoc) {\n doc[\"@patchwork\"] = { type: \"draft\" };\n doc.drafts = [];\n doc.clones = {};\n },\n getTitle() {\n return \"Draft\";\n },\n};\n"],"names":[],"mappings":"AAIO,MAAM,gBAAkD;AAAA,EAC7D,KAAK,KAAe;AAClB,QAAI,YAAY,IAAI,EAAE,MAAM,QAAA;AAC5B,QAAI,SAAS,CAAA;AACb,QAAI,SAAS,CAAA;AAAA,EACf;AAAA,EACA,WAAW;AACT,WAAO;AAAA,EACT;AACF;"}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { isValidAutomergeUrl, encodeHeads } from "@automerge/automerge-repo";
|
|
2
|
+
import { a as accept } from "./index-DAqs20jZ.js";
|
|
3
|
+
import { c as canonicalUrl, S as SKIPPED_DATATYPES } from "./clone-policy-D4XOfZxs.js";
|
|
4
|
+
const ROOT_DOC_SELECTOR = "draft:root-doc";
|
|
5
|
+
const CHECKED_OUT_SELECTOR = "draft:checked-out";
|
|
6
|
+
const DRAFT_LIST_SELECTOR = "draft:list";
|
|
7
|
+
const BASELINE_SELECTOR = "draft:baseline";
|
|
8
|
+
const ATTR_DOC_URL = "doc-url";
|
|
9
|
+
const EMPTY_HEADS = encodeHeads([]);
|
|
10
|
+
const DraftListProvider = (element) => {
|
|
11
|
+
const rawUrl = element.getAttribute(ATTR_DOC_URL);
|
|
12
|
+
if (!rawUrl || !isValidAutomergeUrl(rawUrl)) {
|
|
13
|
+
console.warn(
|
|
14
|
+
`[drafts] <patchwork-view component="patchwork-draft-list-provider"> is missing a valid ${ATTR_DOC_URL} attribute (got ${JSON.stringify(rawUrl)})`
|
|
15
|
+
);
|
|
16
|
+
return () => {
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const docUrl = rawUrl;
|
|
20
|
+
const maybeRepo = "repo" in window ? window.repo : void 0;
|
|
21
|
+
if (!maybeRepo) {
|
|
22
|
+
console.warn(
|
|
23
|
+
"[drafts] window.repo is not set; draft-list provider disabled"
|
|
24
|
+
);
|
|
25
|
+
return () => {
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const repo = maybeRepo;
|
|
29
|
+
let hostDocHandle = null;
|
|
30
|
+
let checkedOutHandle = null;
|
|
31
|
+
const trackedDrafts = /* @__PURE__ */ new Map();
|
|
32
|
+
let mainDraftHandle = null;
|
|
33
|
+
const pendingCheckedOutSubscribers = /* @__PURE__ */ new Set();
|
|
34
|
+
const baselineSubscribers = /* @__PURE__ */ new Map();
|
|
35
|
+
const listSubscribers = /* @__PURE__ */ new Set();
|
|
36
|
+
let orderedDraftUrls = [];
|
|
37
|
+
let draftList = {
|
|
38
|
+
main: { url: docUrl, members: [], childCount: 0, name: null },
|
|
39
|
+
drafts: []
|
|
40
|
+
};
|
|
41
|
+
const mountCounts = /* @__PURE__ */ new Map();
|
|
42
|
+
const skipVerdicts = /* @__PURE__ */ new Map();
|
|
43
|
+
let disposed = false;
|
|
44
|
+
let rewalkInFlight = false;
|
|
45
|
+
let rewalkPending = false;
|
|
46
|
+
const onTrackedChange = () => {
|
|
47
|
+
scheduleRewalk();
|
|
48
|
+
recomputeList();
|
|
49
|
+
notifyBaselines();
|
|
50
|
+
};
|
|
51
|
+
const onHostDocChange = () => scheduleRewalk();
|
|
52
|
+
const onCheckedOutChange = () => {
|
|
53
|
+
notifyBaselines();
|
|
54
|
+
};
|
|
55
|
+
const onMounted = (event) => {
|
|
56
|
+
const detail = event.detail;
|
|
57
|
+
if (!("url" in detail)) return;
|
|
58
|
+
const url = canonicalUrl(detail.url);
|
|
59
|
+
mountCounts.set(url, (mountCounts.get(url) ?? 0) + 1);
|
|
60
|
+
ensureSkipVerdict(url);
|
|
61
|
+
syncMainDraftClones();
|
|
62
|
+
recomputeList();
|
|
63
|
+
};
|
|
64
|
+
const onUnmounted = (event) => {
|
|
65
|
+
const detail = event.detail;
|
|
66
|
+
if (!("url" in detail)) return;
|
|
67
|
+
const url = canonicalUrl(detail.url);
|
|
68
|
+
const count = mountCounts.get(url) ?? 0;
|
|
69
|
+
if (count <= 1) mountCounts.delete(url);
|
|
70
|
+
else mountCounts.set(url, count - 1);
|
|
71
|
+
recomputeList();
|
|
72
|
+
};
|
|
73
|
+
const ready = (async () => {
|
|
74
|
+
const handle = await repo.find(docUrl);
|
|
75
|
+
if (disposed) return;
|
|
76
|
+
hostDocHandle = handle;
|
|
77
|
+
checkedOutHandle = repo.create({ checkedOut: null });
|
|
78
|
+
checkedOutHandle.on("change", onCheckedOutChange);
|
|
79
|
+
const checkedOutUrl = checkedOutHandle.url;
|
|
80
|
+
for (const respond of pendingCheckedOutSubscribers) {
|
|
81
|
+
respond(checkedOutUrl);
|
|
82
|
+
}
|
|
83
|
+
pendingCheckedOutSubscribers.clear();
|
|
84
|
+
notifyBaselines();
|
|
85
|
+
handle.on("change", onHostDocChange);
|
|
86
|
+
scheduleRewalk();
|
|
87
|
+
recomputeList();
|
|
88
|
+
})();
|
|
89
|
+
ready.catch((err) => {
|
|
90
|
+
console.error(`[drafts] failed to initialize draft-list provider:`, err);
|
|
91
|
+
});
|
|
92
|
+
const onSubscribe = (event) => {
|
|
93
|
+
const { type } = event.detail.selector;
|
|
94
|
+
if (type === ROOT_DOC_SELECTOR) {
|
|
95
|
+
accept(event, (respond) => {
|
|
96
|
+
respond(docUrl);
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (type === CHECKED_OUT_SELECTOR) {
|
|
101
|
+
accept(event, (respond) => {
|
|
102
|
+
if (checkedOutHandle) {
|
|
103
|
+
respond(checkedOutHandle.url);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
pendingCheckedOutSubscribers.add(respond);
|
|
107
|
+
return () => pendingCheckedOutSubscribers.delete(respond);
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (type === DRAFT_LIST_SELECTOR) {
|
|
112
|
+
accept(event, (respond) => {
|
|
113
|
+
respond(draftList);
|
|
114
|
+
listSubscribers.add(respond);
|
|
115
|
+
return () => listSubscribers.delete(respond);
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (type === BASELINE_SELECTOR) {
|
|
120
|
+
const rawTarget = event.detail.selector.url;
|
|
121
|
+
if (typeof rawTarget !== "string" || !isValidAutomergeUrl(rawTarget)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const target = canonicalUrl(rawTarget);
|
|
125
|
+
accept(event, (respond) => {
|
|
126
|
+
respond(currentBaseline(target));
|
|
127
|
+
let set = baselineSubscribers.get(target);
|
|
128
|
+
if (!set) baselineSubscribers.set(target, set = /* @__PURE__ */ new Set());
|
|
129
|
+
set.add(respond);
|
|
130
|
+
return () => {
|
|
131
|
+
set.delete(respond);
|
|
132
|
+
if (set.size === 0) baselineSubscribers.delete(target);
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
element.addEventListener("patchwork:subscribe", onSubscribe);
|
|
139
|
+
element.addEventListener("patchwork:mounted", onMounted);
|
|
140
|
+
element.addEventListener("patchwork:unmounted", onUnmounted);
|
|
141
|
+
return () => {
|
|
142
|
+
disposed = true;
|
|
143
|
+
element.removeEventListener("patchwork:subscribe", onSubscribe);
|
|
144
|
+
element.removeEventListener("patchwork:mounted", onMounted);
|
|
145
|
+
element.removeEventListener("patchwork:unmounted", onUnmounted);
|
|
146
|
+
if (hostDocHandle) hostDocHandle.off("change", onHostDocChange);
|
|
147
|
+
if (mainDraftHandle) mainDraftHandle.off("change", onTrackedChange);
|
|
148
|
+
for (const [, h] of trackedDrafts) h.off("change", onTrackedChange);
|
|
149
|
+
mainDraftHandle = null;
|
|
150
|
+
trackedDrafts.clear();
|
|
151
|
+
pendingCheckedOutSubscribers.clear();
|
|
152
|
+
listSubscribers.clear();
|
|
153
|
+
baselineSubscribers.clear();
|
|
154
|
+
mountCounts.clear();
|
|
155
|
+
skipVerdicts.clear();
|
|
156
|
+
if (checkedOutHandle) {
|
|
157
|
+
checkedOutHandle.off("change", onCheckedOutChange);
|
|
158
|
+
repo.delete(checkedOutHandle.url);
|
|
159
|
+
}
|
|
160
|
+
checkedOutHandle = null;
|
|
161
|
+
hostDocHandle = null;
|
|
162
|
+
};
|
|
163
|
+
function scheduleRewalk() {
|
|
164
|
+
if (disposed) return;
|
|
165
|
+
if (!hostDocHandle || !checkedOutHandle) return;
|
|
166
|
+
if (rewalkInFlight) {
|
|
167
|
+
rewalkPending = true;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
rewalkInFlight = true;
|
|
171
|
+
const liveCheckedOut = checkedOutHandle;
|
|
172
|
+
void (async () => {
|
|
173
|
+
try {
|
|
174
|
+
const mainDraft = await ensureMainDraftTracked();
|
|
175
|
+
if (disposed) return;
|
|
176
|
+
const roots = (mainDraft?.doc()?.drafts ?? []).filter(
|
|
177
|
+
isValidAutomergeUrl
|
|
178
|
+
);
|
|
179
|
+
const allDrafts = await collectAllDrafts(
|
|
180
|
+
repo,
|
|
181
|
+
roots,
|
|
182
|
+
trackedDrafts,
|
|
183
|
+
onTrackedChange
|
|
184
|
+
);
|
|
185
|
+
if (disposed) return;
|
|
186
|
+
orderedDraftUrls = allDrafts;
|
|
187
|
+
const selected = liveCheckedOut.doc()?.checkedOut ?? null;
|
|
188
|
+
if (selected && !allDrafts.includes(selected)) {
|
|
189
|
+
liveCheckedOut.change((d) => {
|
|
190
|
+
d.checkedOut = null;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
console.error("[drafts] rewalk failed:", err);
|
|
195
|
+
} finally {
|
|
196
|
+
rewalkInFlight = false;
|
|
197
|
+
recomputeList();
|
|
198
|
+
if (rewalkPending) {
|
|
199
|
+
rewalkPending = false;
|
|
200
|
+
scheduleRewalk();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
}
|
|
205
|
+
function recomputeList() {
|
|
206
|
+
if (disposed) return;
|
|
207
|
+
const next = computeList();
|
|
208
|
+
if (draftListsEqual(draftList, next)) return;
|
|
209
|
+
draftList = next;
|
|
210
|
+
for (const respond of listSubscribers) respond(next);
|
|
211
|
+
}
|
|
212
|
+
function computeList() {
|
|
213
|
+
const drafts = [];
|
|
214
|
+
for (const url of orderedDraftUrls) {
|
|
215
|
+
const doc = trackedDrafts.get(url)?.doc();
|
|
216
|
+
if (!doc || doc.mergedAt !== void 0) continue;
|
|
217
|
+
drafts.push({
|
|
218
|
+
url,
|
|
219
|
+
members: clonesToMembers(doc.clones),
|
|
220
|
+
childCount: doc.drafts.length,
|
|
221
|
+
name: doc.name ?? null
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return { main: computeMainSummary(), drafts };
|
|
225
|
+
}
|
|
226
|
+
function computeMainSummary() {
|
|
227
|
+
const url = mainDraftHandle?.url ?? docUrl;
|
|
228
|
+
const childCount = mainDraftHandle?.doc()?.drafts.length ?? 0;
|
|
229
|
+
const name = mainDraftHandle?.doc()?.name ?? null;
|
|
230
|
+
const mainClones = mainDraftHandle?.doc()?.clones;
|
|
231
|
+
if (mainClones && Object.keys(mainClones).length > 0) {
|
|
232
|
+
return { url, members: clonesToMembers(mainClones), childCount, name };
|
|
233
|
+
}
|
|
234
|
+
const members = [...mountCounts.keys()].filter((u) => skipVerdicts.get(u) !== true).map((u) => ({ url: u, cloneUrl: null, clonedAt: null })).sort(byMemberUrl);
|
|
235
|
+
return { url, members, childCount, name };
|
|
236
|
+
}
|
|
237
|
+
function currentBaseline(target) {
|
|
238
|
+
const doc = checkedOutHandle?.doc();
|
|
239
|
+
const entry = doc?.at?.[target];
|
|
240
|
+
if (entry) return { heads: entry.from ?? null };
|
|
241
|
+
const checkedOut = doc?.checkedOut;
|
|
242
|
+
if (checkedOut) {
|
|
243
|
+
const clonedAt = trackedDrafts.get(checkedOut)?.doc()?.clones?.[target]?.clonedAt;
|
|
244
|
+
return { heads: clonedAt ?? null };
|
|
245
|
+
}
|
|
246
|
+
return { heads: null };
|
|
247
|
+
}
|
|
248
|
+
function notifyBaselines() {
|
|
249
|
+
for (const [target, set] of baselineSubscribers) {
|
|
250
|
+
const baseline = currentBaseline(target);
|
|
251
|
+
for (const respond of [...set]) respond(baseline);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function ensureSkipVerdict(url) {
|
|
255
|
+
if (skipVerdicts.has(url)) return;
|
|
256
|
+
void (async () => {
|
|
257
|
+
try {
|
|
258
|
+
const handle = await repo.find(url);
|
|
259
|
+
if (disposed) return;
|
|
260
|
+
const type = handle.doc()?.["@patchwork"]?.type;
|
|
261
|
+
const skipped = type != null && SKIPPED_DATATYPES.has(type);
|
|
262
|
+
if (skipVerdicts.get(url) === skipped) return;
|
|
263
|
+
skipVerdicts.set(url, skipped);
|
|
264
|
+
syncMainDraftClones();
|
|
265
|
+
recomputeList();
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
})();
|
|
269
|
+
}
|
|
270
|
+
async function ensureMainDraftTracked() {
|
|
271
|
+
if (!hostDocHandle) return null;
|
|
272
|
+
const mainDraftUrl = hostDocHandle.doc()?.["@patchwork"]?.mainDraftUrl;
|
|
273
|
+
if (!mainDraftUrl || !isValidAutomergeUrl(mainDraftUrl)) return null;
|
|
274
|
+
if (mainDraftHandle && mainDraftHandle.url === mainDraftUrl) {
|
|
275
|
+
return mainDraftHandle;
|
|
276
|
+
}
|
|
277
|
+
if (mainDraftHandle) mainDraftHandle.off("change", onTrackedChange);
|
|
278
|
+
const handle = await repo.find(mainDraftUrl);
|
|
279
|
+
if (disposed) return null;
|
|
280
|
+
mainDraftHandle = handle;
|
|
281
|
+
handle.on("change", onTrackedChange);
|
|
282
|
+
syncMainDraftClones();
|
|
283
|
+
return handle;
|
|
284
|
+
}
|
|
285
|
+
function syncMainDraftClones() {
|
|
286
|
+
if (disposed || !mainDraftHandle) return;
|
|
287
|
+
const existing = mainDraftHandle.doc()?.clones ?? {};
|
|
288
|
+
const toAdd = [...mountCounts.keys()].filter(
|
|
289
|
+
(url) => skipVerdicts.get(url) === false && !existing[url]
|
|
290
|
+
);
|
|
291
|
+
if (toAdd.length === 0) return;
|
|
292
|
+
mainDraftHandle.change((d) => {
|
|
293
|
+
for (const url of toAdd) {
|
|
294
|
+
if (!d.clones[url]) {
|
|
295
|
+
d.clones[url] = { cloneUrl: url, clonedAt: EMPTY_HEADS };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
async function collectAllDrafts(repo, roots, tracked, onNewChange) {
|
|
302
|
+
const visited = /* @__PURE__ */ new Set();
|
|
303
|
+
const order = [];
|
|
304
|
+
const queue = [...roots];
|
|
305
|
+
while (queue.length) {
|
|
306
|
+
const url = queue.shift();
|
|
307
|
+
if (visited.has(url)) continue;
|
|
308
|
+
visited.add(url);
|
|
309
|
+
order.push(url);
|
|
310
|
+
let h = tracked.get(url);
|
|
311
|
+
if (!h) {
|
|
312
|
+
h = await repo.find(url);
|
|
313
|
+
tracked.set(url, h);
|
|
314
|
+
h.on("change", onNewChange);
|
|
315
|
+
}
|
|
316
|
+
const drafts = h.doc()?.drafts ?? [];
|
|
317
|
+
for (const child of drafts) {
|
|
318
|
+
if (isValidAutomergeUrl(child)) queue.push(child);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return order;
|
|
322
|
+
}
|
|
323
|
+
function clonesToMembers(clones) {
|
|
324
|
+
return Object.entries(clones).map(([url, entry]) => ({
|
|
325
|
+
url,
|
|
326
|
+
cloneUrl: entry.cloneUrl,
|
|
327
|
+
clonedAt: entry.clonedAt
|
|
328
|
+
})).sort(byMemberUrl);
|
|
329
|
+
}
|
|
330
|
+
function draftListsEqual(a, b) {
|
|
331
|
+
if (!summariesEqual(a.main, b.main)) return false;
|
|
332
|
+
if (a.drafts.length !== b.drafts.length) return false;
|
|
333
|
+
for (let i = 0; i < a.drafts.length; i++) {
|
|
334
|
+
if (!summariesEqual(a.drafts[i], b.drafts[i])) return false;
|
|
335
|
+
}
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
function summariesEqual(a, b) {
|
|
339
|
+
return a.url === b.url && a.childCount === b.childCount && a.name === b.name && memberListsEqual(a.members, b.members);
|
|
340
|
+
}
|
|
341
|
+
function byMemberUrl(a, b) {
|
|
342
|
+
return a.url < b.url ? -1 : a.url > b.url ? 1 : 0;
|
|
343
|
+
}
|
|
344
|
+
function memberListsEqual(a, b) {
|
|
345
|
+
if (a.length !== b.length) return false;
|
|
346
|
+
for (let i = 0; i < a.length; i++) {
|
|
347
|
+
if (a[i].url !== b[i].url) return false;
|
|
348
|
+
if (a[i].cloneUrl !== b[i].cloneUrl) return false;
|
|
349
|
+
if (!sameHeads(a[i].clonedAt, b[i].clonedAt)) return false;
|
|
350
|
+
}
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
function sameHeads(a, b) {
|
|
354
|
+
if (a === b) return true;
|
|
355
|
+
if (!a || !b || a.length !== b.length) return false;
|
|
356
|
+
const set = new Set(b);
|
|
357
|
+
return a.every((h) => set.has(h));
|
|
358
|
+
}
|
|
359
|
+
export {
|
|
360
|
+
DraftListProvider
|
|
361
|
+
};
|
|
362
|
+
//# sourceMappingURL=DraftListProvider-DVhUGU1x.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DraftListProvider-DVhUGU1x.js","sources":["../../src/providers/DraftListProvider.ts"],"sourcesContent":["import {\n encodeHeads,\n isValidAutomergeUrl,\n type AutomergeUrl,\n type DocHandle,\n type Repo,\n type UrlHeads,\n} from \"@automerge/automerge-repo\";\nimport { accept, type SubscribeEvent } from \"@inkandswitch/patchwork-providers\";\nimport type {\n MountedEvent,\n UnmountedEvent,\n} from \"@inkandswitch/patchwork-elements\";\n\nimport type {\n Baseline,\n CheckedOutDraft,\n CloneEntry,\n DraftDoc,\n DraftList,\n DraftMemberDoc,\n DraftSummary,\n HasDrafts,\n} from \"../draft-types.js\";\nimport { SKIPPED_DATATYPES, canonicalUrl } from \"../clone-policy.js\";\n\nconst ROOT_DOC_SELECTOR = \"draft:root-doc\";\nconst CHECKED_OUT_SELECTOR = \"draft:checked-out\";\nconst DRAFT_LIST_SELECTOR = \"draft:list\";\nconst BASELINE_SELECTOR = \"draft:baseline\";\n\nconst ATTR_DOC_URL = \"doc-url\";\n\n// Fork point recorded for the main draft's identity clones: empty heads means\n// \"from the start\", so `getChangesMetaSince(doc, [])` yields the full history.\nconst EMPTY_HEADS: UrlHeads = encodeHeads([]);\n\n// Mounts on a document URL and exposes that document's draft state via three\n// subscriptions:\n// - `draft:root-doc` → AutomergeUrl of the doc this provider is on\n// - `draft:checked-out` → AutomergeUrl of the ephemeral, writeable\n// CheckedOutDraft doc; holds only the selection (`checkedOut = null` = main)\n// - `draft:list` → DraftList: the read-only main entry plus one\n// `DraftSummary` per non-merged draft, each carrying its member docs (on a\n// draft, the forked docs from `DraftDoc.clones`; on main, the main draft's\n// identity clones, or — before the first draft — the docs mounted beneath\n// this provider observed via `patchwork:mounted`, fork fields `null`).\n//\n// Consumers recover the live `DocHandle`s from the realm-local `window.repo`,\n// so member entries carry only plain `AutomergeUrl`s. The link from a host doc\n// to its drafts is `@patchwork.mainDraftUrl` → the main draft, whose `drafts`\n// roots the tree; each `DraftDoc` may have its own sub-drafts via\n// `DraftDoc.drafts`.\nexport const DraftListProvider = (element: HTMLElement) => {\n const rawUrl = element.getAttribute(ATTR_DOC_URL);\n if (!rawUrl || !isValidAutomergeUrl(rawUrl)) {\n console.warn(\n `[drafts] <patchwork-view component=\"patchwork-draft-list-provider\"> ` +\n `is missing a valid ${ATTR_DOC_URL} attribute (got ${JSON.stringify(rawUrl)})`\n );\n return () => {};\n }\n const docUrl: AutomergeUrl = rawUrl;\n\n const maybeRepo = \"repo\" in window ? window.repo : undefined;\n if (!maybeRepo) {\n console.warn(\n \"[drafts] window.repo is not set; draft-list provider disabled\"\n );\n return () => {};\n }\n const repo: Repo = maybeRepo;\n\n let hostDocHandle: DocHandle<HasDrafts> | null = null;\n let checkedOutHandle: DocHandle<CheckedOutDraft> | null = null;\n const trackedDrafts = new Map<AutomergeUrl, DocHandle<DraftDoc>>();\n // The host doc's single main draft (bookkeeping only). Resolved lazily from\n // `@patchwork.mainDraftUrl`; its `drafts` roots the draft tree and its\n // identity `clones` back the \"main\" member list.\n let mainDraftHandle: DocHandle<DraftDoc> | null = null;\n\n // `draft:checked-out` subscribers that arrived before the ephemeral\n // CheckedOutDraft doc was created; flushed once it exists.\n const pendingCheckedOutSubscribers = new Set<(url: AutomergeUrl) => void>();\n\n // `draft:baseline` subscribers, keyed by canonical target url. This provider\n // is the sole answerer (the overlay no longer claims it), serving the\n // checkpoint's per-doc `from` when pinned and the checked-out draft's\n // fork point otherwise (see `currentBaseline`). Re-emitted whenever the\n // checkout doc or a tracked draft's clones change.\n const baselineSubscribers = new Map<\n AutomergeUrl,\n Set<(baseline: Baseline) => void>\n >();\n\n // `draft:list` bookkeeping: the last computed list, its live subscribers, and\n // the draft order from the most recent rewalk.\n const listSubscribers = new Set<(list: DraftList) => void>();\n let orderedDraftUrls: AutomergeUrl[] = [];\n let draftList: DraftList = {\n main: { url: docUrl, members: [], childCount: 0, name: null },\n drafts: [],\n };\n // Main-case membership: docs mounted beneath this provider, ref-counted so a\n // doc shown in several views is only dropped on its last unmount. Populated\n // even while a draft is selected (where it goes unused) so switching back to\n // main is instant.\n const mountCounts = new Map<AutomergeUrl, number>();\n // Cached \"is this an app-global datatype we skip?\" verdict per mounted url,\n // resolved lazily since reading `@patchwork.type` means loading the doc.\n // Absent = unresolved, treated as not-skipped (visible) until known.\n const skipVerdicts = new Map<AutomergeUrl, boolean>();\n\n let disposed = false;\n let rewalkInFlight = false;\n let rewalkPending = false;\n // A tracked draft changing can mean either its sub-draft list moved (needs a\n // rewalk) or its clone map grew (needs a list recompute), so do both. A new\n // clone also gives a checked-out draft a fork-point baseline, so re-publish.\n const onTrackedChange = () => {\n scheduleRewalk();\n recomputeList();\n notifyBaselines();\n };\n const onHostDocChange = () => scheduleRewalk();\n // The checkout doc changed: its `at` checkpoint may have been set, cleared, or\n // moved, so re-publish every live `draft:baseline` subscriber.\n const onCheckedOutChange = () => {\n notifyBaselines();\n };\n\n const onMounted = (event: MountedEvent) => {\n const detail = event.detail;\n if (!(\"url\" in detail)) return;\n const url = canonicalUrl(detail.url);\n mountCounts.set(url, (mountCounts.get(url) ?? 0) + 1);\n ensureSkipVerdict(url);\n syncMainDraftClones();\n recomputeList();\n };\n\n const onUnmounted = (event: UnmountedEvent) => {\n const detail = event.detail;\n if (!(\"url\" in detail)) return;\n const url = canonicalUrl(detail.url);\n const count = mountCounts.get(url) ?? 0;\n if (count <= 1) mountCounts.delete(url);\n else mountCounts.set(url, count - 1);\n recomputeList();\n };\n\n const ready: Promise<void> = (async () => {\n const handle = await repo.find<HasDrafts>(docUrl);\n if (disposed) return;\n hostDocHandle = handle;\n\n // Eagerly create the ephemeral CheckedOutDraft so the sidebar can render\n // its \"Main\" card and write `checkedOut` even before any drafts exist on\n // the host doc.\n checkedOutHandle = repo.create<CheckedOutDraft>({ checkedOut: null });\n checkedOutHandle.on(\"change\", onCheckedOutChange);\n const checkedOutUrl = checkedOutHandle.url;\n for (const respond of pendingCheckedOutSubscribers) {\n respond(checkedOutUrl);\n }\n pendingCheckedOutSubscribers.clear();\n // A checkpoint may already have synced in before this provider mounted.\n notifyBaselines();\n\n handle.on(\"change\", onHostDocChange);\n scheduleRewalk();\n recomputeList();\n })();\n ready.catch((err) => {\n console.error(`[drafts] failed to initialize draft-list provider:`, err);\n });\n\n const onSubscribe = (event: SubscribeEvent) => {\n const { type } = event.detail.selector;\n\n if (type === ROOT_DOC_SELECTOR) {\n accept<AutomergeUrl>(event, (respond) => {\n respond(docUrl);\n });\n return;\n }\n\n if (type === CHECKED_OUT_SELECTOR) {\n accept<AutomergeUrl>(event, (respond) => {\n if (checkedOutHandle) {\n respond(checkedOutHandle.url);\n return;\n }\n pendingCheckedOutSubscribers.add(respond);\n return () => pendingCheckedOutSubscribers.delete(respond);\n });\n return;\n }\n\n if (type === DRAFT_LIST_SELECTOR) {\n // `draft:list` answers with a DraftList *object*, never an AutomergeUrl, so\n // consumers must use `subscribe` (not `subscribeDoc`, which would feed this\n // object into `repo.find` and crash with \"Invalid AutomergeUrl\").\n accept<DraftList>(event, (respond) => {\n respond(draftList);\n listSubscribers.add(respond);\n return () => listSubscribers.delete(respond);\n });\n return;\n }\n\n if (type === BASELINE_SELECTOR) {\n // Sole answerer for `draft:baseline` (the overlay no longer claims it):\n // serves the pinned checkpoint's `from` or the checked-out draft's fork\n // point for `target` (see `currentBaseline`).\n const rawTarget = (event.detail.selector as { url?: unknown }).url;\n if (typeof rawTarget !== \"string\" || !isValidAutomergeUrl(rawTarget)) {\n return;\n }\n const target = canonicalUrl(rawTarget);\n accept<Baseline>(event, (respond) => {\n respond(currentBaseline(target));\n let set = baselineSubscribers.get(target);\n if (!set) baselineSubscribers.set(target, (set = new Set()));\n set.add(respond);\n return () => {\n set!.delete(respond);\n if (set!.size === 0) baselineSubscribers.delete(target);\n };\n });\n return;\n }\n\n };\n\n element.addEventListener(\"patchwork:subscribe\", onSubscribe);\n element.addEventListener(\"patchwork:mounted\", onMounted);\n element.addEventListener(\"patchwork:unmounted\", onUnmounted);\n\n return () => {\n disposed = true;\n element.removeEventListener(\"patchwork:subscribe\", onSubscribe);\n element.removeEventListener(\"patchwork:mounted\", onMounted);\n element.removeEventListener(\"patchwork:unmounted\", onUnmounted);\n if (hostDocHandle) hostDocHandle.off(\"change\", onHostDocChange);\n if (mainDraftHandle) mainDraftHandle.off(\"change\", onTrackedChange);\n for (const [, h] of trackedDrafts) h.off(\"change\", onTrackedChange);\n mainDraftHandle = null;\n trackedDrafts.clear();\n pendingCheckedOutSubscribers.clear();\n listSubscribers.clear();\n baselineSubscribers.clear();\n mountCounts.clear();\n skipVerdicts.clear();\n if (checkedOutHandle) {\n checkedOutHandle.off(\"change\", onCheckedOutChange);\n repo.delete(checkedOutHandle.url);\n }\n checkedOutHandle = null;\n hostDocHandle = null;\n };\n\n function scheduleRewalk(): void {\n if (disposed) return;\n if (!hostDocHandle || !checkedOutHandle) return;\n if (rewalkInFlight) {\n rewalkPending = true;\n return;\n }\n rewalkInFlight = true;\n const liveCheckedOut = checkedOutHandle;\n void (async () => {\n try {\n // Drafts hang off the main draft (`mainDraft.drafts`), which is created\n // on the first draft; until then there are none.\n const mainDraft = await ensureMainDraftTracked();\n if (disposed) return;\n const roots = (mainDraft?.doc()?.drafts ?? []).filter(\n isValidAutomergeUrl\n );\n const allDrafts = await collectAllDrafts(\n repo,\n roots,\n trackedDrafts,\n onTrackedChange\n );\n if (disposed) return;\n orderedDraftUrls = allDrafts;\n\n // Reconcile the checkout pointer: if the checked-out draft is gone\n // (merged or detached), fall back to main.\n const selected = liveCheckedOut.doc()?.checkedOut ?? null;\n if (selected && !allDrafts.includes(selected)) {\n liveCheckedOut.change((d) => {\n d.checkedOut = null;\n });\n }\n } catch (err) {\n console.error(\"[drafts] rewalk failed:\", err);\n } finally {\n rewalkInFlight = false;\n // A rewalk may have just started tracking a draft (whose clones won't\n // fire their own change event), so refresh the list.\n recomputeList();\n if (rewalkPending) {\n rewalkPending = false;\n scheduleRewalk();\n }\n }\n })();\n }\n\n // Recompute the `draft:list` value and push it to subscribers when it\n // actually changed.\n function recomputeList(): void {\n if (disposed) return;\n const next = computeList();\n if (draftListsEqual(draftList, next)) return;\n draftList = next;\n for (const respond of listSubscribers) respond(next);\n }\n\n // The full read-only list: the main entry plus one summary per non-merged\n // draft, in rewalk (tree) order.\n function computeList(): DraftList {\n const drafts: DraftSummary[] = [];\n for (const url of orderedDraftUrls) {\n const doc = trackedDrafts.get(url)?.doc();\n if (!doc || doc.mergedAt !== undefined) continue;\n drafts.push({\n url,\n members: clonesToMembers(doc.clones),\n childCount: doc.drafts.length,\n name: doc.name ?? null,\n });\n }\n return { main: computeMainSummary(), drafts };\n }\n\n // Main's summary. Its members come from the main draft's identity clones once\n // it exists; before the first draft is created (no main draft) we fall back to\n // the docs mounted beneath us, minus the app-global datatypes the overlay\n // would never fork. Members are sorted by url so the diff above is positional.\n function computeMainSummary(): DraftSummary {\n const url = mainDraftHandle?.url ?? docUrl;\n const childCount = mainDraftHandle?.doc()?.drafts.length ?? 0;\n const name = mainDraftHandle?.doc()?.name ?? null;\n\n const mainClones = mainDraftHandle?.doc()?.clones;\n if (mainClones && Object.keys(mainClones).length > 0) {\n return { url, members: clonesToMembers(mainClones), childCount, name };\n }\n\n const members = [...mountCounts.keys()]\n .filter((u) => skipVerdicts.get(u) !== true)\n .map((u) => ({ url: u, cloneUrl: null, clonedAt: null }))\n .sort(byMemberUrl);\n return { url, members, childCount, name };\n }\n\n // The diff baseline for `target`, authoritative for both main and drafts:\n // - a pinned checkpoint honors that doc's `from` exactly (`null` = no diff);\n // - otherwise, on a draft, the doc diffs against its clone's fork point;\n // - otherwise (main, no pin) there is no baseline.\n function currentBaseline(target: AutomergeUrl): Baseline {\n const doc = checkedOutHandle?.doc();\n const entry = doc?.at?.[target];\n if (entry) return { heads: entry.from ?? null };\n\n const checkedOut = doc?.checkedOut;\n if (checkedOut) {\n const clonedAt = trackedDrafts.get(checkedOut)?.doc()?.clones?.[target]\n ?.clonedAt;\n return { heads: clonedAt ?? null };\n }\n return { heads: null };\n }\n\n function notifyBaselines(): void {\n for (const [target, set] of baselineSubscribers) {\n const baseline = currentBaseline(target);\n for (const respond of [...set]) respond(baseline);\n }\n }\n\n // Resolve (once, cached) whether a mounted doc is an app-global datatype we\n // exclude from the main-case membership. On failure we leave it unresolved,\n // so the doc stays visible — mirroring the overlay's \"fall back to forking\".\n function ensureSkipVerdict(url: AutomergeUrl): void {\n if (skipVerdicts.has(url)) return;\n void (async () => {\n try {\n const handle = await repo.find<HasDrafts>(url);\n if (disposed) return;\n const type = handle.doc()?.[\"@patchwork\"]?.type;\n const skipped = type != null && SKIPPED_DATATYPES.has(type);\n if (skipVerdicts.get(url) === skipped) return;\n skipVerdicts.set(url, skipped);\n // A now-confirmed not-skipped doc may belong in the main draft.\n syncMainDraftClones();\n recomputeList();\n } catch {\n // Leave unresolved: the doc keeps showing up, which is the safe default.\n }\n })();\n }\n\n // Resolve and start tracking the host doc's main draft, if any. Returns the\n // handle, or null when the host doc has no `mainDraftUrl` yet. Re-resolves\n // when the pointer changes and attaches `onTrackedChange` so the main draft's\n // `drafts` (tree shape) and `clones` (main membership) stay live.\n async function ensureMainDraftTracked(): Promise<DocHandle<DraftDoc> | null> {\n if (!hostDocHandle) return null;\n const mainDraftUrl = hostDocHandle.doc()?.[\"@patchwork\"]?.mainDraftUrl;\n if (!mainDraftUrl || !isValidAutomergeUrl(mainDraftUrl)) return null;\n if (mainDraftHandle && mainDraftHandle.url === mainDraftUrl) {\n return mainDraftHandle;\n }\n if (mainDraftHandle) mainDraftHandle.off(\"change\", onTrackedChange);\n const handle = await repo.find<DraftDoc>(mainDraftUrl);\n if (disposed) return null;\n mainDraftHandle = handle;\n handle.on(\"change\", onTrackedChange);\n syncMainDraftClones();\n return handle;\n }\n\n // Keep the main draft's identity clone map in step with the live mounted set:\n // every confirmed not-skipped mounted doc gets an identity entry (`cloneUrl\n // === url`, empty fork heads). Additive only — entries are never removed, so\n // main's membership (and history) is stable across unmounts. Writes are\n // diffed, so this is a no-op once everything mounted is already recorded.\n function syncMainDraftClones(): void {\n if (disposed || !mainDraftHandle) return;\n const existing = mainDraftHandle.doc()?.clones ?? {};\n const toAdd = [...mountCounts.keys()].filter(\n (url) => skipVerdicts.get(url) === false && !existing[url]\n );\n if (toAdd.length === 0) return;\n mainDraftHandle.change((d) => {\n for (const url of toAdd) {\n if (!d.clones[url]) {\n d.clones[url] = { cloneUrl: url, clonedAt: EMPTY_HEADS };\n }\n }\n });\n }\n};\n\nasync function collectAllDrafts(\n repo: Repo,\n roots: readonly AutomergeUrl[],\n tracked: Map<AutomergeUrl, DocHandle<DraftDoc>>,\n onNewChange: () => void\n): Promise<AutomergeUrl[]> {\n const visited = new Set<AutomergeUrl>();\n const order: AutomergeUrl[] = [];\n const queue: AutomergeUrl[] = [...roots];\n while (queue.length) {\n const url = queue.shift()!;\n if (visited.has(url)) continue;\n visited.add(url);\n order.push(url);\n\n let h = tracked.get(url);\n if (!h) {\n h = await repo.find<DraftDoc>(url);\n tracked.set(url, h);\n h.on(\"change\", onNewChange);\n }\n const drafts = h.doc()?.drafts ?? [];\n for (const child of drafts) {\n if (isValidAutomergeUrl(child)) queue.push(child);\n }\n }\n return order;\n}\n\n// Project a clone map into member-doc entries, sorted by url so the positional\n// equality checks below stay valid.\nfunction clonesToMembers(\n clones: Record<AutomergeUrl, CloneEntry>\n): DraftMemberDoc[] {\n return Object.entries(clones)\n .map(([url, entry]) => ({\n url: url as AutomergeUrl,\n cloneUrl: entry.cloneUrl,\n clonedAt: entry.clonedAt,\n }))\n .sort(byMemberUrl);\n}\n\nfunction draftListsEqual(a: DraftList, b: DraftList): boolean {\n if (!summariesEqual(a.main, b.main)) return false;\n if (a.drafts.length !== b.drafts.length) return false;\n for (let i = 0; i < a.drafts.length; i++) {\n if (!summariesEqual(a.drafts[i], b.drafts[i])) return false;\n }\n return true;\n}\n\nfunction summariesEqual(a: DraftSummary, b: DraftSummary): boolean {\n return (\n a.url === b.url &&\n a.childCount === b.childCount &&\n a.name === b.name &&\n memberListsEqual(a.members, b.members)\n );\n}\n\nfunction byMemberUrl(a: DraftMemberDoc, b: DraftMemberDoc): number {\n return a.url < b.url ? -1 : a.url > b.url ? 1 : 0;\n}\n\nfunction memberListsEqual(a: DraftMemberDoc[], b: DraftMemberDoc[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i].url !== b[i].url) return false;\n if (a[i].cloneUrl !== b[i].cloneUrl) return false;\n if (!sameHeads(a[i].clonedAt, b[i].clonedAt)) return false;\n }\n return true;\n}\n\nfunction sameHeads(a: UrlHeads | null, b: UrlHeads | null): boolean {\n if (a === b) return true;\n if (!a || !b || a.length !== b.length) return false;\n const set = new Set(b);\n return a.every((h) => set.has(h));\n}\n"],"names":[],"mappings":"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"}
|