@bendyline/docblocks 2.7.2 → 2.7.4
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/THIRD_PARTY_NOTICES.txt +4 -4
- package/dist/{capabilities-BvUC17t9.d.ts → capabilities-BJEkIsO1.d.ts} +9 -4
- package/dist/{chunk-KQ6756AJ.js → chunk-3GSMJ4MQ.js} +1 -1
- package/dist/{chunk-YWYT6K6J.js → chunk-3LXXRIO2.js} +1 -1
- package/dist/{chunk-STUIS5UZ.js → chunk-7LPIGCBG.js} +17 -3
- package/dist/{chunk-UK7R3RC7.js → chunk-BC42VRYW.js} +1 -1
- package/dist/{chunk-IGB2VSRE.js → chunk-FIEMYP2N.js} +2 -2
- package/dist/{chunk-M5ZNQGR5.js → chunk-IYKGM3PV.js} +1 -1
- package/dist/{chunk-6UPO2GE6.js → chunk-K5HRMSXD.js} +3 -3
- package/dist/{chunk-NM5KF6YF.js → chunk-KXQDMZFH.js} +9 -1
- package/dist/{chunk-UDEWLHQI.js → chunk-LDAG5NTQ.js} +3 -3
- package/dist/{chunk-7SN7YQL4.js → chunk-LJLQYXVL.js} +99 -3
- package/dist/{chunk-L657M3XG.js → chunk-PSGAZKWO.js} +2 -2
- package/dist/{chunk-HKOOHM67.js → chunk-Q3OFZWJS.js} +3 -3
- package/dist/{chunk-AYWKIZLD.js → chunk-UTH3HYCZ.js} +5 -1
- package/dist/{chunk-QS5WTLUZ.js → chunk-XI2LYBRR.js} +167 -0
- package/dist/document/index.d.ts +2 -2
- package/dist/document/index.js +3 -3
- package/dist/filesystem/electron.d.ts +5 -5
- package/dist/filesystem/electron.js +4 -4
- package/dist/filesystem/host.d.ts +4 -4
- package/dist/filesystem/host.js +4 -4
- package/dist/filesystem/index.d.ts +27 -8
- package/dist/filesystem/index.js +22 -12
- package/dist/filesystem/indexeddb.d.ts +2 -2
- package/dist/filesystem/indexeddb.js +4 -4
- package/dist/filesystem/memory.d.ts +2 -2
- package/dist/filesystem/memory.js +4 -4
- package/dist/filesystem/native.d.ts +2 -2
- package/dist/filesystem/native.js +4 -4
- package/dist/{filesystem-v2-C8AdSXUN.d.ts → filesystem-v2-CXdAPR27.d.ts} +1 -1
- package/dist/host/index.d.ts +5 -5
- package/dist/host/index.js +1 -1
- package/dist/host/mobile.d.ts +2 -2
- package/dist/host/mobile.js +1 -1
- package/dist/{host-provider-v2-CV0joXaL.d.ts → host-provider-v2-DEWMPiRD.d.ts} +2 -2
- package/dist/index.d.ts +8 -7
- package/dist/index.js +23 -13
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/zod.js +2 -2
- package/dist/reconcile-electron-Bz-iAY_B.d.ts +142 -0
- package/dist/{types-BvDnr3YU.d.ts → types-DLteNrK0.d.ts} +3 -1
- package/dist/{v2-BVnZZyd4.d.ts → v2-DwxWjFC0.d.ts} +12 -1
- package/dist/vscode/index.d.ts +28 -2
- package/dist/vscode/index.js +21 -3
- package/dist/workspace/index.d.ts +41 -141
- package/dist/workspace/index.js +16 -1
- package/dist/workspace-index/index.d.ts +3 -1
- package/dist/workspace-index/index.js +18 -2
- package/dist/workspace-settings/index.d.ts +1 -1
- package/dist/workspace-settings/index.js +3 -3
- package/package.json +2 -2
package/THIRD_PARTY_NOTICES.txt
CHANGED
|
@@ -14,7 +14,7 @@ This notice is included in the published npm tarball. Transitive packages instal
|
|
|
14
14
|
|
|
15
15
|
| Package | Version | License | Source |
|
|
16
16
|
| --- | --- | --- | --- |
|
|
17
|
-
| @bendyline/squisq | 2.12.
|
|
17
|
+
| @bendyline/squisq | 2.12.5 | MIT | https://github.com/bendyline/squisq |
|
|
18
18
|
| @types/debug | 4.1.12 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped |
|
|
19
19
|
| @types/hast | 3.0.4 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped |
|
|
20
20
|
| @types/katex | 0.16.8 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped |
|
|
@@ -132,7 +132,7 @@ This notice is included in the published npm tarball. Transitive packages instal
|
|
|
132
132
|
Package-local license, copying, and notice files are reproduced below. Where a published package omits its repository license, the reviewed aggregate or README identified in `Source files` supplies the retained material.
|
|
133
133
|
|
|
134
134
|
==============================================================================
|
|
135
|
-
Components: @bendyline/squisq@2.12.
|
|
135
|
+
Components: @bendyline/squisq@2.12.5
|
|
136
136
|
Source files: node_modules/@bendyline/squisq/LICENSE
|
|
137
137
|
==============================================================================
|
|
138
138
|
MIT License
|
|
@@ -158,7 +158,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
158
158
|
SOFTWARE.
|
|
159
159
|
|
|
160
160
|
==============================================================================
|
|
161
|
-
Components: @bendyline/squisq@2.12.
|
|
161
|
+
Components: @bendyline/squisq@2.12.5
|
|
162
162
|
Source files: node_modules/@bendyline/squisq/NOTICE.md
|
|
163
163
|
==============================================================================
|
|
164
164
|
# Third-Party Notices for @bendyline/squisq
|
|
@@ -189,7 +189,7 @@ third-party license texts for bundled code and data are shipped in
|
|
|
189
189
|
THIRD_PARTY_LICENSES.txt.
|
|
190
190
|
|
|
191
191
|
==============================================================================
|
|
192
|
-
Components: @bendyline/squisq@2.12.
|
|
192
|
+
Components: @bendyline/squisq@2.12.5
|
|
193
193
|
Source files: node_modules/@bendyline/squisq/THIRD_PARTY_LICENSES.txt
|
|
194
194
|
==============================================================================
|
|
195
195
|
THIRD-PARTY LICENSES FOR @bendyline/squisq
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FileCommitResult, c as FileSystemEntry, b as FileMeta } from './types-
|
|
2
|
-
import { D as DocBlocksHostFsV2API } from './filesystem-v2-
|
|
1
|
+
import { F as FileCommitResult, c as FileSystemEntry, b as FileMeta } from './types-DLteNrK0.js';
|
|
2
|
+
import { D as DocBlocksHostFsV2API } from './filesystem-v2-CXdAPR27.js';
|
|
3
3
|
|
|
4
4
|
/** Provider-neutral catalog management. IDs never authorize filesystem access. */
|
|
5
5
|
interface AiKnowledgeCatalog {
|
|
@@ -190,9 +190,11 @@ interface AiChatMessage {
|
|
|
190
190
|
* What the request is for.
|
|
191
191
|
*
|
|
192
192
|
* This exists so the host can apply different budgets to a person waiting on a
|
|
193
|
-
* draft and a background review pass. It is never sent to the model.
|
|
193
|
+
* draft and a background review pass. It is never sent to the model. Only
|
|
194
|
+
* `write` may spend its output budget reasoning; `study` (summaries, quizzes
|
|
195
|
+
* and flashcards, made in many small calls with explicit caps) never does.
|
|
194
196
|
*/
|
|
195
|
-
type AiChatPurpose = 'write' | 'review' | 'illustrate' | 'chat';
|
|
197
|
+
type AiChatPurpose = 'write' | 'review' | 'illustrate' | 'study' | 'chat';
|
|
196
198
|
interface AiChatRequest {
|
|
197
199
|
readonly messages: readonly AiChatMessage[];
|
|
198
200
|
/** Opaque provider model id. Omitted means "the host's current choice". */
|
|
@@ -890,6 +892,8 @@ interface HostExportTargetGrant {
|
|
|
890
892
|
}
|
|
891
893
|
/** Native export target selection and binary file writing. */
|
|
892
894
|
interface DocBlocksHostExportAPI {
|
|
895
|
+
/** Open a successfully saved grant in its default app; Markdown opens in DocBlocks. */
|
|
896
|
+
openSaved?(documentId: string, grantId: string): Promise<void>;
|
|
893
897
|
/** A share-sheet outcome is never a durable export target. Android can only report presentation. */
|
|
894
898
|
share?(filename: string, data: ArrayBuffer | Uint8Array): Promise<'shared' | 'presented' | 'cancelled'>;
|
|
895
899
|
/** Resolve an exact remembered grant or a display-only host suggestion. */
|
|
@@ -1186,6 +1190,7 @@ interface HostCapabilities {
|
|
|
1186
1190
|
readonly exportDestinations: boolean;
|
|
1187
1191
|
/** Remembered, re-resolvable export targets (`resolveTarget`/`pickTarget`). */
|
|
1188
1192
|
readonly exportRememberedTargets: boolean;
|
|
1193
|
+
readonly openSavedExports: boolean;
|
|
1189
1194
|
readonly externalResources: boolean;
|
|
1190
1195
|
readonly openRequests: boolean;
|
|
1191
1196
|
readonly menuCommands: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FILE_SYSTEM_TRANSFER_LIMITS,
|
|
3
3
|
maybeGetDocBlocksHost
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KXQDMZFH.js";
|
|
5
5
|
import {
|
|
6
6
|
parseFileSystemCapabilities
|
|
7
7
|
} from "./chunk-245W57QP.js";
|
|
@@ -26,11 +26,12 @@ import {
|
|
|
26
26
|
WORKSPACE_ROOT,
|
|
27
27
|
deserializeFsError,
|
|
28
28
|
fsErrorFromUnknown,
|
|
29
|
+
isFsErrorCode,
|
|
29
30
|
isSerializedFsError,
|
|
30
31
|
parseWorkspacePath,
|
|
31
32
|
workspacePathBasename,
|
|
32
33
|
workspacePathDirname
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
34
35
|
|
|
35
36
|
// src/filesystem/host-provider-v2.ts
|
|
36
37
|
var fallbackInstanceSequence = 0;
|
|
@@ -419,7 +420,13 @@ function normalizeEntry(entry) {
|
|
|
419
420
|
if (!isNonNegativeSafeInteger(entry.size)) {
|
|
420
421
|
throw new TypeError("Filesystem file size must be a non-negative safe integer.");
|
|
421
422
|
}
|
|
422
|
-
|
|
423
|
+
const readIssue = normalizeReadIssue(entry.readIssue);
|
|
424
|
+
return Object.freeze({
|
|
425
|
+
...common,
|
|
426
|
+
kind: "file",
|
|
427
|
+
size: entry.size,
|
|
428
|
+
...readIssue ? { readIssue } : {}
|
|
429
|
+
});
|
|
423
430
|
}
|
|
424
431
|
if (entry.kind === "directory") {
|
|
425
432
|
if (entry.size !== null) throw new TypeError("Filesystem directory size must be null.");
|
|
@@ -427,6 +434,13 @@ function normalizeEntry(entry) {
|
|
|
427
434
|
}
|
|
428
435
|
throw new TypeError("Unknown filesystem entry kind.");
|
|
429
436
|
}
|
|
437
|
+
function normalizeReadIssue(value) {
|
|
438
|
+
if (value === void 0) return void 0;
|
|
439
|
+
if (!isRecord(value) || !isFsErrorCode(value.code) || !isBoundedString(value.message, HOST_WIRE_LIMITS.messageCharacters, 1)) {
|
|
440
|
+
throw new TypeError("Filesystem entry read issue is malformed.");
|
|
441
|
+
}
|
|
442
|
+
return Object.freeze({ code: value.code, message: value.message });
|
|
443
|
+
}
|
|
430
444
|
function normalizeDirectoryListing(value, parent) {
|
|
431
445
|
if (!Array.isArray(value)) throw new TypeError("Expected a filesystem directory listing.");
|
|
432
446
|
const entries = value.map(normalizeEntry);
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
} from "./chunk-XAMILHQP.js";
|
|
4
4
|
import {
|
|
5
5
|
decodeUtf8Text
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IYKGM3PV.js";
|
|
7
7
|
import {
|
|
8
8
|
FsError,
|
|
9
9
|
parseWorkspacePath
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
11
11
|
|
|
12
12
|
// src/filesystem/move-error.ts
|
|
13
13
|
function locationFromPresence(source, destination) {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-DZB666V7.js";
|
|
4
4
|
import {
|
|
5
5
|
parentChain
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3GSMJ4MQ.js";
|
|
7
7
|
import {
|
|
8
8
|
bytesEqual,
|
|
9
9
|
compareSnapshotsByName,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-LPIJ6HKL.js";
|
|
16
16
|
import {
|
|
17
17
|
decodeUtf8Text
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-IYKGM3PV.js";
|
|
19
19
|
import {
|
|
20
20
|
FsError,
|
|
21
21
|
WORKSPACE_ROOT,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
workspacePathContains,
|
|
26
26
|
workspacePathDirname,
|
|
27
27
|
workspacePathJoin
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
29
29
|
|
|
30
30
|
// src/filesystem/native-provider-v2.ts
|
|
31
31
|
var NativeFileSystemMoveRecoveryError = class extends FsError {
|
|
@@ -27,6 +27,7 @@ var NO_CAPABILITIES = Object.freeze({
|
|
|
27
27
|
clipboard: false,
|
|
28
28
|
exportDestinations: false,
|
|
29
29
|
exportRememberedTargets: false,
|
|
30
|
+
openSavedExports: false,
|
|
30
31
|
externalResources: false,
|
|
31
32
|
openRequests: false,
|
|
32
33
|
menuCommands: false,
|
|
@@ -103,6 +104,7 @@ function deriveHostCapabilities(host) {
|
|
|
103
104
|
clipboard: hasMethod(host.clipboard, "writeText"),
|
|
104
105
|
exportDestinations: hasMethod(exports, "save"),
|
|
105
106
|
exportRememberedTargets: hasMethod(exports, "resolveTarget") && hasMethod(exports, "pickTarget"),
|
|
107
|
+
openSavedExports: hasMethod(exports, "openSaved"),
|
|
106
108
|
externalResources: hasMethod(host.external, "readText"),
|
|
107
109
|
openRequests: hasMethod(host, "onOpenRequest"),
|
|
108
110
|
menuCommands: hasMethod(host, "onMenuCommand"),
|
|
@@ -148,7 +150,13 @@ var AI_WIRE_LIMITS = Object.freeze({
|
|
|
148
150
|
downloadBytesCeiling: Number.MAX_SAFE_INTEGER
|
|
149
151
|
});
|
|
150
152
|
var CHAT_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant"]);
|
|
151
|
-
var CHAT_PURPOSES = /* @__PURE__ */ new Set([
|
|
153
|
+
var CHAT_PURPOSES = /* @__PURE__ */ new Set([
|
|
154
|
+
"write",
|
|
155
|
+
"review",
|
|
156
|
+
"illustrate",
|
|
157
|
+
"study",
|
|
158
|
+
"chat"
|
|
159
|
+
]);
|
|
152
160
|
var REVIEW_MODES = /* @__PURE__ */ new Set(["off", "explicit", "implicit"]);
|
|
153
161
|
var FINISH_REASONS = /* @__PURE__ */ new Set(["stop", "length", "cancelled"]);
|
|
154
162
|
var UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parentChainWithRoot
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3GSMJ4MQ.js";
|
|
4
4
|
import {
|
|
5
5
|
compareSnapshotsByName,
|
|
6
6
|
compareText,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./chunk-LPIJ6HKL.js";
|
|
12
12
|
import {
|
|
13
13
|
decodeUtf8Text
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-IYKGM3PV.js";
|
|
15
15
|
import {
|
|
16
16
|
FsError,
|
|
17
17
|
WORKSPACE_ROOT,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
workspacePathBasename,
|
|
20
20
|
workspacePathContains,
|
|
21
21
|
workspacePathDirname
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
23
23
|
|
|
24
24
|
// src/filesystem/memory-provider-v2.ts
|
|
25
25
|
var MEMORY_CAPABILITIES = Object.freeze({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
guessMimeType
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Q3OFZWJS.js";
|
|
4
4
|
import {
|
|
5
5
|
bytesEqual,
|
|
6
6
|
compareSnapshotsByName,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
createFileSystemDocumentTarget,
|
|
18
18
|
describeEntryMove,
|
|
19
19
|
describePartialMove
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-FIEMYP2N.js";
|
|
21
21
|
import {
|
|
22
22
|
getFileSystemProviderV2
|
|
23
23
|
} from "./chunk-XAMILHQP.js";
|
|
@@ -31,7 +31,98 @@ import {
|
|
|
31
31
|
workspacePathDirname,
|
|
32
32
|
workspacePathJoin,
|
|
33
33
|
workspacePathToLegacy
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
35
|
+
|
|
36
|
+
// src/filesystem/wiki-links.ts
|
|
37
|
+
var markdownModule = null;
|
|
38
|
+
function loadMarkdown() {
|
|
39
|
+
markdownModule ?? (markdownModule = import("@bendyline/squisq/markdown"));
|
|
40
|
+
return markdownModule;
|
|
41
|
+
}
|
|
42
|
+
async function suggestWikiArticles(files, directories, documentPath, query, extension = ".md", explicitExtensions = false) {
|
|
43
|
+
const { wikiLinkPath } = await loadMarkdown();
|
|
44
|
+
if (query.length > 2048 || query && !wikiLinkPath(`${query.trimEnd()}x`)) return [];
|
|
45
|
+
const source = parseWorkspacePath(documentPath);
|
|
46
|
+
const parent = workspacePathDirname(source);
|
|
47
|
+
const rootPrefix = parent ? `${parent}/` : "";
|
|
48
|
+
const slash = query.lastIndexOf("/");
|
|
49
|
+
const prefix = query.slice(0, slash + 1);
|
|
50
|
+
const needle = query.slice(slash + 1).toLowerCase();
|
|
51
|
+
const candidates = [];
|
|
52
|
+
const relative = (path) => {
|
|
53
|
+
if (!path.startsWith(rootPrefix)) return null;
|
|
54
|
+
const target = path.slice(rootPrefix.length);
|
|
55
|
+
if (!target.startsWith(prefix)) return null;
|
|
56
|
+
const name = target.slice(prefix.length);
|
|
57
|
+
return name && !name.includes("/") && name.toLowerCase().includes(needle) ? target : null;
|
|
58
|
+
};
|
|
59
|
+
for (const directory of directories) {
|
|
60
|
+
const target = relative(directory);
|
|
61
|
+
if (target && target.length < 2048 && wikiLinkPath(target))
|
|
62
|
+
candidates.push({
|
|
63
|
+
target: `${target}/`,
|
|
64
|
+
label: `${target.slice(prefix.length)}/`,
|
|
65
|
+
kind: "folder"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const articlePaths = new Set(files.map((file) => file.path));
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
if (file.path === source || !/\.(?:md|html?)$/i.test(file.path)) continue;
|
|
71
|
+
const target = relative(file.path);
|
|
72
|
+
if (!target || !wikiLinkPath(target)) continue;
|
|
73
|
+
const stem = file.path.replace(/\.(?:md|html?)$/i, "");
|
|
74
|
+
const preferred = [`${stem}${extension}`, `${stem}.md`, `${stem}.html`, `${stem}.htm`].find(
|
|
75
|
+
(path) => articlePaths.has(path)
|
|
76
|
+
);
|
|
77
|
+
const insertion = !explicitExtensions && file.path === preferred ? target.replace(/\.(?:md|html?)$/i, "") : target;
|
|
78
|
+
candidates.push({ target: insertion, label: insertion.slice(prefix.length), kind: "article" });
|
|
79
|
+
}
|
|
80
|
+
return candidates.sort(
|
|
81
|
+
(a, b) => Number(b.kind === "folder") - Number(a.kind === "folder") || Number(b.label.toLowerCase().startsWith(needle)) - Number(a.label.toLowerCase().startsWith(needle)) || a.label.localeCompare(b.label) || a.target.localeCompare(b.target)
|
|
82
|
+
).slice(0, 20);
|
|
83
|
+
}
|
|
84
|
+
async function resolveWikiArticlePath(documentPath, target, extension = ".md") {
|
|
85
|
+
const { wikiLinkPath } = await loadMarkdown();
|
|
86
|
+
const relative = wikiLinkPath(target, extension);
|
|
87
|
+
if (!relative) throw new FsError("invalid-path", "Invalid wiki article name.");
|
|
88
|
+
return workspacePathJoin(workspacePathDirname(parseWorkspacePath(documentPath)), relative);
|
|
89
|
+
}
|
|
90
|
+
async function findWikiArticle(provider, documentPath, target, extension = ".md") {
|
|
91
|
+
const { wikiLinkPath } = await loadMarkdown();
|
|
92
|
+
const preferred = await resolveWikiArticlePath(documentPath, target, extension);
|
|
93
|
+
const candidates = /\.(?:md|html?)$/i.test(target) ? [target] : [.../* @__PURE__ */ new Set([`${target}${extension}`, `${target}.md`, `${target}.html`, `${target}.htm`])];
|
|
94
|
+
for (const relativePath of candidates) {
|
|
95
|
+
const path = await resolveWikiArticlePath(documentPath, relativePath, extension);
|
|
96
|
+
if (await wikiArticleExists(provider, path)) return { path, relativePath, exists: true };
|
|
97
|
+
}
|
|
98
|
+
return { path: preferred, relativePath: wikiLinkPath(target, extension), exists: false };
|
|
99
|
+
}
|
|
100
|
+
async function wikiArticleExists(provider, path) {
|
|
101
|
+
const v2 = getFileSystemProviderV2(provider);
|
|
102
|
+
if (!v2) return await provider.stat(path) !== null;
|
|
103
|
+
const entry = await v2.stat(path);
|
|
104
|
+
if (entry && entry.kind !== "file")
|
|
105
|
+
throw new FsError("type-mismatch", "The article path is a folder.");
|
|
106
|
+
return entry !== null;
|
|
107
|
+
}
|
|
108
|
+
async function ensureWikiArticle(provider, path) {
|
|
109
|
+
if (await wikiArticleExists(provider, path)) return false;
|
|
110
|
+
const v2 = getFileSystemProviderV2(provider);
|
|
111
|
+
if (!v2) throw new FsError("not-supported", "This workspace cannot create articles safely.");
|
|
112
|
+
try {
|
|
113
|
+
await v2.writeFile(path, new Uint8Array(), {
|
|
114
|
+
mode: "create",
|
|
115
|
+
expectedVersion: null,
|
|
116
|
+
createParents: true
|
|
117
|
+
});
|
|
118
|
+
return true;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (error instanceof FsError && (error.code === "already-exists" || error.code === "conflict")) {
|
|
121
|
+
if (await wikiArticleExists(provider, path)) return false;
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
35
126
|
|
|
36
127
|
// src/filesystem/legacy-v2-adapter.ts
|
|
37
128
|
var EPOCH = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
@@ -1104,6 +1195,11 @@ function createFileMediaProvider(container, markdownBasename) {
|
|
|
1104
1195
|
}
|
|
1105
1196
|
|
|
1106
1197
|
export {
|
|
1198
|
+
suggestWikiArticles,
|
|
1199
|
+
resolveWikiArticlePath,
|
|
1200
|
+
findWikiArticle,
|
|
1201
|
+
wikiArticleExists,
|
|
1202
|
+
ensureWikiArticle,
|
|
1107
1203
|
LegacyFileSystemProviderV2Adapter,
|
|
1108
1204
|
rewriteCompanionReferences,
|
|
1109
1205
|
documentCompanionPath,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HostFileSystemProviderV2
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7LPIGCBG.js";
|
|
4
4
|
import {
|
|
5
5
|
ELECTRON_FILE_SYSTEM_V2_CAPABILITIES,
|
|
6
6
|
maybeGetDocBlocksHost
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KXQDMZFH.js";
|
|
8
8
|
|
|
9
9
|
// src/filesystem/electron-provider-v2.ts
|
|
10
10
|
var ElectronFileSystemProviderV2 = class extends HostFileSystemProviderV2 {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-DZB666V7.js";
|
|
8
8
|
import {
|
|
9
9
|
parentChainWithRoot
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3GSMJ4MQ.js";
|
|
11
11
|
import {
|
|
12
12
|
isRecord
|
|
13
13
|
} from "./chunk-73OOROXH.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from "./chunk-LPIJ6HKL.js";
|
|
23
23
|
import {
|
|
24
24
|
decodeUtf8Text
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-IYKGM3PV.js";
|
|
26
26
|
import {
|
|
27
27
|
FsError,
|
|
28
28
|
WORKSPACE_ROOT,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
workspacePathBasename,
|
|
32
32
|
workspacePathContains,
|
|
33
33
|
workspacePathDirname
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
35
35
|
|
|
36
36
|
// src/filesystem/indexeddb-provider-v2.ts
|
|
37
37
|
var ENTRY_SCHEMA_VERSION = 1;
|
|
@@ -17,6 +17,9 @@ var FS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
17
17
|
"aborted",
|
|
18
18
|
"io"
|
|
19
19
|
]);
|
|
20
|
+
function isFsErrorCode(value) {
|
|
21
|
+
return typeof value === "string" && FS_ERROR_CODES.has(value);
|
|
22
|
+
}
|
|
20
23
|
var FS_OPERATIONS = /* @__PURE__ */ new Set([
|
|
21
24
|
"parse-path",
|
|
22
25
|
"read",
|
|
@@ -109,7 +112,7 @@ function mapNodeErrorCodeToFsErrorCode(code) {
|
|
|
109
112
|
function isSerializedFsError(value) {
|
|
110
113
|
if (!value || typeof value !== "object") return false;
|
|
111
114
|
const candidate = value;
|
|
112
|
-
return candidate.name === "FsError" &&
|
|
115
|
+
return candidate.name === "FsError" && isFsErrorCode(candidate.code) && typeof candidate.message === "string" && (candidate.operation === null || typeof candidate.operation === "string" && FS_OPERATIONS.has(candidate.operation)) && (candidate.path === null || typeof candidate.path === "string") && (candidate.destinationPath === null || typeof candidate.destinationPath === "string") && typeof candidate.retryable === "boolean";
|
|
113
116
|
}
|
|
114
117
|
function deserializeFsError(value) {
|
|
115
118
|
return new FsError(value.code, value.message, {
|
|
@@ -205,6 +208,7 @@ function invalidPath(path, message) {
|
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
export {
|
|
211
|
+
isFsErrorCode,
|
|
208
212
|
FsError,
|
|
209
213
|
mapDomExceptionToFsErrorCode,
|
|
210
214
|
mapNodeErrorCodeToFsErrorCode,
|
|
@@ -4,6 +4,166 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
getFileSystemProviderV2
|
|
6
6
|
} from "./chunk-XAMILHQP.js";
|
|
7
|
+
import {
|
|
8
|
+
parseWorkspacePath
|
|
9
|
+
} from "./chunk-UTH3HYCZ.js";
|
|
10
|
+
|
|
11
|
+
// src/workspace/backup.ts
|
|
12
|
+
var WORKSPACE_BACKUP_MANIFEST = "docblocks-backup.json";
|
|
13
|
+
var WORKSPACE_BACKUP_LIMITS = Object.freeze({
|
|
14
|
+
maxEntries: 1e4,
|
|
15
|
+
maxUncompressedBytes: 128 * 1024 * 1024,
|
|
16
|
+
maxEntryUncompressedBytes: 64 * 1024 * 1024,
|
|
17
|
+
maxCompressionRatio: 1e3
|
|
18
|
+
});
|
|
19
|
+
function exactRecord(value, keys) {
|
|
20
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
21
|
+
throw new Error("Invalid workspace backup metadata.");
|
|
22
|
+
}
|
|
23
|
+
const record = value;
|
|
24
|
+
if (Object.keys(record).length !== keys.length || keys.some((key) => !(key in record))) {
|
|
25
|
+
throw new Error("Unrecognized workspace backup metadata fields.");
|
|
26
|
+
}
|
|
27
|
+
return record;
|
|
28
|
+
}
|
|
29
|
+
function entryPath(value) {
|
|
30
|
+
if (typeof value !== "string" || value.length > 4096)
|
|
31
|
+
throw new Error("Invalid backup entry path.");
|
|
32
|
+
const path = parseWorkspacePath(value);
|
|
33
|
+
if (!path || path !== value)
|
|
34
|
+
throw new Error("Backup entries must have canonical relative paths.");
|
|
35
|
+
return path;
|
|
36
|
+
}
|
|
37
|
+
function parseWorkspaceBackupManifest(value) {
|
|
38
|
+
const record = exactRecord(value, ["format", "version", "workspaces"]);
|
|
39
|
+
if (record.format !== "docblocks-workspace-backup" || record.version !== 1) {
|
|
40
|
+
throw new Error("This workspace backup version is not supported.");
|
|
41
|
+
}
|
|
42
|
+
if (!Array.isArray(record.workspaces) || !record.workspaces.length || record.workspaces.length > 100) {
|
|
43
|
+
throw new Error("A backup must contain between 1 and 100 workspaces.");
|
|
44
|
+
}
|
|
45
|
+
let directoryCount = 0;
|
|
46
|
+
const workspaces = record.workspaces.map((value2, index) => {
|
|
47
|
+
const workspace = exactRecord(value2, ["name", "prefix", "directories"]);
|
|
48
|
+
if (typeof workspace.name !== "string" || !workspace.name.trim() || workspace.name.length > 1024) {
|
|
49
|
+
throw new Error("Invalid backup workspace name.");
|
|
50
|
+
}
|
|
51
|
+
if (workspace.prefix !== `workspaces/${index + 1}` || !Array.isArray(workspace.directories)) {
|
|
52
|
+
throw new Error("Invalid backup workspace location.");
|
|
53
|
+
}
|
|
54
|
+
directoryCount += workspace.directories.length;
|
|
55
|
+
if (directoryCount > WORKSPACE_BACKUP_LIMITS.maxEntries)
|
|
56
|
+
throw new Error("Too many backup directories.");
|
|
57
|
+
const directories = workspace.directories.map(entryPath);
|
|
58
|
+
if (new Set(directories).size !== directories.length)
|
|
59
|
+
throw new Error("Duplicate backup directories.");
|
|
60
|
+
return { name: workspace.name, prefix: workspace.prefix, directories };
|
|
61
|
+
});
|
|
62
|
+
return { format: "docblocks-workspace-backup", version: 1, workspaces };
|
|
63
|
+
}
|
|
64
|
+
async function appendWorkspaceBackup(container, provider, previous) {
|
|
65
|
+
const snapshot = await provider.snapshot();
|
|
66
|
+
const workspace = {
|
|
67
|
+
name: provider.label || "Workspace",
|
|
68
|
+
prefix: `workspaces/${previous.length + 1}`,
|
|
69
|
+
directories: snapshot.entries.filter((entry) => entry.kind === "directory" && entry.path !== "").map((entry) => entry.path)
|
|
70
|
+
};
|
|
71
|
+
const workspaces = [...previous, workspace];
|
|
72
|
+
parseWorkspaceBackupManifest({ format: "docblocks-workspace-backup", version: 1, workspaces });
|
|
73
|
+
for (const entry of snapshot.entries) {
|
|
74
|
+
if (entry.kind === "file") {
|
|
75
|
+
entryPath(entry.path);
|
|
76
|
+
if (entry.data.byteLength > WORKSPACE_BACKUP_LIMITS.maxEntryUncompressedBytes) {
|
|
77
|
+
throw new Error(`Backup file exceeds the 64 MiB restore limit: ${entry.path}`);
|
|
78
|
+
}
|
|
79
|
+
await container.writeFile(`${workspace.prefix}/${entry.path}`, entry.data);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return workspaces;
|
|
83
|
+
}
|
|
84
|
+
async function finishWorkspaceBackup(container, workspaces) {
|
|
85
|
+
const manifest = parseWorkspaceBackupManifest({
|
|
86
|
+
format: "docblocks-workspace-backup",
|
|
87
|
+
version: 1,
|
|
88
|
+
workspaces
|
|
89
|
+
});
|
|
90
|
+
const bytes = new TextEncoder().encode(JSON.stringify(manifest));
|
|
91
|
+
if (bytes.byteLength > 1024 * 1024) throw new Error("Workspace backup metadata is too large.");
|
|
92
|
+
await container.writeFile(WORKSPACE_BACKUP_MANIFEST, bytes);
|
|
93
|
+
await readWorkspaceBackup(container, "Workspace");
|
|
94
|
+
}
|
|
95
|
+
async function readWorkspaceBackup(container, legacyName) {
|
|
96
|
+
const entries = await container.listFiles();
|
|
97
|
+
if (entries.length > WORKSPACE_BACKUP_LIMITS.maxEntries)
|
|
98
|
+
throw new Error("Too many backup files.");
|
|
99
|
+
const paths = entries.map((entry) => entryPath(entry.path));
|
|
100
|
+
if (new Set(paths).size !== paths.length) throw new Error("Duplicate backup files.");
|
|
101
|
+
const archiveEntries = new Set(paths);
|
|
102
|
+
for (const path of paths) {
|
|
103
|
+
const parts = path.split("/");
|
|
104
|
+
while (parts.length > 1) {
|
|
105
|
+
parts.pop();
|
|
106
|
+
archiveEntries.add(`${parts.join("/")}/`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (archiveEntries.size > WORKSPACE_BACKUP_LIMITS.maxEntries)
|
|
110
|
+
throw new Error("Too many backup entries.");
|
|
111
|
+
const metadata = paths.includes(parseWorkspacePath(WORKSPACE_BACKUP_MANIFEST)) ? await container.readFile(WORKSPACE_BACKUP_MANIFEST) : null;
|
|
112
|
+
if (metadata && metadata.byteLength > 1024 * 1024)
|
|
113
|
+
throw new Error("Workspace backup metadata is too large.");
|
|
114
|
+
const manifest = metadata ? parseWorkspaceBackupManifest(
|
|
115
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(metadata))
|
|
116
|
+
) : null;
|
|
117
|
+
const workspaces = manifest?.workspaces ?? [{ name: legacyName, prefix: "", directories: [] }];
|
|
118
|
+
if (paths.length + workspaces.reduce((count, workspace) => count + workspace.directories.length, 0) > WORKSPACE_BACKUP_LIMITS.maxEntries) {
|
|
119
|
+
throw new Error("Too many backup files and directories.");
|
|
120
|
+
}
|
|
121
|
+
const result = workspaces.map((workspace) => ({
|
|
122
|
+
...workspace,
|
|
123
|
+
files: []
|
|
124
|
+
}));
|
|
125
|
+
let total = metadata?.byteLength ?? 0;
|
|
126
|
+
for (const path of paths) {
|
|
127
|
+
if (manifest && path === WORKSPACE_BACKUP_MANIFEST) continue;
|
|
128
|
+
const index = manifest ? workspaces.findIndex((workspace) => path.startsWith(`${workspace.prefix}/`)) : 0;
|
|
129
|
+
if (index < 0) throw new Error(`Backup file is outside its workspace: ${path}`);
|
|
130
|
+
const relative = entryPath(manifest ? path.slice(workspaces[index].prefix.length + 1) : path);
|
|
131
|
+
const data = await container.readFile(path);
|
|
132
|
+
if (!data) throw new Error(`Backup file is missing: ${path}`);
|
|
133
|
+
total += data.byteLength;
|
|
134
|
+
if (data.byteLength > WORKSPACE_BACKUP_LIMITS.maxEntryUncompressedBytes || total > WORKSPACE_BACKUP_LIMITS.maxUncompressedBytes) {
|
|
135
|
+
throw new Error("Workspace backup exceeds the restore size limits.");
|
|
136
|
+
}
|
|
137
|
+
result[index].files.push({ path: relative, data });
|
|
138
|
+
}
|
|
139
|
+
for (const workspace of result) {
|
|
140
|
+
const files = new Set(workspace.files.map((file) => file.path));
|
|
141
|
+
for (const path of [...workspace.directories, ...files]) {
|
|
142
|
+
if (workspace.directories.includes(path) && files.has(path))
|
|
143
|
+
throw new Error(`Conflicting backup entry: ${path}`);
|
|
144
|
+
const parts = path.split("/");
|
|
145
|
+
while (parts.length > 1) {
|
|
146
|
+
parts.pop();
|
|
147
|
+
if (files.has(parseWorkspacePath(parts.join("/"))))
|
|
148
|
+
throw new Error(`Backup file is also a parent directory: ${path}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
async function restoreWorkspaceBackup(workspace, provider) {
|
|
155
|
+
if ((await provider.readDirectory(parseWorkspacePath(""))).length)
|
|
156
|
+
throw new Error("Restore requires a new, empty workspace.");
|
|
157
|
+
for (const path of workspace.directories)
|
|
158
|
+
await provider.createDirectory(path, { createParents: true });
|
|
159
|
+
for (const file of workspace.files) {
|
|
160
|
+
await provider.writeFile(file.path, file.data, {
|
|
161
|
+
mode: "create",
|
|
162
|
+
createParents: true,
|
|
163
|
+
expectedVersion: null
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
7
167
|
|
|
8
168
|
// src/workspace/workspace-schema.ts
|
|
9
169
|
var MAX_IDENTIFIER_CHARACTERS = 256;
|
|
@@ -214,6 +374,13 @@ function reconcileElectronWorkspaceDescriptors(local, hostWorkspaces, platform,
|
|
|
214
374
|
}
|
|
215
375
|
|
|
216
376
|
export {
|
|
377
|
+
WORKSPACE_BACKUP_MANIFEST,
|
|
378
|
+
WORKSPACE_BACKUP_LIMITS,
|
|
379
|
+
parseWorkspaceBackupManifest,
|
|
380
|
+
appendWorkspaceBackup,
|
|
381
|
+
finishWorkspaceBackup,
|
|
382
|
+
readWorkspaceBackup,
|
|
383
|
+
restoreWorkspaceBackup,
|
|
217
384
|
parsePersistedWorkspaceList,
|
|
218
385
|
DEFAULT_WORKSPACE_ID,
|
|
219
386
|
registerTransientWorkspace,
|
package/dist/document/index.d.ts
CHANGED
package/dist/document/index.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
DocumentSession,
|
|
10
10
|
DocumentSessionConflictError,
|
|
11
11
|
createFileSystemDocumentTarget
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-FIEMYP2N.js";
|
|
13
13
|
import "../chunk-XAMILHQP.js";
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-IYKGM3PV.js";
|
|
15
|
+
import "../chunk-UTH3HYCZ.js";
|
|
16
16
|
export {
|
|
17
17
|
DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION,
|
|
18
18
|
DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY,
|