@bendyline/docblocks 2.0.0 → 2.1.1
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/README.md +2 -2
- package/dist/{chunk-2D7Y4IR3.js → chunk-4437YWLE.js} +123 -67
- package/dist/{chunk-5MYAICRE.js → chunk-45T5AFCN.js} +44 -57
- package/dist/{chunk-PGR7LK6D.js → chunk-6L3JRDE7.js} +14 -6
- package/dist/{chunk-RVQHY3XU.js → chunk-6XHOOBYF.js} +0 -1
- package/dist/chunk-73OOROXH.js +8 -0
- package/dist/{chunk-SI2LU2RP.js → chunk-AYWKIZLD.js} +1 -1
- package/dist/{chunk-GCPBEMMH.js → chunk-BVY7GGNV.js} +10 -21
- package/dist/{chunk-AEHCVWU5.js → chunk-DZB666V7.js} +0 -1
- package/dist/{chunk-75UUF6C4.js → chunk-HI7QEWL6.js} +18 -10
- package/dist/chunk-KQ6756AJ.js +28 -0
- package/dist/chunk-LMMOFRGQ.js +148 -0
- package/dist/{chunk-FNW556FN.js → chunk-M2PUNKHS.js} +0 -1
- package/dist/chunk-M5ZNQGR5.js +19 -0
- package/dist/chunk-M62ZGJ5I.js +51 -0
- package/dist/chunk-OQCPBOQA.js +168 -0
- package/dist/{chunk-EGNDADXB.js → chunk-QI6YKTQV.js} +2 -3
- package/dist/chunk-SJBB5OD7.js +227 -0
- package/dist/{chunk-EZKJZUNJ.js → chunk-XAMILHQP.js} +0 -1
- package/dist/{chunk-J32GU3F3.js → chunk-YM7O3PWO.js} +249 -222
- package/dist/{chunk-RQJRQF46.js → chunk-ZO7G53QP.js} +41 -49
- package/dist/document/index.d.ts +358 -6
- package/dist/document/index.js +24 -4
- package/dist/filesystem/electron.d.ts +73 -4
- package/dist/filesystem/electron.js +16 -4
- package/dist/filesystem/index.d.ts +228 -22
- package/dist/filesystem/index.js +133 -20
- package/dist/filesystem/indexeddb.d.ts +284 -5
- package/dist/filesystem/indexeddb.js +22 -5
- package/dist/filesystem/memory.d.ts +152 -4
- package/dist/filesystem/memory.js +12 -4
- package/dist/filesystem/native.d.ts +136 -4
- package/dist/filesystem/native.js +27 -4
- package/dist/host/index.d.ts +32 -9
- package/dist/host/index.js +26 -30
- package/dist/index.d.ts +14 -10
- package/dist/index.js +204 -10
- package/dist/mcp/index.d.ts +33 -4
- package/dist/mcp/index.js +31 -4
- package/dist/mcp/zod.d.ts +645 -643
- package/dist/mcp/zod.js +700 -885
- package/dist/share/index.d.ts +43 -0
- package/dist/share/index.js +12 -0
- package/dist/{types-CsX6EN2t.d.ts → types-BEg5SQ1_.d.ts} +1 -1
- package/dist/{types-eOlt9J7n.d.ts → types-CueK0tvU.d.ts} +34 -11
- package/dist/vscode/index.d.ts +225 -3
- package/dist/vscode/index.js +389 -3
- package/dist/workspace/index.d.ts +141 -4
- package/dist/workspace/index.js +28 -3
- package/package.json +10 -5
- package/dist/chunk-2D7Y4IR3.js.map +0 -1
- package/dist/chunk-5MYAICRE.js.map +0 -1
- package/dist/chunk-75UUF6C4.js.map +0 -1
- package/dist/chunk-AEHCVWU5.js.map +0 -1
- package/dist/chunk-AYZ4HN5M.js +0 -20
- package/dist/chunk-AYZ4HN5M.js.map +0 -1
- package/dist/chunk-EGNDADXB.js.map +0 -1
- package/dist/chunk-EZKJZUNJ.js.map +0 -1
- package/dist/chunk-FNW556FN.js.map +0 -1
- package/dist/chunk-GCPBEMMH.js.map +0 -1
- package/dist/chunk-J32GU3F3.js.map +0 -1
- package/dist/chunk-PGR7LK6D.js.map +0 -1
- package/dist/chunk-RQJRQF46.js.map +0 -1
- package/dist/chunk-RVQHY3XU.js.map +0 -1
- package/dist/chunk-SI2LU2RP.js.map +0 -1
- package/dist/chunk-W5UUUII5.js +0 -142
- package/dist/chunk-W5UUUII5.js.map +0 -1
- package/dist/document/document-session.d.ts +0 -127
- package/dist/document/document-session.d.ts.map +0 -1
- package/dist/document/document-session.js +0 -749
- package/dist/document/document-session.js.map +0 -1
- package/dist/document/filesystem-target.d.ts +0 -17
- package/dist/document/filesystem-target.d.ts.map +0 -1
- package/dist/document/filesystem-target.js +0 -70
- package/dist/document/filesystem-target.js.map +0 -1
- package/dist/document/index.d.ts.map +0 -1
- package/dist/document/index.js.map +0 -1
- package/dist/document/recovery-journal.d.ts +0 -125
- package/dist/document/recovery-journal.d.ts.map +0 -1
- package/dist/document/recovery-journal.js +0 -385
- package/dist/document/recovery-journal.js.map +0 -1
- package/dist/document/types.d.ts +0 -89
- package/dist/document/types.d.ts.map +0 -1
- package/dist/document/types.js +0 -9
- package/dist/document/types.js.map +0 -1
- package/dist/filesystem/commit-lock.d.ts +0 -3
- package/dist/filesystem/commit-lock.d.ts.map +0 -1
- package/dist/filesystem/commit-lock.js +0 -20
- package/dist/filesystem/commit-lock.js.map +0 -1
- package/dist/filesystem/dbk-workspace.d.ts +0 -34
- package/dist/filesystem/dbk-workspace.d.ts.map +0 -1
- package/dist/filesystem/dbk-workspace.js +0 -85
- package/dist/filesystem/dbk-workspace.js.map +0 -1
- package/dist/filesystem/electron-provider-v2.d.ts +0 -36
- package/dist/filesystem/electron-provider-v2.d.ts.map +0 -1
- package/dist/filesystem/electron-provider-v2.js +0 -503
- package/dist/filesystem/electron-provider-v2.js.map +0 -1
- package/dist/filesystem/electron-provider.d.ts +0 -35
- package/dist/filesystem/electron-provider.d.ts.map +0 -1
- package/dist/filesystem/electron-provider.js +0 -69
- package/dist/filesystem/electron-provider.js.map +0 -1
- package/dist/filesystem/electron.d.ts.map +0 -1
- package/dist/filesystem/electron.js.map +0 -1
- package/dist/filesystem/file-media-provider.d.ts +0 -23
- package/dist/filesystem/file-media-provider.d.ts.map +0 -1
- package/dist/filesystem/file-media-provider.js +0 -85
- package/dist/filesystem/file-media-provider.js.map +0 -1
- package/dist/filesystem/filesystem-content-container.d.ts +0 -24
- package/dist/filesystem/filesystem-content-container.d.ts.map +0 -1
- package/dist/filesystem/filesystem-content-container.js +0 -153
- package/dist/filesystem/filesystem-content-container.js.map +0 -1
- package/dist/filesystem/fs-error.d.ts +0 -46
- package/dist/filesystem/fs-error.d.ts.map +0 -1
- package/dist/filesystem/fs-error.js +0 -170
- package/dist/filesystem/fs-error.js.map +0 -1
- package/dist/filesystem/index.d.ts.map +0 -1
- package/dist/filesystem/index.js.map +0 -1
- package/dist/filesystem/indexeddb-content-container.d.ts +0 -22
- package/dist/filesystem/indexeddb-content-container.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-content-container.js +0 -100
- package/dist/filesystem/indexeddb-content-container.js.map +0 -1
- package/dist/filesystem/indexeddb-provider-v2.d.ts +0 -96
- package/dist/filesystem/indexeddb-provider-v2.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-provider-v2.js +0 -1241
- package/dist/filesystem/indexeddb-provider-v2.js.map +0 -1
- package/dist/filesystem/indexeddb-provider.d.ts +0 -39
- package/dist/filesystem/indexeddb-provider.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-provider.js +0 -145
- package/dist/filesystem/indexeddb-provider.js.map +0 -1
- package/dist/filesystem/indexeddb-store.d.ts +0 -34
- package/dist/filesystem/indexeddb-store.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-store.js +0 -165
- package/dist/filesystem/indexeddb-store.js.map +0 -1
- package/dist/filesystem/indexeddb.d.ts.map +0 -1
- package/dist/filesystem/indexeddb.js.map +0 -1
- package/dist/filesystem/legacy-v2-adapter.d.ts +0 -62
- package/dist/filesystem/legacy-v2-adapter.d.ts.map +0 -1
- package/dist/filesystem/legacy-v2-adapter.js +0 -499
- package/dist/filesystem/legacy-v2-adapter.js.map +0 -1
- package/dist/filesystem/memory-provider-v2.d.ts +0 -92
- package/dist/filesystem/memory-provider-v2.d.ts.map +0 -1
- package/dist/filesystem/memory-provider-v2.js +0 -615
- package/dist/filesystem/memory-provider-v2.js.map +0 -1
- package/dist/filesystem/memory-provider.d.ts +0 -54
- package/dist/filesystem/memory-provider.d.ts.map +0 -1
- package/dist/filesystem/memory-provider.js +0 -132
- package/dist/filesystem/memory-provider.js.map +0 -1
- package/dist/filesystem/memory.d.ts.map +0 -1
- package/dist/filesystem/memory.js.map +0 -1
- package/dist/filesystem/move-entry.d.ts +0 -9
- package/dist/filesystem/move-entry.d.ts.map +0 -1
- package/dist/filesystem/move-entry.js +0 -103
- package/dist/filesystem/move-entry.js.map +0 -1
- package/dist/filesystem/move-error.d.ts +0 -53
- package/dist/filesystem/move-error.d.ts.map +0 -1
- package/dist/filesystem/move-error.js +0 -99
- package/dist/filesystem/move-error.js.map +0 -1
- package/dist/filesystem/native-provider-v2.d.ts +0 -75
- package/dist/filesystem/native-provider-v2.d.ts.map +0 -1
- package/dist/filesystem/native-provider-v2.js +0 -849
- package/dist/filesystem/native-provider-v2.js.map +0 -1
- package/dist/filesystem/native-provider.d.ts +0 -53
- package/dist/filesystem/native-provider.d.ts.map +0 -1
- package/dist/filesystem/native-provider.js +0 -471
- package/dist/filesystem/native-provider.js.map +0 -1
- package/dist/filesystem/native.d.ts.map +0 -1
- package/dist/filesystem/native.js.map +0 -1
- package/dist/filesystem/types.d.ts +0 -83
- package/dist/filesystem/types.d.ts.map +0 -1
- package/dist/filesystem/types.js +0 -16
- package/dist/filesystem/types.js.map +0 -1
- package/dist/filesystem/v2.d.ts +0 -172
- package/dist/filesystem/v2.d.ts.map +0 -1
- package/dist/filesystem/v2.js +0 -16
- package/dist/filesystem/v2.js.map +0 -1
- package/dist/filesystem/workspace-path.d.ts +0 -21
- package/dist/filesystem/workspace-path.d.ts.map +0 -1
- package/dist/filesystem/workspace-path.js +0 -80
- package/dist/filesystem/workspace-path.js.map +0 -1
- package/dist/host/filesystem-v2.d.ts +0 -45
- package/dist/host/filesystem-v2.d.ts.map +0 -1
- package/dist/host/filesystem-v2.js +0 -13
- package/dist/host/filesystem-v2.js.map +0 -1
- package/dist/host/git.d.ts +0 -200
- package/dist/host/git.d.ts.map +0 -1
- package/dist/host/git.js +0 -15
- package/dist/host/git.js.map +0 -1
- package/dist/host/index.d.ts.map +0 -1
- package/dist/host/index.js.map +0 -1
- package/dist/host/types.d.ts +0 -232
- package/dist/host/types.d.ts.map +0 -1
- package/dist/host/types.js +0 -10
- package/dist/host/types.js.map +0 -1
- package/dist/host/wire-policy.d.ts +0 -22
- package/dist/host/wire-policy.d.ts.map +0 -1
- package/dist/host/wire-policy.js +0 -92
- package/dist/host/wire-policy.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -466
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js +0 -25
- package/dist/mcp/types.js.map +0 -1
- package/dist/mcp/wire.d.ts +0 -29
- package/dist/mcp/wire.d.ts.map +0 -1
- package/dist/mcp/wire.js +0 -1046
- package/dist/mcp/wire.js.map +0 -1
- package/dist/mcp/zod.d.ts.map +0 -1
- package/dist/mcp/zod.js.map +0 -1
- package/dist/vscode/index.d.ts.map +0 -1
- package/dist/vscode/index.js.map +0 -1
- package/dist/vscode/messages.d.ts +0 -204
- package/dist/vscode/messages.d.ts.map +0 -1
- package/dist/vscode/messages.js +0 -494
- package/dist/vscode/messages.js.map +0 -1
- package/dist/workspace/index.d.ts.map +0 -1
- package/dist/workspace/index.js.map +0 -1
- package/dist/workspace/reconcile-electron.d.ts +0 -19
- package/dist/workspace/reconcile-electron.d.ts.map +0 -1
- package/dist/workspace/reconcile-electron.js +0 -42
- package/dist/workspace/reconcile-electron.js.map +0 -1
- package/dist/workspace/types.d.ts +0 -69
- package/dist/workspace/types.d.ts.map +0 -1
- package/dist/workspace/types.js +0 -2
- package/dist/workspace/types.js.map +0 -1
- package/dist/workspace/workspace-manager.d.ts +0 -47
- package/dist/workspace/workspace-manager.d.ts.map +0 -1
- package/dist/workspace/workspace-manager.js +0 -126
- package/dist/workspace/workspace-manager.js.map +0 -1
- package/src/document/document-session.ts +0 -834
- package/src/document/filesystem-target.ts +0 -109
- package/src/document/index.ts +0 -41
- package/src/document/recovery-journal.ts +0 -536
- package/src/document/types.ts +0 -116
- package/src/filesystem/commit-lock.ts +0 -29
- package/src/filesystem/dbk-workspace.ts +0 -135
- package/src/filesystem/electron-provider-v2.ts +0 -630
- package/src/filesystem/electron-provider.ts +0 -99
- package/src/filesystem/electron.ts +0 -3
- package/src/filesystem/file-media-provider.ts +0 -103
- package/src/filesystem/filesystem-content-container.ts +0 -164
- package/src/filesystem/fs-error.ts +0 -234
- package/src/filesystem/index.ts +0 -143
- package/src/filesystem/indexeddb-content-container.ts +0 -112
- package/src/filesystem/indexeddb-provider-v2.ts +0 -1740
- package/src/filesystem/indexeddb-provider.ts +0 -171
- package/src/filesystem/indexeddb-store.ts +0 -207
- package/src/filesystem/indexeddb.ts +0 -12
- package/src/filesystem/legacy-v2-adapter.ts +0 -779
- package/src/filesystem/memory-provider-v2.ts +0 -896
- package/src/filesystem/memory-provider.ts +0 -180
- package/src/filesystem/memory.ts +0 -15
- package/src/filesystem/move-entry.ts +0 -142
- package/src/filesystem/move-error.ts +0 -159
- package/src/filesystem/native-provider-v2.ts +0 -1165
- package/src/filesystem/native-provider.ts +0 -537
- package/src/filesystem/native.ts +0 -16
- package/src/filesystem/types.ts +0 -114
- package/src/filesystem/v2.ts +0 -231
- package/src/filesystem/workspace-path.ts +0 -92
- package/src/host/filesystem-v2.ts +0 -104
- package/src/host/git.ts +0 -246
- package/src/host/index.ts +0 -93
- package/src/host/types.ts +0 -274
- package/src/host/wire-policy.ts +0 -103
- package/src/index.ts +0 -10
- package/src/mcp/index.ts +0 -3
- package/src/mcp/types.ts +0 -594
- package/src/mcp/wire.ts +0 -1280
- package/src/mcp/zod.ts +0 -1000
- package/src/vscode/index.ts +0 -2
- package/src/vscode/messages.ts +0 -704
- package/src/workspace/index.ts +0 -17
- package/src/workspace/reconcile-electron.ts +0 -65
- package/src/workspace/types.ts +0 -67
- package/src/workspace/workspace-manager.ts +0 -151
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NativeFileSystemProvider — wraps the File System Access API
|
|
3
|
-
* (window.showDirectoryPicker / FileSystemDirectoryHandle).
|
|
4
|
-
*
|
|
5
|
-
* Progressive enhancement: only available in browsers that support
|
|
6
|
-
* the API (Chrome, Edge). Feature-detect with `isNativeFileSystemSupported()`.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { FileCommitResult, FileSystemProvider, FileSystemEntry, FileMeta } from './types.js';
|
|
10
|
-
import { withFileCommitLock } from './commit-lock.js';
|
|
11
|
-
import { NativeFileSystemProviderV2 } from './native-provider-v2.js';
|
|
12
|
-
import { parseWorkspacePath } from './workspace-path.js';
|
|
13
|
-
|
|
14
|
-
// ── Feature detection ──────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
export function isNativeFileSystemSupported(): boolean {
|
|
17
|
-
return (
|
|
18
|
-
typeof globalThis !== 'undefined' &&
|
|
19
|
-
typeof (globalThis as { showDirectoryPicker?: unknown }).showDirectoryPicker === 'function'
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ── Handle persistence (IndexedDB, structured clone) ───────────────
|
|
24
|
-
|
|
25
|
-
const HANDLE_DB_NAME = 'docblocks-handles';
|
|
26
|
-
const HANDLE_STORE_NAME = 'directory-handles';
|
|
27
|
-
|
|
28
|
-
function openHandleDB(): Promise<IDBDatabase> {
|
|
29
|
-
return new Promise((resolve, reject) => {
|
|
30
|
-
const req = indexedDB.open(HANDLE_DB_NAME, 1);
|
|
31
|
-
req.onupgradeneeded = () => {
|
|
32
|
-
req.result.createObjectStore(HANDLE_STORE_NAME);
|
|
33
|
-
};
|
|
34
|
-
req.onsuccess = () => resolve(req.result);
|
|
35
|
-
req.onerror = () => reject(req.error);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Persist a FileSystemDirectoryHandle so it survives page reloads. */
|
|
40
|
-
export async function storeDirectoryHandle(
|
|
41
|
-
workspaceId: string,
|
|
42
|
-
handle: FileSystemDirectoryHandle,
|
|
43
|
-
): Promise<void> {
|
|
44
|
-
const db = await openHandleDB();
|
|
45
|
-
return new Promise((resolve, reject) => {
|
|
46
|
-
const tx = db.transaction(HANDLE_STORE_NAME, 'readwrite');
|
|
47
|
-
tx.objectStore(HANDLE_STORE_NAME).put(handle, workspaceId);
|
|
48
|
-
tx.oncomplete = () => {
|
|
49
|
-
db.close();
|
|
50
|
-
resolve();
|
|
51
|
-
};
|
|
52
|
-
tx.onerror = () => {
|
|
53
|
-
db.close();
|
|
54
|
-
reject(tx.error);
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Retrieve a previously stored handle. Returns null if not found. */
|
|
60
|
-
export async function loadDirectoryHandle(
|
|
61
|
-
workspaceId: string,
|
|
62
|
-
): Promise<FileSystemDirectoryHandle | null> {
|
|
63
|
-
const db = await openHandleDB();
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
const tx = db.transaction(HANDLE_STORE_NAME, 'readonly');
|
|
66
|
-
const req = tx.objectStore(HANDLE_STORE_NAME).get(workspaceId);
|
|
67
|
-
req.onsuccess = () => {
|
|
68
|
-
db.close();
|
|
69
|
-
resolve(req.result ?? null);
|
|
70
|
-
};
|
|
71
|
-
req.onerror = () => {
|
|
72
|
-
db.close();
|
|
73
|
-
reject(req.error);
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Remove a stored handle (e.g. when deleting a workspace). */
|
|
79
|
-
export async function removeDirectoryHandle(workspaceId: string): Promise<void> {
|
|
80
|
-
const db = await openHandleDB();
|
|
81
|
-
return new Promise((resolve, reject) => {
|
|
82
|
-
const tx = db.transaction(HANDLE_STORE_NAME, 'readwrite');
|
|
83
|
-
tx.objectStore(HANDLE_STORE_NAME).delete(workspaceId);
|
|
84
|
-
tx.oncomplete = () => {
|
|
85
|
-
db.close();
|
|
86
|
-
resolve();
|
|
87
|
-
};
|
|
88
|
-
tx.onerror = () => {
|
|
89
|
-
db.close();
|
|
90
|
-
reject(tx.error);
|
|
91
|
-
};
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ── Helpers ────────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
function normalisePath(p: string): string {
|
|
98
|
-
return parseWorkspacePath(p);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function errorName(error: unknown): string | undefined {
|
|
102
|
-
return typeof error === 'object' && error !== null && 'name' in error
|
|
103
|
-
? String((error as { name?: unknown }).name)
|
|
104
|
-
: undefined;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function isMissingEntryError(error: unknown): boolean {
|
|
108
|
-
const name = errorName(error);
|
|
109
|
-
return name === 'NotFoundError' || name === 'TypeMismatchError';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function isPermissionError(error: unknown): boolean {
|
|
113
|
-
const name = errorName(error);
|
|
114
|
-
return name === 'NotAllowedError' || name === 'SecurityError';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
class NativeMoveRecoveryError extends Error {
|
|
118
|
-
readonly causes: readonly unknown[];
|
|
119
|
-
|
|
120
|
-
constructor(message: string, causes: readonly unknown[]) {
|
|
121
|
-
super(message);
|
|
122
|
-
this.name = 'NativeMoveRecoveryError';
|
|
123
|
-
this.causes = causes;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Walk a chain of path segments to reach a FileSystemDirectoryHandle.
|
|
129
|
-
* Returns null if any segment is missing.
|
|
130
|
-
*/
|
|
131
|
-
async function resolveDir(
|
|
132
|
-
root: FileSystemDirectoryHandle,
|
|
133
|
-
dirPath: string,
|
|
134
|
-
): Promise<FileSystemDirectoryHandle | null> {
|
|
135
|
-
if (!dirPath) return root;
|
|
136
|
-
const parts = dirPath.split('/');
|
|
137
|
-
let current = root;
|
|
138
|
-
for (const part of parts) {
|
|
139
|
-
try {
|
|
140
|
-
current = await current.getDirectoryHandle(part);
|
|
141
|
-
} catch (error: unknown) {
|
|
142
|
-
if (isMissingEntryError(error)) return null;
|
|
143
|
-
throw error;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return current;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Walk path segments, creating directories as needed.
|
|
151
|
-
*/
|
|
152
|
-
async function resolveDirCreate(
|
|
153
|
-
root: FileSystemDirectoryHandle,
|
|
154
|
-
dirPath: string,
|
|
155
|
-
): Promise<FileSystemDirectoryHandle> {
|
|
156
|
-
if (!dirPath) return root;
|
|
157
|
-
const parts = dirPath.split('/');
|
|
158
|
-
let current = root;
|
|
159
|
-
for (const part of parts) {
|
|
160
|
-
current = await current.getDirectoryHandle(part, { create: true });
|
|
161
|
-
}
|
|
162
|
-
return current;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function parentDir(p: string): string {
|
|
166
|
-
const idx = p.lastIndexOf('/');
|
|
167
|
-
return idx === -1 ? '' : p.slice(0, idx);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function baseName(p: string): string {
|
|
171
|
-
const idx = p.lastIndexOf('/');
|
|
172
|
-
return idx === -1 ? p : p.slice(idx + 1);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function toWritableBinary(data: ArrayBuffer | Uint8Array): ArrayBuffer {
|
|
176
|
-
if (data instanceof ArrayBuffer) return data;
|
|
177
|
-
const copy = new Uint8Array(data.byteLength);
|
|
178
|
-
copy.set(data);
|
|
179
|
-
return copy.buffer;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function writeAndClose(
|
|
183
|
-
writable: FileSystemWritableFileStream,
|
|
184
|
-
data: string | ArrayBuffer,
|
|
185
|
-
): Promise<void> {
|
|
186
|
-
try {
|
|
187
|
-
await writable.write(data);
|
|
188
|
-
await writable.close();
|
|
189
|
-
} catch (error: unknown) {
|
|
190
|
-
await writable.abort(error).catch(() => undefined);
|
|
191
|
-
throw error;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ── Implementation ─────────────────────────────────────────────────
|
|
196
|
-
|
|
197
|
-
export class NativeFileSystemProvider implements FileSystemProvider {
|
|
198
|
-
readonly id: string;
|
|
199
|
-
readonly label: string;
|
|
200
|
-
readonly v2: NativeFileSystemProviderV2;
|
|
201
|
-
|
|
202
|
-
private root: FileSystemDirectoryHandle;
|
|
203
|
-
|
|
204
|
-
constructor(id: string, root: FileSystemDirectoryHandle) {
|
|
205
|
-
this.id = id;
|
|
206
|
-
this.label = root.name;
|
|
207
|
-
this.root = root;
|
|
208
|
-
this.v2 = new NativeFileSystemProviderV2(id, root);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
private withMutationLock<T>(operation: () => Promise<T>): Promise<T> {
|
|
212
|
-
return withFileCommitLock(`native:${this.id}:workspace`, operation);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
private async copyDirectory(oldDirPath: string, newDirPath: string): Promise<void> {
|
|
216
|
-
const source = await resolveDir(this.root, oldDirPath);
|
|
217
|
-
if (!source)
|
|
218
|
-
throw new DOMException(`Source directory does not exist: ${oldDirPath}`, 'NotFoundError');
|
|
219
|
-
await resolveDirCreate(this.root, newDirPath);
|
|
220
|
-
|
|
221
|
-
for await (const [name, handle] of source as unknown as AsyncIterable<
|
|
222
|
-
[string, FileSystemHandle]
|
|
223
|
-
>) {
|
|
224
|
-
const oldChild = oldDirPath ? `${oldDirPath}/${name}` : name;
|
|
225
|
-
const newChild = newDirPath ? `${newDirPath}/${name}` : name;
|
|
226
|
-
if (handle.kind === 'directory') {
|
|
227
|
-
await this.copyDirectory(oldChild, newChild);
|
|
228
|
-
} else {
|
|
229
|
-
const fileHandle = await source.getFileHandle(name);
|
|
230
|
-
const file = await fileHandle.getFile();
|
|
231
|
-
await this.writeBinaryUnlocked(newChild, await file.arrayBuffer());
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
async readFile(path: string): Promise<string | null> {
|
|
237
|
-
const p = normalisePath(path);
|
|
238
|
-
const dir = await resolveDir(this.root, parentDir(p));
|
|
239
|
-
if (!dir) return null;
|
|
240
|
-
try {
|
|
241
|
-
const fileHandle = await dir.getFileHandle(baseName(p));
|
|
242
|
-
const file = await fileHandle.getFile();
|
|
243
|
-
return file.text();
|
|
244
|
-
} catch (error: unknown) {
|
|
245
|
-
if (isMissingEntryError(error)) return null;
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async writeFile(path: string, content: string): Promise<void> {
|
|
251
|
-
return this.withMutationLock(() => this.writeFileUnlocked(path, content));
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
private async writeFileUnlocked(path: string, content: string): Promise<void> {
|
|
255
|
-
const p = normalisePath(path);
|
|
256
|
-
const dir = await resolveDirCreate(this.root, parentDir(p));
|
|
257
|
-
const fileHandle = await dir.getFileHandle(baseName(p), { create: true });
|
|
258
|
-
const writable = await fileHandle.createWritable();
|
|
259
|
-
await writeAndClose(writable, content);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
async commitFile(
|
|
263
|
-
path: string,
|
|
264
|
-
content: string,
|
|
265
|
-
expectedContent: string | null,
|
|
266
|
-
): Promise<FileCommitResult> {
|
|
267
|
-
const p = normalisePath(path);
|
|
268
|
-
return this.withMutationLock(async () => {
|
|
269
|
-
const current = await this.readFile(p);
|
|
270
|
-
if (current !== expectedContent && current !== content) {
|
|
271
|
-
const meta = await this.stat(p);
|
|
272
|
-
return {
|
|
273
|
-
status: 'conflict',
|
|
274
|
-
content: current,
|
|
275
|
-
version: meta?.lastModified ?? null,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
await this.writeFileUnlocked(p, content);
|
|
279
|
-
const meta = await this.stat(p);
|
|
280
|
-
return { status: 'committed', version: meta?.lastModified ?? null };
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
async delete(path: string): Promise<void> {
|
|
285
|
-
return this.withMutationLock(() => this.deleteUnlocked(path));
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
private async deleteUnlocked(path: string): Promise<void> {
|
|
289
|
-
const p = normalisePath(path);
|
|
290
|
-
if (!p) throw new Error('Cannot delete the filesystem root');
|
|
291
|
-
const parent = parentDir(p);
|
|
292
|
-
const name = baseName(p);
|
|
293
|
-
const dir = await resolveDir(this.root, parent);
|
|
294
|
-
if (!dir) return;
|
|
295
|
-
try {
|
|
296
|
-
await dir.removeEntry(name, { recursive: true });
|
|
297
|
-
} catch (error: unknown) {
|
|
298
|
-
if (isMissingEntryError(error)) return;
|
|
299
|
-
throw error;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
async rename(oldPath: string, newPath: string): Promise<void> {
|
|
304
|
-
return this.withMutationLock(() => this.renameUnlocked(oldPath, newPath));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
private async renameUnlocked(oldPath: string, newPath: string): Promise<void> {
|
|
308
|
-
const op = normalisePath(oldPath);
|
|
309
|
-
const np = normalisePath(newPath);
|
|
310
|
-
if (op === np) return;
|
|
311
|
-
if (!op || !np) {
|
|
312
|
-
throw new Error('Cannot rename the filesystem root');
|
|
313
|
-
}
|
|
314
|
-
if (np.startsWith(op + '/')) {
|
|
315
|
-
throw new Error('Cannot move a directory into itself');
|
|
316
|
-
}
|
|
317
|
-
if (!(await this.exists(op))) {
|
|
318
|
-
throw new Error(`Source does not exist: ${oldPath}`);
|
|
319
|
-
}
|
|
320
|
-
if (await this.exists(np)) {
|
|
321
|
-
throw new Error(`Destination exists: ${newPath}`);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// The File System Access API doesn't have a native rename.
|
|
325
|
-
// Copy → delete.
|
|
326
|
-
const oldParent = await resolveDir(this.root, parentDir(op));
|
|
327
|
-
if (!oldParent) {
|
|
328
|
-
throw new DOMException(`Source does not exist: ${oldPath}`, 'NotFoundError');
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
let fileHandle: FileSystemFileHandle | null = null;
|
|
332
|
-
try {
|
|
333
|
-
fileHandle = await oldParent.getFileHandle(baseName(op));
|
|
334
|
-
} catch (error: unknown) {
|
|
335
|
-
if (!isMissingEntryError(error)) throw error;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (fileHandle) {
|
|
339
|
-
const file = await fileHandle.getFile();
|
|
340
|
-
await this.writeBinaryUnlocked(np, await file.arrayBuffer());
|
|
341
|
-
try {
|
|
342
|
-
await this.deleteUnlocked(op);
|
|
343
|
-
} catch (error: unknown) {
|
|
344
|
-
try {
|
|
345
|
-
await this.deleteUnlocked(np);
|
|
346
|
-
} catch (rollbackError: unknown) {
|
|
347
|
-
throw new NativeMoveRecoveryError(
|
|
348
|
-
`Move partially completed and rollback failed: ${oldPath} -> ${newPath}`,
|
|
349
|
-
[error, rollbackError],
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
throw error;
|
|
353
|
-
}
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
try {
|
|
358
|
-
await this.copyDirectory(op, np);
|
|
359
|
-
} catch (error: unknown) {
|
|
360
|
-
try {
|
|
361
|
-
await this.deleteUnlocked(np);
|
|
362
|
-
} catch (rollbackError: unknown) {
|
|
363
|
-
throw new NativeMoveRecoveryError(
|
|
364
|
-
`Move failed and destination cleanup failed: ${oldPath} -> ${newPath}`,
|
|
365
|
-
[error, rollbackError],
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
throw error;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
try {
|
|
372
|
-
await this.deleteUnlocked(op);
|
|
373
|
-
} catch (error: unknown) {
|
|
374
|
-
try {
|
|
375
|
-
await this.deleteUnlocked(np);
|
|
376
|
-
} catch (rollbackError: unknown) {
|
|
377
|
-
throw new NativeMoveRecoveryError(
|
|
378
|
-
`Move partially completed and rollback failed: ${oldPath} -> ${newPath}`,
|
|
379
|
-
[error, rollbackError],
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
throw error;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async readDirectory(path: string): Promise<FileSystemEntry[]> {
|
|
387
|
-
const p = normalisePath(path);
|
|
388
|
-
const dir = await resolveDir(this.root, p);
|
|
389
|
-
if (!dir) return [];
|
|
390
|
-
|
|
391
|
-
const entries: FileSystemEntry[] = [];
|
|
392
|
-
for await (const [name, handle] of dir as unknown as AsyncIterable<
|
|
393
|
-
[string, FileSystemHandle]
|
|
394
|
-
>) {
|
|
395
|
-
const entryPath = p ? `${p}/${name}` : name;
|
|
396
|
-
if (handle.kind === 'directory') {
|
|
397
|
-
entries.push({ kind: 'directory', name, path: entryPath });
|
|
398
|
-
} else {
|
|
399
|
-
entries.push({ kind: 'file', name, path: entryPath });
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Sort: directories first, then alphabetical
|
|
404
|
-
entries.sort((a, b) => {
|
|
405
|
-
if (a.kind !== b.kind) return a.kind === 'directory' ? -1 : 1;
|
|
406
|
-
return a.name.localeCompare(b.name);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
return entries;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async exists(path: string): Promise<boolean> {
|
|
413
|
-
const p = normalisePath(path);
|
|
414
|
-
const parent = parentDir(p);
|
|
415
|
-
const name = baseName(p);
|
|
416
|
-
const dir = await resolveDir(this.root, parent);
|
|
417
|
-
if (!dir) return false;
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
await dir.getFileHandle(name);
|
|
421
|
-
return true;
|
|
422
|
-
} catch (fileError: unknown) {
|
|
423
|
-
if (!isMissingEntryError(fileError)) throw fileError;
|
|
424
|
-
try {
|
|
425
|
-
await dir.getDirectoryHandle(name);
|
|
426
|
-
return true;
|
|
427
|
-
} catch (directoryError: unknown) {
|
|
428
|
-
if (!isMissingEntryError(directoryError)) throw directoryError;
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
async createDirectory(path: string): Promise<void> {
|
|
435
|
-
return this.withMutationLock(async () => {
|
|
436
|
-
const p = normalisePath(path);
|
|
437
|
-
await resolveDirCreate(this.root, p);
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
async stat(path: string): Promise<FileMeta | null> {
|
|
442
|
-
const p = normalisePath(path);
|
|
443
|
-
const dir = await resolveDir(this.root, parentDir(p));
|
|
444
|
-
if (!dir) return null;
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
const fileHandle = await dir.getFileHandle(baseName(p));
|
|
448
|
-
const file = await fileHandle.getFile();
|
|
449
|
-
return {
|
|
450
|
-
name: file.name,
|
|
451
|
-
path: p,
|
|
452
|
-
size: file.size,
|
|
453
|
-
lastModified: new Date(file.lastModified).toISOString(),
|
|
454
|
-
};
|
|
455
|
-
} catch (error: unknown) {
|
|
456
|
-
if (isMissingEntryError(error)) return null;
|
|
457
|
-
throw error;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
async readBinary(path: string): Promise<ArrayBuffer | null> {
|
|
462
|
-
const p = normalisePath(path);
|
|
463
|
-
const dir = await resolveDir(this.root, parentDir(p));
|
|
464
|
-
if (!dir) return null;
|
|
465
|
-
try {
|
|
466
|
-
const fileHandle = await dir.getFileHandle(baseName(p));
|
|
467
|
-
const file = await fileHandle.getFile();
|
|
468
|
-
return file.arrayBuffer();
|
|
469
|
-
} catch (error: unknown) {
|
|
470
|
-
if (isMissingEntryError(error)) return null;
|
|
471
|
-
throw error;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
async writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void> {
|
|
476
|
-
return this.withMutationLock(() => this.writeBinaryUnlocked(path, data));
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
private async writeBinaryUnlocked(path: string, data: ArrayBuffer | Uint8Array): Promise<void> {
|
|
480
|
-
const p = normalisePath(path);
|
|
481
|
-
const dir = await resolveDirCreate(this.root, parentDir(p));
|
|
482
|
-
const fileHandle = await dir.getFileHandle(baseName(p), { create: true });
|
|
483
|
-
const writable = await fileHandle.createWritable();
|
|
484
|
-
await writeAndClose(writable, toWritableBinary(data));
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Prompt the user to pick a local folder and return a NativeFileSystemProvider.
|
|
490
|
-
* The directory handle is persisted in IndexedDB so it can be restored later.
|
|
491
|
-
* Throws if the user cancels or the API is unsupported.
|
|
492
|
-
*/
|
|
493
|
-
export async function openNativeFolder(): Promise<NativeFileSystemProvider> {
|
|
494
|
-
if (!isNativeFileSystemSupported()) {
|
|
495
|
-
throw new Error('File System Access API is not supported in this browser');
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
const handle = await (
|
|
499
|
-
globalThis as unknown as {
|
|
500
|
-
showDirectoryPicker: (options: { mode: 'readwrite' }) => Promise<FileSystemDirectoryHandle>;
|
|
501
|
-
}
|
|
502
|
-
).showDirectoryPicker({ mode: 'readwrite' });
|
|
503
|
-
const id = `native-${handle.name}-${Date.now()}`;
|
|
504
|
-
await storeDirectoryHandle(id, handle);
|
|
505
|
-
return new NativeFileSystemProvider(id, handle);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Restore a previously opened native folder from a persisted handle.
|
|
510
|
-
* Re-requests read/write permission (browser will show a prompt).
|
|
511
|
-
* Returns null if the handle is not found or permission is denied.
|
|
512
|
-
*/
|
|
513
|
-
export async function restoreNativeFolder(
|
|
514
|
-
workspaceId: string,
|
|
515
|
-
): Promise<NativeFileSystemProvider | null> {
|
|
516
|
-
const handle = await loadDirectoryHandle(workspaceId);
|
|
517
|
-
if (!handle) return null;
|
|
518
|
-
|
|
519
|
-
// Verify/request permission
|
|
520
|
-
const opts = { mode: 'readwrite' as const };
|
|
521
|
-
const h = handle as FileSystemDirectoryHandle & {
|
|
522
|
-
queryPermission(desc: { mode: string }): Promise<string>;
|
|
523
|
-
requestPermission(desc: { mode: string }): Promise<string>;
|
|
524
|
-
};
|
|
525
|
-
try {
|
|
526
|
-
if ((await h.queryPermission(opts)) === 'granted') {
|
|
527
|
-
return new NativeFileSystemProvider(workspaceId, handle);
|
|
528
|
-
}
|
|
529
|
-
if ((await h.requestPermission(opts)) === 'granted') {
|
|
530
|
-
return new NativeFileSystemProvider(workspaceId, handle);
|
|
531
|
-
}
|
|
532
|
-
} catch (error: unknown) {
|
|
533
|
-
if (!isPermissionError(error)) throw error;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
return null;
|
|
537
|
-
}
|
package/src/filesystem/native.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/** Browser File System Access API provider entry point. */
|
|
2
|
-
export {
|
|
3
|
-
NativeFileSystemProvider,
|
|
4
|
-
isNativeFileSystemSupported,
|
|
5
|
-
openNativeFolder,
|
|
6
|
-
restoreNativeFolder,
|
|
7
|
-
storeDirectoryHandle,
|
|
8
|
-
loadDirectoryHandle,
|
|
9
|
-
removeDirectoryHandle,
|
|
10
|
-
} from './native-provider.js';
|
|
11
|
-
export {
|
|
12
|
-
NativeFileSystemProviderV2,
|
|
13
|
-
NativeFileSystemMoveRecoveryError,
|
|
14
|
-
type NativeFileSystemMovePathState,
|
|
15
|
-
type NativeFileSystemMoveRecoveryState,
|
|
16
|
-
} from './native-provider-v2.js';
|
package/src/filesystem/types.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FileSystemProvider — abstract interface for a virtual filesystem.
|
|
3
|
-
*
|
|
4
|
-
* Legacy text-oriented facade retained while consumers migrate to
|
|
5
|
-
* FileSystemProviderV2. New persistence code must use the provider's `v2`
|
|
6
|
-
* contract so paths, errors, operation modes, and capabilities are explicit.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// ── Entry types ────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
import type { FileSystemProviderV2 } from './v2.js';
|
|
12
|
-
|
|
13
|
-
export interface FileEntry {
|
|
14
|
-
kind: 'file';
|
|
15
|
-
name: string;
|
|
16
|
-
path: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface FolderEntry {
|
|
20
|
-
kind: 'directory';
|
|
21
|
-
name: string;
|
|
22
|
-
path: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type FileSystemEntry = FileEntry | FolderEntry;
|
|
26
|
-
|
|
27
|
-
export interface FileMeta {
|
|
28
|
-
name: string;
|
|
29
|
-
path: string;
|
|
30
|
-
size: number;
|
|
31
|
-
lastModified: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type FileCommitResult =
|
|
35
|
-
| { status: 'committed'; version: string | null }
|
|
36
|
-
| { status: 'conflict'; content: string | null; version: string | null };
|
|
37
|
-
|
|
38
|
-
// ── Provider interface ─────────────────────────────────────────────
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @deprecated Compatibility facade for external providers and older callers.
|
|
42
|
-
* Implement new backends with `FileSystemProviderV2`; built-in facades expose
|
|
43
|
-
* their authoritative implementation through `v2`.
|
|
44
|
-
*/
|
|
45
|
-
export interface FileSystemProvider {
|
|
46
|
-
/** Unique identifier for this provider instance. */
|
|
47
|
-
readonly id: string;
|
|
48
|
-
|
|
49
|
-
/** Human-readable label (e.g., folder name or "Browser Storage"). */
|
|
50
|
-
readonly label: string;
|
|
51
|
-
|
|
52
|
-
/** Optional correctness-first implementation exposed during the v1-to-v2 migration. */
|
|
53
|
-
readonly v2?: FileSystemProviderV2;
|
|
54
|
-
|
|
55
|
-
/** Read the text content of a file. Returns null if the file doesn't exist. */
|
|
56
|
-
readFile(path: string): Promise<string | null>;
|
|
57
|
-
|
|
58
|
-
/** Write text content to a file, creating it (and parent dirs) if needed. */
|
|
59
|
-
writeFile(path: string, content: string): Promise<void>;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Conditionally replace a text file when it still matches the caller's
|
|
63
|
-
* persisted baseline. Production providers implement this at their
|
|
64
|
-
* strongest available serialization boundary.
|
|
65
|
-
*/
|
|
66
|
-
commitFile?(
|
|
67
|
-
path: string,
|
|
68
|
-
content: string,
|
|
69
|
-
expectedContent: string | null,
|
|
70
|
-
): Promise<FileCommitResult>;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Legacy recursive removal of a file or directory subtree. Workspace root
|
|
74
|
-
* deletion is forbidden. Prefer v2 `remove({ recursive })`.
|
|
75
|
-
*/
|
|
76
|
-
delete(path: string): Promise<void>;
|
|
77
|
-
|
|
78
|
-
/** Rename or move an entry. Rejects missing sources and existing destinations. */
|
|
79
|
-
rename(oldPath: string, newPath: string): Promise<void>;
|
|
80
|
-
|
|
81
|
-
/** List immediate children of a directory. */
|
|
82
|
-
readDirectory(path: string): Promise<FileSystemEntry[]>;
|
|
83
|
-
|
|
84
|
-
/** Check whether a path exists. */
|
|
85
|
-
exists(path: string): Promise<boolean>;
|
|
86
|
-
|
|
87
|
-
/** Create a directory (and parents if needed). */
|
|
88
|
-
createDirectory(path: string): Promise<void>;
|
|
89
|
-
|
|
90
|
-
/** Get metadata for a file. Returns null if not found. */
|
|
91
|
-
stat(path: string): Promise<FileMeta | null>;
|
|
92
|
-
|
|
93
|
-
/** Read raw binary content. Returns null if not found. */
|
|
94
|
-
readBinary(path: string): Promise<ArrayBuffer | null>;
|
|
95
|
-
|
|
96
|
-
/** Write raw binary content. */
|
|
97
|
-
writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export type FileSystemProviderWithV2 = FileSystemProvider & {
|
|
101
|
-
readonly v2: FileSystemProviderV2;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/** Discover a provider-owned v2 implementation without coupling consumers to a concrete class. */
|
|
105
|
-
export function hasFileSystemProviderV2(
|
|
106
|
-
provider: FileSystemProvider,
|
|
107
|
-
): provider is FileSystemProviderWithV2 {
|
|
108
|
-
return provider.v2 !== undefined && provider.v2 !== null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** Return the provider-owned v2 implementation when migration support is available. */
|
|
112
|
-
export function getFileSystemProviderV2(provider: FileSystemProvider): FileSystemProviderV2 | null {
|
|
113
|
-
return provider.v2 ?? null;
|
|
114
|
-
}
|