@lemoncat7/dsh-knowledge 2.3.0 → 2.3.2

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.
Files changed (52) hide show
  1. package/README.md +12 -4
  2. package/docs/architecture.md +1 -1
  3. package/lib/api.d.ts +2 -0
  4. package/lib/api.d.ts.map +1 -1
  5. package/lib/api.js +93 -0
  6. package/lib/api.js.map +1 -1
  7. package/lib/client.js +1 -1
  8. package/lib/client.js.map +1 -1
  9. package/lib/config.d.ts +2 -0
  10. package/lib/config.d.ts.map +1 -1
  11. package/lib/config.js +26 -0
  12. package/lib/config.js.map +1 -1
  13. package/lib/extraction.js +9 -2
  14. package/lib/extraction.js.map +1 -1
  15. package/lib/index.d.ts.map +1 -1
  16. package/lib/index.js +15 -1
  17. package/lib/index.js.map +1 -1
  18. package/lib/notes/domain.d.ts +8 -0
  19. package/lib/notes/domain.d.ts.map +1 -1
  20. package/lib/notes/domain.js.map +1 -1
  21. package/lib/notes/share-import.d.ts +50 -0
  22. package/lib/notes/share-import.d.ts.map +1 -0
  23. package/lib/notes/share-import.js +344 -0
  24. package/lib/notes/share-import.js.map +1 -0
  25. package/lib/notes/share-markdown.d.ts +12 -0
  26. package/lib/notes/share-markdown.d.ts.map +1 -0
  27. package/lib/notes/share-markdown.js +79 -0
  28. package/lib/notes/share-markdown.js.map +1 -0
  29. package/lib/notes/share-page.d.ts +12 -0
  30. package/lib/notes/share-page.d.ts.map +1 -0
  31. package/lib/notes/share-page.js +176 -0
  32. package/lib/notes/share-page.js.map +1 -0
  33. package/lib/notes/store.d.ts +15 -1
  34. package/lib/notes/store.d.ts.map +1 -1
  35. package/lib/notes/store.js +177 -6
  36. package/lib/notes/store.js.map +1 -1
  37. package/lib/web-note-editor-selection.d.ts.map +1 -1
  38. package/lib/web-note-editor-selection.js +23 -0
  39. package/lib/web-note-editor-selection.js.map +1 -1
  40. package/lib/web.d.ts.map +1 -1
  41. package/lib/web.js +7 -6
  42. package/lib/web.js.map +1 -1
  43. package/package.json +2 -2
  44. package/web/app.js +303 -29
  45. package/web/index.html +1 -2
  46. package/web/note-editor.js +64 -64
  47. package/web/styles.css +168 -291
  48. package/lib/web-workspace-effects.d.ts +0 -13
  49. package/lib/web-workspace-effects.d.ts.map +0 -1
  50. package/lib/web-workspace-effects.js +0 -366
  51. package/lib/web-workspace-effects.js.map +0 -1
  52. package/web/workspace-effects.js +0 -16
@@ -0,0 +1,176 @@
1
+ import { renderSharedMarkdown } from './share-markdown.js';
2
+ export function renderNoteSharePage(input) {
3
+ const { share, nodes } = input;
4
+ const baseHref = `${input.apiPrefix.replace(/\/$/, '')}/shared/${encodeURIComponent(share.token)}`;
5
+ const paths = relativePaths(share.node, nodes);
6
+ const selected = input.selectedNode;
7
+ const selectedPath = selected === undefined ? '' : paths.get(selected.id) ?? selected.name;
8
+ const rendered = renderSharedContent(selected ?? share.node, selectedPath || share.node.name, input.selectedText, input.contentTruncated, baseHref);
9
+ const directory = share.node.kind === 'folder'
10
+ ? renderDirectoryPanel(share.node, nodes, baseHref, selected?.id, input.listTruncated === true)
11
+ : '';
12
+ const outline = rendered.outline === undefined ? '' : renderOutlinePanel(rendered.outline);
13
+ const panelClass = directory.length === 0 && outline.length === 0 ? ' is-single' : '';
14
+ const title = share.node.name;
15
+ return `<!doctype html>
16
+ <html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
17
+ <meta name="color-scheme" content="light dark"><meta name="referrer" content="no-referrer"><title>${escapeHtml(title)} · 分享笔记</title>
18
+ <style>${SHARE_PAGE_CSS}</style></head><body>
19
+ <main class="share-shell">
20
+ <header class="share-header"><div class="share-title"><span class="eyebrow">DSH KNOWLEDGE</span><h1>${escapeHtml(title)}</h1><p>${share.node.kind === 'folder' ? `共享目录 · ${Math.max(0, nodes.length - 1)} 个项目` : '共享笔记文档 · 只读'}</p></div><span class="readonly">只读分享</span></header>
21
+ <div class="share-workspace${panelClass}">
22
+ ${directory}
23
+ <section class="share-content">${rendered.html}</section>
24
+ ${outline}
25
+ </div>
26
+ <footer class="share-footer"><span>分享于 ${formatDate(share.createdAt)}</span><span>内容会随原笔记更新</span></footer>
27
+ </main></body></html>`;
28
+ }
29
+ function renderDirectoryPanel(root, nodes, baseHref, selectedId, truncated) {
30
+ const children = childNodes(nodes);
31
+ return `<details class="share-panel directory-panel" open>
32
+ <summary class="panel-toggle">${directoryIcon()}<span class="panel-label">目录</span><span class="panel-count">${Math.max(0, nodes.length - 1)}</span>${chevronIcon()}</summary>
33
+ <nav class="share-tree" aria-label="共享目录">
34
+ <a class="tree-root" href="${escapeAttribute(baseHref)}">${folderIcon()}<span>${escapeHtml(root.name)}</span></a>
35
+ ${renderTreeChildren(root.id, children, baseHref, selectedId, 0)}
36
+ ${truncated ? '<p class="notice">目录内容较多,仅展示前 500 项。</p>' : ''}
37
+ </nav>
38
+ </details>`;
39
+ }
40
+ function renderTreeChildren(parentId, children, baseHref, selectedId, depth) {
41
+ return (children.get(parentId) ?? []).map(node => {
42
+ if (node.kind === 'folder') {
43
+ const descendants = containsNode(node.id, selectedId, children);
44
+ return `<details class="tree-folder"${depth === 0 || descendants ? ' open' : ''}>
45
+ <summary class="tree-item is-folder" style="padding-left:${9 + depth * 14}px">${folderIcon()}<span>${escapeHtml(node.name)}</span>${chevronIcon()}</summary>
46
+ <div class="tree-children">${renderTreeChildren(node.id, children, baseHref, selectedId, depth + 1)}</div>
47
+ </details>`;
48
+ }
49
+ const href = `${baseHref}?note=${encodeURIComponent(node.id)}`;
50
+ const active = node.id === selectedId;
51
+ return `<a class="tree-item is-file${active ? ' is-active' : ''}" style="padding-left:${9 + depth * 14}px" href="${escapeAttribute(href)}"${active ? ' aria-current="page"' : ''}>${fileIcon()}<span>${escapeHtml(node.name)}</span></a>`;
52
+ }).join('');
53
+ }
54
+ function childNodes(nodes) {
55
+ const result = new Map();
56
+ for (const node of nodes) {
57
+ if (node.parentId === null)
58
+ continue;
59
+ const siblings = result.get(node.parentId) ?? [];
60
+ siblings.push(node);
61
+ result.set(node.parentId, siblings);
62
+ }
63
+ for (const siblings of result.values()) {
64
+ siblings.sort((left, right) => {
65
+ if (left.kind === 'folder' && right.kind !== 'folder')
66
+ return -1;
67
+ if (left.kind !== 'folder' && right.kind === 'folder')
68
+ return 1;
69
+ return left.name.localeCompare(right.name, 'zh-CN', { numeric: true });
70
+ });
71
+ }
72
+ return result;
73
+ }
74
+ function containsNode(rootId, selectedId, children) {
75
+ if (selectedId === undefined)
76
+ return false;
77
+ const pending = [...(children.get(rootId) ?? [])];
78
+ while (pending.length > 0) {
79
+ const current = pending.pop();
80
+ if (current === undefined)
81
+ break;
82
+ if (current.id === selectedId)
83
+ return true;
84
+ pending.push(...(children.get(current.id) ?? []));
85
+ }
86
+ return false;
87
+ }
88
+ function renderOutlinePanel(headings) {
89
+ return `<details class="share-panel outline-panel" open>
90
+ <summary class="panel-toggle">${outlineIcon()}<span class="panel-label">大纲</span><span class="panel-count">${headings.length}</span>${chevronIcon()}</summary>
91
+ <nav class="share-outline" aria-label="文档大纲">${headings.length === 0
92
+ ? '<p class="outline-empty">这篇文档还没有标题。</p>'
93
+ : headings.map(heading => `<a href="#${escapeAttribute(heading.id)}" style="padding-left:${8 + Math.min(3, Math.max(0, heading.depth - 1)) * 12}px">${escapeHtml(heading.text)}</a>`).join('')}</nav>
94
+ </details>`;
95
+ }
96
+ function renderSharedContent(node, path, text, truncated, baseHref) {
97
+ if (node.kind === 'folder') {
98
+ return { html: '<div class="empty"><span class="empty-mark" aria-hidden="true"></span><h2>选择一篇文档</h2><p>从目录中选择要阅读的内容。</p></div>' };
99
+ }
100
+ const download = `${baseHref}/content?noteId=${encodeURIComponent(node.id)}&download=1`;
101
+ const heading = `<header class="content-header"><div class="content-title"><span>${escapeHtml(path)}</span><h2>${escapeHtml(node.name)}</h2></div><a class="download" href="${escapeAttribute(download)}">${downloadIcon()}<span>下载</span></a></header>`;
102
+ if (node.mediaType?.startsWith('image/')) {
103
+ const source = `${baseHref}/content?noteId=${encodeURIComponent(node.id)}`;
104
+ return { html: `${heading}<div class="image-stage"><img src="${escapeAttribute(source)}" alt="${escapeAttribute(node.name)}"></div>` };
105
+ }
106
+ if (text !== undefined) {
107
+ const notice = truncated ? '<p class="notice content-notice">文档较长,网页仅显示前 512 KiB;下载可查看完整内容。</p>' : '';
108
+ if (isMarkdown(node)) {
109
+ const markdown = renderSharedMarkdown(text);
110
+ return { html: `${heading}${notice}<article class="document"><div class="markdown-body">${markdown.html}</div></article>`, outline: markdown.headings };
111
+ }
112
+ return { html: `${heading}${notice}<article class="document"><pre class="plain-text">${escapeHtml(text)}</pre></article>` };
113
+ }
114
+ return { html: `${heading}<div class="empty"><span class="file-large" aria-hidden="true"></span><h2>此格式不支持网页预览</h2><p>可以下载后使用本地应用打开。</p><a class="download primary" href="${escapeAttribute(download)}">${downloadIcon()}<span>下载文件</span></a></div>` };
115
+ }
116
+ function isMarkdown(node) {
117
+ const mediaType = node.mediaType?.toLocaleLowerCase() ?? '';
118
+ const name = node.name.toLocaleLowerCase();
119
+ return node.kind === 'document' || mediaType === 'text/markdown' || name.endsWith('.md') || name.endsWith('.markdown');
120
+ }
121
+ function relativePaths(root, nodes) {
122
+ const byId = new Map(nodes.map(node => [node.id, node]));
123
+ const paths = new Map([[root.id, root.name]]);
124
+ const resolve = (node, seen = new Set()) => {
125
+ const cached = paths.get(node.id);
126
+ if (cached !== undefined)
127
+ return cached;
128
+ if (seen.has(node.id) || node.parentId === null)
129
+ return node.name;
130
+ seen.add(node.id);
131
+ const parent = byId.get(node.parentId);
132
+ const value = parent === undefined ? node.name : `${resolve(parent, seen)}/${node.name}`;
133
+ paths.set(node.id, value);
134
+ return value;
135
+ };
136
+ for (const node of nodes)
137
+ resolve(node);
138
+ return paths;
139
+ }
140
+ function directoryIcon() {
141
+ return '<svg class="panel-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M3.5 5.25h4l1.35 1.5h7.65v8H3.5v-9.5Z" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/></svg>';
142
+ }
143
+ function outlineIcon() {
144
+ return '<svg class="panel-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M5 5.5h10M5 10h7.5M5 14.5h9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>';
145
+ }
146
+ function chevronIcon() {
147
+ return '<svg class="chevron" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="m5.75 6.25 2.25 2.5 2.25-2.5" stroke="currentColor" stroke-width="1.35" stroke-linecap="round" stroke-linejoin="round"/></svg>';
148
+ }
149
+ function folderIcon() {
150
+ return '<svg class="tree-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M3.5 5.5h4l1.25 1.4h7.75v7.6h-13v-9Z" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round"/></svg>';
151
+ }
152
+ function fileIcon() {
153
+ return '<svg class="tree-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M5.25 3.5h6l3.5 3.5v9.5h-9.5v-13Z" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round"/><path d="M11.25 3.75V7h3.25" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round"/></svg>';
154
+ }
155
+ function downloadIcon() {
156
+ return '<svg viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="M9 2.75v8.5m0 0 3-3m-3 3-3-3M3.5 14.75h11" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>';
157
+ }
158
+ function formatDate(value) {
159
+ const date = new Date(value);
160
+ return Number.isNaN(date.getTime()) ? value : new Intl.DateTimeFormat('zh-CN', { dateStyle: 'medium', timeStyle: 'short' }).format(date);
161
+ }
162
+ function escapeHtml(value) {
163
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#39;');
164
+ }
165
+ function escapeAttribute(value) {
166
+ return escapeHtml(value);
167
+ }
168
+ const SHARE_PAGE_CSS = `
169
+ :root{color-scheme:light dark;--page:#eef0f2;--shell:rgba(250,251,252,.84);--surface:rgba(255,255,255,.42);--panel:rgba(239,242,244,.6);--raised:rgba(255,255,255,.78);--line:rgba(25,31,36,.11);--line-strong:rgba(25,31,36,.24);--text:#202428;--muted:#727b82;--soft:#8b9399;--accent:#4f5961;--code:#f1f3f4;--shadow:0 18px 58px rgba(24,30,35,.11);--radius:20px;--font-ui:Inter,"SF Pro Text","PingFang SC","Microsoft YaHei",system-ui,sans-serif;--font-reading:"Source Han Sans SC","Noto Sans CJK SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;--font-mono:"SFMono-Regular",Consolas,"Liberation Mono",monospace}
170
+ *{box-sizing:border-box}html{min-width:0;background:var(--page);color:var(--text);font-family:var(--font-ui);scroll-behavior:smooth}body{min-width:0;min-height:100dvh;margin:0;padding:clamp(10px,2vw,28px);background:radial-gradient(circle at 14% 4%,rgba(255,255,255,.92),transparent 34%),var(--page)}button,input,select,textarea,a,summary{font:inherit}.share-shell{width:min(1680px,100%);min-height:calc(100dvh - clamp(20px,4vw,56px));margin:0 auto;overflow:hidden;border:1px solid var(--line);border-radius:var(--radius);background:var(--shell);box-shadow:var(--shadow);backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px)}.share-header{min-height:96px;display:flex;align-items:center;justify-content:space-between;gap:24px;border-bottom:1px solid var(--line);padding:19px clamp(18px,2vw,30px)}.share-title{min-width:0}.eyebrow{display:block;color:var(--muted);font:650 10px/1.2 var(--font-mono);letter-spacing:.12em}.share-header h1{margin:7px 0 0;overflow-wrap:anywhere;font-size:clamp(20px,2.3vw,30px);line-height:1.2;letter-spacing:-.025em}.share-header p{margin:5px 0 0;color:var(--muted);font-size:12px}.readonly{flex:none;border:1px solid var(--line);border-radius:999px;padding:7px 11px;background:var(--raised);color:#626a70;font-size:11px}.share-workspace{min-height:calc(100dvh - 210px);display:grid;grid-template-columns:auto minmax(0,1fr) auto}.share-workspace.is-single{grid-template-columns:minmax(0,1fr)}.share-panel{min-width:0;width:52px;background:var(--panel)}.share-panel[open]{width:clamp(220px,19vw,300px)}.directory-panel{border-right:1px solid var(--line)}.outline-panel{border-left:1px solid var(--line)}.panel-toggle{min-height:50px;display:flex;align-items:center;gap:8px;padding:0 14px;color:var(--muted);cursor:pointer;list-style:none;user-select:none;touch-action:manipulation}.panel-toggle::-webkit-details-marker,.tree-item::-webkit-details-marker{display:none}.panel-toggle::marker,.tree-item::marker{content:""}.panel-toggle:hover{background:rgba(255,255,255,.32);color:var(--text)}.panel-toggle:focus-visible,.tree-item:focus-visible,.share-outline a:focus-visible,.download:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.panel-icon{width:20px;height:20px;flex:none}.panel-label{min-width:0;overflow:hidden;font-size:12px;font-weight:650;white-space:nowrap}.panel-count{min-width:19px;margin-left:auto;border-radius:999px;padding:2px 5px;background:rgba(34,40,45,.07);font:600 10px/1.35 var(--font-mono);text-align:center}.chevron{width:16px;height:16px;flex:none;transition:transform .16s ease}.share-panel[open]>.panel-toggle>.chevron,.tree-folder[open]>.tree-item>.chevron{transform:rotate(180deg)}.share-panel:not([open])>.panel-toggle{justify-content:center;padding-inline:0}.share-panel:not([open]) .panel-label,.share-panel:not([open]) .panel-count,.share-panel:not([open])>.panel-toggle>.chevron{display:none}.share-tree,.share-outline{max-height:calc(100dvh - 260px);overflow:auto;padding:5px 9px 14px;scrollbar-width:thin;scrollbar-color:rgba(90,99,106,.35) transparent}.tree-root,.tree-item{min-width:0;min-height:38px;display:flex;align-items:center;gap:8px;border:0;border-radius:9px;padding:7px 9px;color:#4d555b;font-size:12px;text-decoration:none;cursor:pointer}.tree-root{margin-bottom:5px;color:var(--text);font-weight:650}.tree-item{padding-left:calc(9px + var(--depth)*14px)}.tree-item span,.tree-root span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-icon{width:18px;height:18px;flex:none;color:#7e878e}.tree-folder>.tree-item>.chevron{margin-left:auto}.tree-folder:not([open])>.tree-children{display:none}.tree-root:hover,.tree-item:hover{background:rgba(255,255,255,.66);color:var(--text)}.tree-item.is-active{background:var(--raised);color:var(--text);box-shadow:inset 2px 0 0 var(--accent),0 1px 5px rgba(25,31,36,.07)}.share-outline{padding-top:4px}.share-outline a{min-height:34px;display:flex;align-items:center;border-radius:8px;padding:6px 8px 6px calc(8px + min(var(--level),3)*12px);overflow:hidden;color:#566068;font-size:11px;line-height:1.4;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.share-outline a:hover{background:rgba(255,255,255,.66);color:var(--text)}.outline-empty{margin:8px;padding:12px;border:1px dashed var(--line);border-radius:9px;color:var(--muted);font-size:11px;line-height:1.5}.share-content{min-width:0;display:grid;align-content:start;grid-template-rows:auto minmax(0,1fr);background:var(--surface)}.content-header{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:18px;border-bottom:1px solid var(--line);padding:13px clamp(16px,2.5vw,34px)}.content-title{min-width:0}.content-header .content-title>span{display:block;max-width:min(70vw,900px);overflow:hidden;color:var(--muted);font-size:10px;text-overflow:ellipsis;white-space:nowrap}.content-header h2{margin:5px 0 0;overflow-wrap:anywhere;font-size:18px;letter-spacing:-.015em}.download{min-height:44px;display:inline-flex;align-items:center;justify-content:center;gap:7px;flex:none;border:1px solid var(--line);border-radius:10px;padding:8px 13px;background:var(--raised);color:#30363b;font-size:12px;font-weight:620;text-decoration:none;touch-action:manipulation}.download svg{width:17px;height:17px}.download:hover{border-color:var(--line-strong);background:#fff}.download.primary{margin-top:12px;background:#30363b;color:#fff}.document{min-width:0;padding:clamp(26px,4vw,66px) clamp(18px,5vw,84px) 72px}.plain-text,.markdown-body{width:min(100%,980px);margin:0 auto;color:#30363b;overflow-wrap:anywhere}.plain-text{font:14px/1.78 var(--font-mono);white-space:pre-wrap}.markdown-body{font:15px/1.78 var(--font-reading)}.markdown-body>*:first-child{margin-top:0}.markdown-body>*:last-child{margin-bottom:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{position:relative;margin:1.65em 0 .65em;color:var(--text);font-family:var(--font-ui);line-height:1.35;letter-spacing:-.018em;scroll-margin-top:22px}.markdown-body h1{font-size:2em}.markdown-body h2{border-bottom:1px solid var(--line);padding-bottom:.34em;font-size:1.55em}.markdown-body h3{font-size:1.28em}.markdown-body h4{font-size:1.1em}.markdown-body h5,.markdown-body h6{font-size:1em}.heading-anchor{margin-left:.45em;color:var(--soft);font-weight:450;text-decoration:none;opacity:0}.markdown-body :is(h1,h2,h3,h4,h5,h6):hover .heading-anchor,.heading-anchor:focus-visible{opacity:1}.markdown-body p{margin:.85em 0}.markdown-body a{color:#3f647b;text-decoration-color:rgba(63,100,123,.35);text-underline-offset:3px}.markdown-body a:hover{text-decoration-color:currentColor}.markdown-body ul,.markdown-body ol{margin:.75em 0;padding-left:1.65em}.markdown-body li+li{margin-top:.25em}.markdown-body blockquote{margin:1.15em 0;border-left:3px solid #9aa2a8;padding:.15em 1em;color:#5f686f}.markdown-body code{border:1px solid var(--line);border-radius:5px;padding:.12em .35em;background:var(--code);font:13px/1.5 var(--font-mono)}.markdown-body pre{max-width:100%;overflow:auto;border:1px solid var(--line);border-radius:12px;padding:16px;background:var(--code);scrollbar-width:thin}.markdown-body pre code{border:0;padding:0;background:transparent;white-space:pre}.markdown-body hr{height:1px;margin:2em 0;border:0;background:var(--line)}.markdown-body table{width:100%;display:block;margin:1.2em 0;overflow-x:auto;border-collapse:collapse;scrollbar-width:thin}.markdown-body th,.markdown-body td{min-width:110px;border:1px solid var(--line);padding:8px 11px;text-align:left}.markdown-body th{background:rgba(85,94,101,.06);font-weight:650}.markdown-body img{max-width:100%;height:auto;display:block;margin:1.4em auto;border-radius:12px}.task-box{width:14px;height:14px;display:inline-grid;place-items:center;margin:0 7px 0 -1.4em;border:1px solid #899198;border-radius:4px;vertical-align:-2px}.task-box.is-checked:after{width:7px;height:4px;border:solid currentColor;border-width:0 0 1.5px 1.5px;content:"";transform:translateY(-1px) rotate(-45deg)}.unsafe-link,.image-fallback{color:var(--muted)}.image-stage{min-height:0;display:grid;place-items:center;padding:24px}.image-stage img{max-width:100%;max-height:72dvh;border-radius:12px;box-shadow:0 10px 34px rgba(25,31,36,.12)}.empty{min-height:420px;display:grid;place-content:center;justify-items:center;padding:32px;color:var(--muted);text-align:center}.empty h2{margin:14px 0 0;color:#30363b;font-size:17px}.empty p{margin:6px 0 0;font-size:12px}.empty-mark,.file-large{width:54px;height:39px;border:1.5px solid #939ba1;border-radius:7px;background:rgba(255,255,255,.55)}.file-large{width:40px;height:50px}.notice{margin:10px 7px;border-left:2px solid #7e878e;padding:6px 9px;color:var(--muted);font-size:11px;line-height:1.5}.content-notice{margin:16px clamp(16px,3vw,32px) 0}.share-footer{min-height:48px;display:flex;align-items:center;justify-content:space-between;gap:16px;border-top:1px solid var(--line);padding:10px 18px;color:var(--muted);font-size:10px}
171
+ body{overflow:hidden}.share-shell{height:calc(100dvh - clamp(20px,4vw,56px));min-height:0;display:grid;grid-template-rows:auto minmax(0,1fr) auto}.share-workspace{min-height:0;overflow:hidden}.share-panel{height:100%;overflow:hidden}.share-panel[open]{display:grid;grid-template-rows:auto minmax(0,1fr)}.share-tree,.share-outline{min-height:0;max-height:none}.share-content{min-height:0;display:block;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:rgba(90,99,106,.35) transparent}.content-header{position:sticky;z-index:3;top:0;background:rgba(250,251,252,.9);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}
172
+ @media(max-width:860px){body{padding:0}.share-shell{height:100dvh;min-height:0;border:0;border-radius:0}.share-header{min-height:86px;padding:15px 16px}.readonly{display:none}.share-workspace,.share-workspace.is-single{min-height:0;display:flex;overflow:hidden;flex-direction:column}.share-panel,.share-panel[open]{width:100%;height:auto;display:block;flex:none;border:0;border-bottom:1px solid var(--line)}.directory-panel{order:1}.outline-panel{order:2}.share-content{order:3;min-height:0;flex:1;overflow:auto}.share-panel:not([open])>.panel-toggle{justify-content:flex-start;padding-inline:14px}.share-panel:not([open]) .panel-label,.share-panel:not([open]) .panel-count,.share-panel:not([open])>.panel-toggle>.chevron{display:inline-flex}.share-panel:not([open])>.panel-toggle>.chevron{margin-left:auto}.share-panel[open]>.panel-toggle>.chevron{margin-left:0}.share-tree,.share-outline{max-height:min(30dvh,240px)}.content-header{padding-inline:16px}.content-header .content-title>span{max-width:62vw}.document{padding:28px 18px 52px}.markdown-body{font-size:16px}.markdown-body h1{font-size:1.72em}.markdown-body h2{font-size:1.42em}.download span{display:none}.share-footer{align-items:flex-start;flex-direction:column;gap:3px;padding:11px 16px}}
173
+ @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.chevron{transition:none}}
174
+ @media(prefers-color-scheme:dark){:root{--page:#17191b;--shell:rgba(31,34,37,.9);--surface:rgba(255,255,255,.018);--panel:rgba(15,17,18,.27);--raised:rgba(255,255,255,.065);--line:rgba(255,255,255,.1);--line-strong:rgba(255,255,255,.3);--text:#eef0f2;--muted:#9ba1a6;--soft:#777f85;--accent:#b8bec2;--code:rgba(9,11,12,.38);--shadow:0 18px 58px rgba(0,0,0,.36)}body{background:radial-gradient(circle at 14% 4%,rgba(255,255,255,.055),transparent 34%),var(--page)}.content-header{background:rgba(31,34,37,.9)}.readonly,.download{color:#d9dcde}.panel-toggle:hover,.tree-root:hover,.tree-item:hover,.share-outline a:hover{background:rgba(255,255,255,.065)}.panel-count{background:rgba(255,255,255,.07)}.tree-root{color:var(--text)}.tree-item,.share-outline a{color:#b5babd}.tree-icon{color:#858d93}.tree-item.is-active{color:#f1f2f3;box-shadow:inset 2px 0 0 var(--accent),0 1px 7px rgba(0,0,0,.2)}.download:hover{background:rgba(255,255,255,.1)}.download.primary{background:#e3e6e8;color:#202326}.plain-text,.markdown-body{color:#d9dcde}.markdown-body a{color:#91b9cf}.markdown-body blockquote{color:#aeb4b8}.markdown-body th{background:rgba(255,255,255,.045)}.empty h2{color:#e4e7e9}.empty-mark,.file-large{border-color:#777f85;background:rgba(255,255,255,.04)}}
175
+ `;
176
+ //# sourceMappingURL=share-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share-page.js","sourceRoot":"","sources":["../../src/notes/share-page.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type NoteFileUpload, type NoteListRequest, type NoteNode, type NoteVersion } from './domain.js';
1
+ import { type NoteFileUpload, type NoteListRequest, type NoteNode, type NoteShare, type NoteVersion } from './domain.js';
2
2
  export declare class NoteStore {
3
3
  private readonly rootPath;
4
4
  private readonly removeOnClose;
@@ -11,6 +11,13 @@ export declare class NoteStore {
11
11
  list(request?: NoteListRequest): NoteNode[];
12
12
  get(id: string): NoteNode | undefined;
13
13
  subtree(id: string): NoteNode[];
14
+ listSharedSubtree(id: string, limit?: number): NoteNode[];
15
+ isWithin(rootId: string, candidateId: string): boolean;
16
+ listShares(): NoteShare[];
17
+ getShareByNoteId(noteId: string): NoteShare | undefined;
18
+ getShareByToken(token: string): NoteShare | undefined;
19
+ createShare(noteId: string): NoteShare;
20
+ deleteShare(noteId: string): boolean;
14
21
  createFolder(name: string, parentId?: string | null): Promise<NoteNode>;
15
22
  createDocument(name: string, parentId?: string | null, content?: string): Promise<NoteNode>;
16
23
  upload(upload: NoteFileUpload): Promise<NoteNode>;
@@ -18,6 +25,11 @@ export declare class NoteStore {
18
25
  node: NoteNode;
19
26
  content: Buffer;
20
27
  }>;
28
+ readPreview(id: string, maximumBytes: number): Promise<{
29
+ node: NoteNode;
30
+ content: Buffer;
31
+ truncated: boolean;
32
+ }>;
21
33
  updateContent(id: string, content: Uint8Array): Promise<NoteNode>;
22
34
  listVersions(id: string, limit?: number): NoteVersion[];
23
35
  readVersion(id: string, version: number): Promise<{
@@ -41,8 +53,10 @@ export declare class NoteStore {
41
53
  private assertNameAvailable;
42
54
  private nameExists;
43
55
  private isDescendant;
56
+ private mapShare;
44
57
  private migrate;
45
58
  private migrateVersionOne;
59
+ private migrateVersionTwo;
46
60
  private objectPath;
47
61
  private versionDirectory;
48
62
  private versionPath;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notes/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notes/store.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,13 @@
1
- import { createHash, randomUUID } from 'node:crypto';
1
+ import { createHash, randomBytes, randomUUID } from 'node:crypto';
2
2
  import { constants as fileConstants, copyFileSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
3
- import { readFile, rename, rm } from 'node:fs/promises';
3
+ import { open, readFile, rename, rm } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
5
  import { DatabaseSync } from 'node:sqlite';
6
6
  import { atomicWriteFile } from '../atomic-file.js';
7
7
  import { isEditableNoteNode, isNoteId, } from './domain.js';
8
8
  const MAX_NOTE_BYTES = 64 * 1024 * 1024;
9
9
  const MAX_NOTE_NAME_LENGTH = 255;
10
+ const NOTE_SHARE_TOKEN_PATTERN = /^share_[A-Za-z0-9_-]{32}$/;
10
11
  export class NoteStore {
11
12
  rootPath;
12
13
  removeOnClose;
@@ -71,6 +72,91 @@ export class NoteStore {
71
72
  throw notFound(`note node "${id}" was not found`);
72
73
  return rows.map(mapNoteNode);
73
74
  }
75
+ listSharedSubtree(id, limit = 500) {
76
+ this.assertOpen();
77
+ assertNoteId(id);
78
+ const boundedLimit = Number.isInteger(limit) ? Math.min(1000, Math.max(1, limit)) : 500;
79
+ const rows = this.db.prepare(`
80
+ WITH RECURSIVE descendants(id) AS (
81
+ SELECT id FROM note_nodes WHERE id=?
82
+ UNION ALL
83
+ SELECT child.id FROM note_nodes child JOIN descendants parent ON child.parent_id=parent.id
84
+ )
85
+ SELECT ${NOTE_COLUMNS} FROM note_nodes WHERE id IN (SELECT id FROM descendants)
86
+ ORDER BY CASE kind WHEN 'folder' THEN 0 ELSE 1 END, name COLLATE NOCASE, id
87
+ LIMIT ?
88
+ `).all(id, boundedLimit);
89
+ if (rows.length === 0)
90
+ throw notFound(`note node "${id}" was not found`);
91
+ return rows.map(mapNoteNode);
92
+ }
93
+ isWithin(rootId, candidateId) {
94
+ this.assertOpen();
95
+ assertNoteId(rootId);
96
+ assertNoteId(candidateId);
97
+ if (rootId === candidateId)
98
+ return this.get(rootId) !== undefined;
99
+ return this.db.prepare(`
100
+ WITH RECURSIVE descendants(id) AS (
101
+ SELECT id FROM note_nodes WHERE parent_id=?
102
+ UNION ALL
103
+ SELECT child.id FROM note_nodes child JOIN descendants parent ON child.parent_id=parent.id
104
+ )
105
+ SELECT 1 FROM descendants WHERE id=? LIMIT 1
106
+ `).get(rootId, candidateId) !== undefined;
107
+ }
108
+ listShares() {
109
+ this.assertOpen();
110
+ const rows = this.db.prepare(`
111
+ SELECT ${NOTE_SHARE_COLUMNS}
112
+ FROM note_shares s JOIN note_nodes n ON n.id=s.note_id
113
+ ORDER BY s.updated_at DESC, s.id
114
+ `).all();
115
+ return rows.map(row => this.mapShare(row));
116
+ }
117
+ getShareByNoteId(noteId) {
118
+ this.assertOpen();
119
+ assertNoteId(noteId);
120
+ const row = this.db.prepare(`
121
+ SELECT ${NOTE_SHARE_COLUMNS}
122
+ FROM note_shares s JOIN note_nodes n ON n.id=s.note_id
123
+ WHERE s.note_id=?
124
+ `).get(noteId);
125
+ return row === undefined ? undefined : this.mapShare(row);
126
+ }
127
+ getShareByToken(token) {
128
+ this.assertOpen();
129
+ if (!NOTE_SHARE_TOKEN_PATTERN.test(token))
130
+ return undefined;
131
+ const row = this.db.prepare(`
132
+ SELECT ${NOTE_SHARE_COLUMNS}
133
+ FROM note_shares s JOIN note_nodes n ON n.id=s.note_id
134
+ WHERE s.token=?
135
+ `).get(token);
136
+ return row === undefined ? undefined : this.mapShare(row);
137
+ }
138
+ createShare(noteId) {
139
+ this.assertOpen();
140
+ const node = this.requireNode(noteId);
141
+ const existing = this.getShareByNoteId(noteId);
142
+ if (existing !== undefined)
143
+ return existing;
144
+ const id = `share_${randomUUID().replaceAll('-', '')}`;
145
+ const token = `share_${randomBytes(24).toString('base64url')}`;
146
+ const timestamp = new Date().toISOString();
147
+ const result = this.db.prepare(`
148
+ INSERT INTO note_shares(id,note_id,token,created_at,updated_at) VALUES(?,?,?,?,?)
149
+ ON CONFLICT(note_id) DO NOTHING
150
+ `).run(id, noteId, token, timestamp, timestamp);
151
+ if (result.changes === 0)
152
+ return this.getShareByNoteId(noteId);
153
+ return { id, noteId, token, createdAt: timestamp, updatedAt: timestamp, node };
154
+ }
155
+ deleteShare(noteId) {
156
+ this.assertOpen();
157
+ assertNoteId(noteId);
158
+ return this.db.prepare('DELETE FROM note_shares WHERE note_id=?').run(noteId).changes === 1;
159
+ }
74
160
  async createFolder(name, parentId = null) {
75
161
  return this.createNode('folder', name, parentId, null, Buffer.alloc(0));
76
162
  }
@@ -99,6 +185,32 @@ export class NoteStore {
99
185
  throw error;
100
186
  }
101
187
  }
188
+ async readPreview(id, maximumBytes) {
189
+ const node = this.get(id);
190
+ if (node === undefined)
191
+ throw notFound(`note node "${id}" was not found`);
192
+ if (node.kind === 'folder')
193
+ throw inputError('folders do not have file content');
194
+ const limit = Number.isInteger(maximumBytes) ? Math.min(MAX_NOTE_BYTES, Math.max(1, maximumBytes)) : 512 * 1024;
195
+ const size = Math.min(node.size, limit);
196
+ const content = Buffer.alloc(size);
197
+ let file;
198
+ try {
199
+ file = await open(this.objectPath(id), 'r');
200
+ const { bytesRead } = await file.read(content, 0, size, 0);
201
+ if (bytesRead !== size)
202
+ throw new Error(`note node "${id}" has an invalid stored size`);
203
+ return { node, content, truncated: node.size > size };
204
+ }
205
+ catch (error) {
206
+ if (isNodeError(error, 'ENOENT'))
207
+ throw notFound(`note content "${id}" was not found`);
208
+ throw error;
209
+ }
210
+ finally {
211
+ await file?.close().catch(() => { });
212
+ }
213
+ }
102
214
  async updateContent(id, content) {
103
215
  return this.enqueueContentMutation(id, () => this.updateContentNow(id, Buffer.from(content)));
104
216
  }
@@ -428,9 +540,33 @@ export class NoteStore {
428
540
  SELECT 1 FROM descendants WHERE id=? LIMIT 1
429
541
  `).get(ancestorId, candidateId) !== undefined;
430
542
  }
543
+ mapShare(row) {
544
+ const noteId = String(row.note_id);
545
+ const node = mapNoteNode({
546
+ id: row.node_id,
547
+ parent_id: row.node_parent_id,
548
+ parent_key: row.node_parent_key,
549
+ kind: row.node_kind,
550
+ name: row.node_name,
551
+ media_type: row.node_media_type,
552
+ size: row.node_size,
553
+ sha256: row.node_sha256,
554
+ version: row.node_version,
555
+ created_at: row.node_created_at,
556
+ updated_at: row.node_updated_at,
557
+ });
558
+ return {
559
+ id: String(row.share_id),
560
+ noteId,
561
+ token: String(row.token),
562
+ createdAt: String(row.share_created_at),
563
+ updatedAt: String(row.share_updated_at),
564
+ node,
565
+ };
566
+ }
431
567
  migrate() {
432
- const version = Number(this.db.prepare('PRAGMA user_version').get().user_version ?? 0);
433
- if (version > 2)
568
+ let version = Number(this.db.prepare('PRAGMA user_version').get().user_version ?? 0);
569
+ if (version > 3)
434
570
  throw new Error(`note database schema ${version} is newer than this plugin supports`);
435
571
  if (version === 0)
436
572
  this.db.exec(`
@@ -458,15 +594,29 @@ export class NoteStore {
458
594
  created_at TEXT NOT NULL,
459
595
  PRIMARY KEY(note_id, version)
460
596
  );
597
+ CREATE TABLE note_shares (
598
+ id TEXT PRIMARY KEY,
599
+ note_id TEXT NOT NULL UNIQUE REFERENCES note_nodes(id) ON DELETE CASCADE,
600
+ token TEXT NOT NULL UNIQUE,
601
+ created_at TEXT NOT NULL,
602
+ updated_at TEXT NOT NULL
603
+ );
461
604
  CREATE UNIQUE INDEX note_sibling_name ON note_nodes(parent_key, name COLLATE NOCASE);
462
605
  CREATE INDEX note_parent_order ON note_nodes(parent_key, kind, name COLLATE NOCASE);
463
606
  CREATE INDEX note_name ON note_nodes(name COLLATE NOCASE);
464
607
  CREATE INDEX note_versions_recent ON note_versions(note_id, version DESC);
465
- PRAGMA user_version = 2;
608
+ CREATE INDEX note_shares_recent ON note_shares(updated_at DESC);
609
+ PRAGMA user_version = 3;
466
610
  COMMIT;
467
611
  `);
468
- if (version === 1)
612
+ if (version === 0)
613
+ return;
614
+ if (version === 1) {
469
615
  this.migrateVersionOne();
616
+ version = 2;
617
+ }
618
+ if (version === 2)
619
+ this.migrateVersionTwo();
470
620
  }
471
621
  migrateVersionOne() {
472
622
  const files = this.db.prepare(`
@@ -543,6 +693,21 @@ export class NoteStore {
543
693
  throw error;
544
694
  }
545
695
  }
696
+ migrateVersionTwo() {
697
+ this.db.exec(`
698
+ BEGIN IMMEDIATE;
699
+ CREATE TABLE note_shares (
700
+ id TEXT PRIMARY KEY,
701
+ note_id TEXT NOT NULL UNIQUE REFERENCES note_nodes(id) ON DELETE CASCADE,
702
+ token TEXT NOT NULL UNIQUE,
703
+ created_at TEXT NOT NULL,
704
+ updated_at TEXT NOT NULL
705
+ );
706
+ CREATE INDEX note_shares_recent ON note_shares(updated_at DESC);
707
+ PRAGMA user_version = 3;
708
+ COMMIT;
709
+ `);
710
+ }
546
711
  objectPath(id) {
547
712
  assertNoteId(id);
548
713
  return join(this.objectsPath, id);
@@ -571,6 +736,12 @@ export class NoteStore {
571
736
  }
572
737
  }
573
738
  const NOTE_COLUMNS = 'id,parent_id,parent_key,kind,name,media_type,size,sha256,version,created_at,updated_at';
739
+ const NOTE_SHARE_COLUMNS = `
740
+ s.id AS share_id,s.note_id,s.token,s.created_at AS share_created_at,s.updated_at AS share_updated_at,
741
+ n.id AS node_id,n.parent_id AS node_parent_id,n.parent_key AS node_parent_key,n.kind AS node_kind,
742
+ n.name AS node_name,n.media_type AS node_media_type,n.size AS node_size,n.sha256 AS node_sha256,
743
+ n.version AS node_version,n.created_at AS node_created_at,n.updated_at AS node_updated_at
744
+ `;
574
745
  export function normalizeNoteName(value) {
575
746
  const name = value.trim().normalize('NFC');
576
747
  if (name.length === 0 || name.length > MAX_NOTE_NAME_LENGTH) {