@superblocksteam/workspace-sync 0.0.0-stage → 2.0.178-next.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/LICENSE.txt +87 -0
- package/README.md +43 -2
- package/dist/atomic-write.d.ts +7 -0
- package/dist/atomic-write.d.ts.map +1 -0
- package/dist/atomic-write.js +33 -0
- package/dist/atomic-write.js.map +1 -0
- package/dist/branch-write-guard.d.ts +32 -0
- package/dist/branch-write-guard.d.ts.map +1 -0
- package/dist/branch-write-guard.js +38 -0
- package/dist/branch-write-guard.js.map +1 -0
- package/dist/control.d.ts +237 -0
- package/dist/control.d.ts.map +1 -0
- package/dist/control.js +242 -0
- package/dist/control.js.map +1 -0
- package/dist/dbfs-transport.d.ts +52 -0
- package/dist/dbfs-transport.d.ts.map +1 -0
- package/dist/dbfs-transport.js +21 -0
- package/dist/dbfs-transport.js.map +1 -0
- package/dist/download.d.ts +54 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +475 -0
- package/dist/download.js.map +1 -0
- package/dist/draft-helpers.d.ts +114 -0
- package/dist/draft-helpers.d.ts.map +1 -0
- package/dist/draft-helpers.js +760 -0
- package/dist/draft-helpers.js.map +1 -0
- package/dist/draft-journal-store.d.ts +30 -0
- package/dist/draft-journal-store.d.ts.map +1 -0
- package/dist/draft-journal-store.js +7 -0
- package/dist/draft-journal-store.js.map +1 -0
- package/dist/draft-state-report-metrics.d.ts +5 -0
- package/dist/draft-state-report-metrics.d.ts.map +1 -0
- package/dist/draft-state-report-metrics.js +36 -0
- package/dist/draft-state-report-metrics.js.map +1 -0
- package/dist/file-draft-journal-store.d.ts +26 -0
- package/dist/file-draft-journal-store.d.ts.map +1 -0
- package/dist/file-draft-journal-store.js +123 -0
- package/dist/file-draft-journal-store.js.map +1 -0
- package/dist/flush-scheduler.d.ts +24 -0
- package/dist/flush-scheduler.d.ts.map +1 -0
- package/dist/flush-scheduler.js +36 -0
- package/dist/flush-scheduler.js.map +1 -0
- package/dist/hash-cache.d.ts +16 -0
- package/dist/hash-cache.d.ts.map +1 -0
- package/dist/hash-cache.js +62 -0
- package/dist/hash-cache.js.map +1 -0
- package/dist/hash-dir-tree.d.ts +10 -0
- package/dist/hash-dir-tree.d.ts.map +1 -0
- package/dist/hash-dir-tree.js +53 -0
- package/dist/hash-dir-tree.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/list-dir.d.ts +31 -0
- package/dist/list-dir.d.ts.map +1 -0
- package/dist/list-dir.js +153 -0
- package/dist/list-dir.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +16 -0
- package/dist/logger.js.map +1 -0
- package/dist/native-draft-session.d.ts +28 -0
- package/dist/native-draft-session.d.ts.map +1 -0
- package/dist/native-draft-session.js +154 -0
- package/dist/native-draft-session.js.map +1 -0
- package/dist/rpc-client.d.ts +7 -0
- package/dist/rpc-client.d.ts.map +1 -0
- package/dist/rpc-client.js +2 -0
- package/dist/rpc-client.js.map +1 -0
- package/dist/safe-directory-reader.d.ts +28 -0
- package/dist/safe-directory-reader.d.ts.map +1 -0
- package/dist/safe-directory-reader.js +136 -0
- package/dist/safe-directory-reader.js.map +1 -0
- package/dist/server-tree.d.ts +56 -0
- package/dist/server-tree.d.ts.map +1 -0
- package/dist/server-tree.js +179 -0
- package/dist/server-tree.js.map +1 -0
- package/dist/session-draft-journal-store.d.ts +42 -0
- package/dist/session-draft-journal-store.d.ts.map +1 -0
- package/dist/session-draft-journal-store.js +177 -0
- package/dist/session-draft-journal-store.js.map +1 -0
- package/dist/snapshot/take-snapshot.d.ts +41 -0
- package/dist/snapshot/take-snapshot.d.ts.map +1 -0
- package/dist/snapshot/take-snapshot.js +244 -0
- package/dist/snapshot/take-snapshot.js.map +1 -0
- package/dist/snapshot/types.d.ts +25 -0
- package/dist/snapshot/types.d.ts.map +1 -0
- package/dist/snapshot/types.js +3 -0
- package/dist/snapshot/types.js.map +1 -0
- package/dist/snapshot/upload-snapshot.d.ts +33 -0
- package/dist/snapshot/upload-snapshot.d.ts.map +1 -0
- package/dist/snapshot/upload-snapshot.js +113 -0
- package/dist/snapshot/upload-snapshot.js.map +1 -0
- package/dist/socket-dbfs-transport.d.ts +32 -0
- package/dist/socket-dbfs-transport.d.ts.map +1 -0
- package/dist/socket-dbfs-transport.js +126 -0
- package/dist/socket-dbfs-transport.js.map +1 -0
- package/dist/sync-credential-provider.d.ts +27 -0
- package/dist/sync-credential-provider.d.ts.map +1 -0
- package/dist/sync-credential-provider.js +22 -0
- package/dist/sync-credential-provider.js.map +1 -0
- package/dist/sync-engine.d.ts +119 -0
- package/dist/sync-engine.d.ts.map +1 -0
- package/dist/sync-engine.js +358 -0
- package/dist/sync-engine.js.map +1 -0
- package/dist/sync-paths.d.ts +61 -0
- package/dist/sync-paths.d.ts.map +1 -0
- package/dist/sync-paths.js +107 -0
- package/dist/sync-paths.js.map +1 -0
- package/dist/sync-telemetry.d.ts +12 -0
- package/dist/sync-telemetry.d.ts.map +1 -0
- package/dist/sync-telemetry.js +33 -0
- package/dist/sync-telemetry.js.map +1 -0
- package/dist/testing.d.ts +66 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +180 -0
- package/dist/testing.js.map +1 -0
- package/dist/workspace-state-store.d.ts +52 -0
- package/dist/workspace-state-store.d.ts.map +1 -0
- package/dist/workspace-state-store.js +45 -0
- package/dist/workspace-state-store.js.map +1 -0
- package/package.json +59 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface LocalDirEntryFile {
|
|
2
|
+
type: "-";
|
|
3
|
+
executable: boolean;
|
|
4
|
+
name: string;
|
|
5
|
+
localPath: string;
|
|
6
|
+
contents: Buffer;
|
|
7
|
+
}
|
|
8
|
+
export interface LocalDirEntryDirectory {
|
|
9
|
+
type: "d";
|
|
10
|
+
name: string;
|
|
11
|
+
localPath: string;
|
|
12
|
+
}
|
|
13
|
+
export interface LocalDirEntrySymLink {
|
|
14
|
+
type: "l";
|
|
15
|
+
name: string;
|
|
16
|
+
localPath: string;
|
|
17
|
+
target: string;
|
|
18
|
+
}
|
|
19
|
+
export type LocalDirEntry = LocalDirEntryFile | LocalDirEntryDirectory | LocalDirEntrySymLink;
|
|
20
|
+
/**
|
|
21
|
+
* Lists the contents of a local directory. The function will load the contents of files into memory, but as it is a generator, this
|
|
22
|
+
* will happen lazily, so only one file will be loaded into memory at a time. The function will also ignore files in the directories
|
|
23
|
+
* listed in `codeModeSyncExcludedDirectories` and files matched by `isCodeModeExcludedFile`.
|
|
24
|
+
*
|
|
25
|
+
* @param localDirectoryPath - The path to the local directory to list.
|
|
26
|
+
* @returns An async generator that yields the contents of the directory.
|
|
27
|
+
*/
|
|
28
|
+
export declare function listLocalDirectory(localDirectoryPath: string, rootDirectoryPath?: string, limits?: {
|
|
29
|
+
maxFileBytes: number;
|
|
30
|
+
}): AsyncGenerator<LocalDirEntry, void, void>;
|
|
31
|
+
//# sourceMappingURL=list-dir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-dir.d.ts","sourceRoot":"","sources":["../src/list-dir.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,GAAG,CAAC;IACV,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,sBAAsB,GACtB,oBAAoB,CAAC;AAezB;;;;;;;GAOG;AACH,wBAAuB,kBAAkB,CACvC,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,SAAqB,EACtC,MAAM,CAAC,EAAE;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAChC,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAyI3C"}
|
package/dist/list-dir.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { codeModeSyncExcludedDirectories } from "@superblocksteam/shared";
|
|
4
|
+
import { getSyncLogger } from "./logger.js";
|
|
5
|
+
import { SafeDirectoryReader } from "./safe-directory-reader.js";
|
|
6
|
+
import { isCodeModeExcludedFile, isPersistedChecklistPathOrAncestor, isPersistedSuperblocksFile, isSnapshotExcludedName, NATIVE_SYSTEM_SKILLS_ROOT, NPM_TO_PNPM_STATE_RELATIVE_PATH, PRIVATE_REGISTRY_MIGRATION_SENTINEL_RELATIVE_PATH, TEMPLATE_DEPENDENCIES_STATE_RELATIVE_PATH, } from "./sync-paths.js";
|
|
7
|
+
function isNodeError(error) {
|
|
8
|
+
return error instanceof Error && "code" in error;
|
|
9
|
+
}
|
|
10
|
+
async function pathExists(targetPath) {
|
|
11
|
+
try {
|
|
12
|
+
await fsp.access(targetPath);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Lists the contents of a local directory. The function will load the contents of files into memory, but as it is a generator, this
|
|
21
|
+
* will happen lazily, so only one file will be loaded into memory at a time. The function will also ignore files in the directories
|
|
22
|
+
* listed in `codeModeSyncExcludedDirectories` and files matched by `isCodeModeExcludedFile`.
|
|
23
|
+
*
|
|
24
|
+
* @param localDirectoryPath - The path to the local directory to list.
|
|
25
|
+
* @returns An async generator that yields the contents of the directory.
|
|
26
|
+
*/
|
|
27
|
+
export async function* listLocalDirectory(localDirectoryPath, rootDirectoryPath = localDirectoryPath, limits) {
|
|
28
|
+
const logger = getSyncLogger();
|
|
29
|
+
let localDirHandle;
|
|
30
|
+
try {
|
|
31
|
+
localDirHandle = await fsp.opendir(localDirectoryPath);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// A nested directory can vanish mid-scan (the migration deletes `scratch`
|
|
35
|
+
// while a snapshot walks the tree). A missing root is not a race: callers
|
|
36
|
+
// rely on that rejection to fail the sync instead of uploading nothing.
|
|
37
|
+
const isNestedDirectory = path.resolve(localDirectoryPath) !== path.resolve(rootDirectoryPath);
|
|
38
|
+
if (isNestedDirectory && isNodeError(error) && error.code === "ENOENT") {
|
|
39
|
+
logger.warn(`Directory was deleted during directory scan, skipping: ${localDirectoryPath}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
for await (const localDirEntry of localDirHandle) {
|
|
45
|
+
const name = localDirEntry.name
|
|
46
|
+
// On macOS, filenames in the filesystem are typically stored in decomposed form from a Unicode normalization perspective
|
|
47
|
+
// (i.e. NFD). We need to convert it to precomposed form (i.e. NFC) to match what everything else uses and expects.
|
|
48
|
+
.normalize("NFC");
|
|
49
|
+
const localFilePath = `${localDirectoryPath}/${name}`;
|
|
50
|
+
const relativePath = path.relative(rootDirectoryPath, localFilePath);
|
|
51
|
+
const normalizedRelativePath = relativePath.split(path.sep).join("/");
|
|
52
|
+
if (name !== ".superblocks" && isSnapshotExcludedName(name))
|
|
53
|
+
continue;
|
|
54
|
+
if (normalizedRelativePath === NATIVE_SYSTEM_SKILLS_ROOT)
|
|
55
|
+
continue;
|
|
56
|
+
if (codeModeSyncExcludedDirectories.includes(name) &&
|
|
57
|
+
!(localDirEntry.isDirectory() &&
|
|
58
|
+
isPersistedChecklistPathOrAncestor(normalizedRelativePath))) {
|
|
59
|
+
if (!localDirEntry.isDirectory()) {
|
|
60
|
+
logger.debug(`[sync-service] dbfs upload: excluding non-directory entry "${name}" at ${localFilePath}`);
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (localDirEntry.isFile()) {
|
|
65
|
+
if (normalizedRelativePath.startsWith(".superblocks/") &&
|
|
66
|
+
!isPersistedSuperblocksFile(normalizedRelativePath)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (isCodeModeExcludedFile(name)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const file = await SafeDirectoryReader.readLocalFile(localFilePath, limits?.maxFileBytes ?? Number.MAX_SAFE_INTEGER);
|
|
74
|
+
yield {
|
|
75
|
+
type: "-",
|
|
76
|
+
executable: file.executable,
|
|
77
|
+
name,
|
|
78
|
+
localPath: localFilePath,
|
|
79
|
+
contents: file.content,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
84
|
+
logger.warn(`File was deleted during directory scan, skipping: ${localFilePath}`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (localDirEntry.isDirectory()) {
|
|
91
|
+
if (normalizedRelativePath.startsWith(".superblocks/") &&
|
|
92
|
+
!isPersistedChecklistPathOrAncestor(normalizedRelativePath)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (normalizedRelativePath === ".superblocks") {
|
|
96
|
+
// `.superblocks/` is excluded from sync wholesale unless it carries
|
|
97
|
+
// an allowlisted persisted file (see `isPersistedSuperblocksFile`).
|
|
98
|
+
// Probe every allowlisted descendant before skipping; otherwise a
|
|
99
|
+
// workspace whose ONLY persisted artifact is the private-registry
|
|
100
|
+
// sentinel (brownfield migration before any AI session has written
|
|
101
|
+
// a checklist) would lose the sentinel on every upload, defeating
|
|
102
|
+
// cross-pod persistence.
|
|
103
|
+
const checklistPath = path.join(localFilePath, "ai", "checklist.json");
|
|
104
|
+
const persistedFiles = [
|
|
105
|
+
PRIVATE_REGISTRY_MIGRATION_SENTINEL_RELATIVE_PATH,
|
|
106
|
+
NPM_TO_PNPM_STATE_RELATIVE_PATH,
|
|
107
|
+
TEMPLATE_DEPENDENCIES_STATE_RELATIVE_PATH,
|
|
108
|
+
].map((file) => path.join(rootDirectoryPath, file));
|
|
109
|
+
let hasPersistedDescendant = await pathExists(checklistPath);
|
|
110
|
+
for (const file of persistedFiles) {
|
|
111
|
+
hasPersistedDescendant ||= await pathExists(file);
|
|
112
|
+
}
|
|
113
|
+
if (!hasPersistedDescendant) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (normalizedRelativePath === ".superblocks/ai") {
|
|
118
|
+
const checklistPath = path.join(localFilePath, "checklist.json");
|
|
119
|
+
if (!(await pathExists(checklistPath))) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
yield {
|
|
124
|
+
type: "d",
|
|
125
|
+
name,
|
|
126
|
+
localPath: localFilePath,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else if (localDirEntry.isSymbolicLink()) {
|
|
130
|
+
try {
|
|
131
|
+
const target = await fsp.readlink(localFilePath);
|
|
132
|
+
yield {
|
|
133
|
+
type: "l",
|
|
134
|
+
name,
|
|
135
|
+
localPath: localFilePath,
|
|
136
|
+
target,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
141
|
+
logger.warn(`Symlink was deleted during directory scan, skipping: ${localFilePath}`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// ignore files of other types
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=list-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-dir.js","sourceRoot":"","sources":["../src/list-dir.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The narrow logger this package writes to. The host process binds its own
|
|
3
|
+
* logger with {@link setSyncLoggerProvider}; until it does, messages go to the
|
|
4
|
+
* console.
|
|
5
|
+
*/
|
|
6
|
+
export interface SyncLogger {
|
|
7
|
+
debug: (...messages: unknown[]) => void;
|
|
8
|
+
warn: (...messages: unknown[]) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Binds the logger this package uses. The provider is called on every log
|
|
12
|
+
* call, so a host whose own default logger changes later is followed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setSyncLoggerProvider(next: () => SyncLogger): void;
|
|
15
|
+
export declare function getSyncLogger(): SyncLogger;
|
|
16
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACxC;AASD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,UAAU,GAAG,IAAI,CAElE;AAED,wBAAgB,aAAa,IAAI,UAAU,CAE1C"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const consoleSyncLogger = {
|
|
2
|
+
debug: (...messages) => console.debug(...messages),
|
|
3
|
+
warn: (...messages) => console.warn(...messages),
|
|
4
|
+
};
|
|
5
|
+
let provider = () => consoleSyncLogger;
|
|
6
|
+
/**
|
|
7
|
+
* Binds the logger this package uses. The provider is called on every log
|
|
8
|
+
* call, so a host whose own default logger changes later is followed.
|
|
9
|
+
*/
|
|
10
|
+
export function setSyncLoggerProvider(next) {
|
|
11
|
+
provider = next;
|
|
12
|
+
}
|
|
13
|
+
export function getSyncLogger() {
|
|
14
|
+
return provider();
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAUA,MAAM,iBAAiB,GAAe;IACpC,KAAK,EAAE,CAAC,GAAG,QAAmB,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAG,QAAmB,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;CAC5D,CAAC;AAEF,IAAI,QAAQ,GAAqB,GAAG,EAAE,CAAC,iBAAiB,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAsB;IAC1D,QAAQ,GAAG,IAAI,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,QAAQ,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DraftJournalPhase, DraftJournalStore } from "./draft-journal-store.js";
|
|
2
|
+
/**
|
|
3
|
+
* The recovery journal for one native execution session: what the tracked
|
|
4
|
+
* files held before the session, and the originals the draft markers are
|
|
5
|
+
* rebuilt from. Persistence goes through a {@link DraftJournalStore}; a
|
|
6
|
+
* directory, or nothing, selects the {@link FileDraftJournalStore} beside the
|
|
7
|
+
* application root.
|
|
8
|
+
*/
|
|
9
|
+
export declare class NativeDraftJournal {
|
|
10
|
+
private readonly root;
|
|
11
|
+
private readonly scope;
|
|
12
|
+
private readonly store;
|
|
13
|
+
constructor(root: string, scope: string, store?: DraftJournalStore | string);
|
|
14
|
+
exists(): Promise<boolean>;
|
|
15
|
+
/** The stored session's phase, or undefined when there is none. */
|
|
16
|
+
phase(): Promise<DraftJournalPhase | undefined>;
|
|
17
|
+
capture(): Promise<void>;
|
|
18
|
+
reconcile(finalize: boolean): Promise<{
|
|
19
|
+
changedPaths: string[];
|
|
20
|
+
hash?: string;
|
|
21
|
+
} | undefined>;
|
|
22
|
+
retireUploaded(hash: string): Promise<void>;
|
|
23
|
+
clear(): Promise<void>;
|
|
24
|
+
private validate;
|
|
25
|
+
private read;
|
|
26
|
+
private snapshot;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=native-draft-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-draft-session.d.ts","sourceRoot":"","sources":["../src/native-draft-session.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iBAAiB,EAEjB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAWlC;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAE1C,YACmB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EAC9B,KAAK,GAAE,iBAAiB,GAAG,MAA2C,EAMvE;IAEK,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAE/B;IAED,mEAAmE;IAC7D,KAAK,IAAI,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAEpD;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B7B;IAEK,SAAS,CACb,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAmChE;IAEK,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhD;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,OAAO,CAAC,QAAQ;YAuBF,IAAI;YAaJ,QAAQ;CAwBvB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { DraftMarkers, getDraftInfo } from "./draft-helpers.js";
|
|
5
|
+
import { defaultDraftJournalDirectory, FileDraftJournalStore, } from "./file-draft-journal-store.js";
|
|
6
|
+
import { listLocalDirectory } from "./list-dir.js";
|
|
7
|
+
import { snapshotLocalDirectoryWithDrafts } from "./snapshot/take-snapshot.js";
|
|
8
|
+
const MAX_BYTES = 32 * 1024 * 1024;
|
|
9
|
+
const MAX_ENTRIES = 2000;
|
|
10
|
+
/**
|
|
11
|
+
* The recovery journal for one native execution session: what the tracked
|
|
12
|
+
* files held before the session, and the originals the draft markers are
|
|
13
|
+
* rebuilt from. Persistence goes through a {@link DraftJournalStore}; a
|
|
14
|
+
* directory, or nothing, selects the {@link FileDraftJournalStore} beside the
|
|
15
|
+
* application root.
|
|
16
|
+
*/
|
|
17
|
+
export class NativeDraftJournal {
|
|
18
|
+
root;
|
|
19
|
+
scope;
|
|
20
|
+
store;
|
|
21
|
+
constructor(root, scope, store = defaultDraftJournalDirectory(root)) {
|
|
22
|
+
this.root = root;
|
|
23
|
+
this.scope = scope;
|
|
24
|
+
this.store =
|
|
25
|
+
typeof store === "string"
|
|
26
|
+
? new FileDraftJournalStore(root, store)
|
|
27
|
+
: store;
|
|
28
|
+
}
|
|
29
|
+
async exists() {
|
|
30
|
+
return (await this.read()) !== undefined;
|
|
31
|
+
}
|
|
32
|
+
/** The stored session's phase, or undefined when there is none. */
|
|
33
|
+
async phase() {
|
|
34
|
+
return (await this.read())?.phase;
|
|
35
|
+
}
|
|
36
|
+
async capture() {
|
|
37
|
+
const pending = await this.read();
|
|
38
|
+
const markers = new DraftMarkers(this.root);
|
|
39
|
+
await markers.prepare();
|
|
40
|
+
const before = await this.snapshot();
|
|
41
|
+
const info = await getDraftInfo(this.root);
|
|
42
|
+
const targets = [
|
|
43
|
+
...new Set([
|
|
44
|
+
...before.keys(),
|
|
45
|
+
...info.additions,
|
|
46
|
+
...info.edits,
|
|
47
|
+
...info.deletions,
|
|
48
|
+
]),
|
|
49
|
+
];
|
|
50
|
+
const originals = await markers.originals(targets, before, MAX_BYTES, MAX_ENTRIES * 5);
|
|
51
|
+
await this.store.write({
|
|
52
|
+
root: await fs.realpath(this.root),
|
|
53
|
+
scope: this.scope,
|
|
54
|
+
id: randomUUID(),
|
|
55
|
+
phase: "running",
|
|
56
|
+
before: pending?.before ?? before,
|
|
57
|
+
originals,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async reconcile(finalize) {
|
|
61
|
+
const journal = await this.read();
|
|
62
|
+
if (!journal)
|
|
63
|
+
return undefined;
|
|
64
|
+
const { before, originals } = journal;
|
|
65
|
+
const after = await this.snapshot();
|
|
66
|
+
const candidates = new Set([
|
|
67
|
+
...before.keys(),
|
|
68
|
+
...originals.keys(),
|
|
69
|
+
...after.keys(),
|
|
70
|
+
]);
|
|
71
|
+
const changedPaths = [];
|
|
72
|
+
const markers = new DraftMarkers(this.root);
|
|
73
|
+
for (const relative of candidates) {
|
|
74
|
+
await markers.reconcile(relative, originals.get(relative), after.get(relative));
|
|
75
|
+
const previous = before.get(relative);
|
|
76
|
+
const current = after.get(relative);
|
|
77
|
+
if (previous === undefined
|
|
78
|
+
? current !== undefined
|
|
79
|
+
: current === undefined || !previous.equals(current))
|
|
80
|
+
changedPaths.push(relative);
|
|
81
|
+
}
|
|
82
|
+
if (!finalize)
|
|
83
|
+
return { changedPaths };
|
|
84
|
+
if (changedPaths.length === 0) {
|
|
85
|
+
await this.clear();
|
|
86
|
+
return { changedPaths };
|
|
87
|
+
}
|
|
88
|
+
const { hash } = await snapshotLocalDirectoryWithDrafts(this.root);
|
|
89
|
+
await this.store.write({ ...journal, phase: "complete", hash });
|
|
90
|
+
return { changedPaths, hash };
|
|
91
|
+
}
|
|
92
|
+
async retireUploaded(hash) {
|
|
93
|
+
const journal = await this.read();
|
|
94
|
+
if (journal?.phase === "complete" && journal.hash === hash)
|
|
95
|
+
await this.clear();
|
|
96
|
+
}
|
|
97
|
+
async clear() {
|
|
98
|
+
await this.store.clear();
|
|
99
|
+
}
|
|
100
|
+
validate(files) {
|
|
101
|
+
let bytes = 0;
|
|
102
|
+
let entries = 0;
|
|
103
|
+
for (const [relative, content] of files) {
|
|
104
|
+
const normalized = path.relative(this.root, path.resolve(this.root, relative));
|
|
105
|
+
if (!normalized ||
|
|
106
|
+
normalized !== relative ||
|
|
107
|
+
normalized === ".." ||
|
|
108
|
+
normalized.startsWith(`..${path.sep}`) ||
|
|
109
|
+
path.isAbsolute(normalized))
|
|
110
|
+
throw new Error("Invalid native draft journal path");
|
|
111
|
+
bytes += content.length;
|
|
112
|
+
if (bytes > MAX_BYTES || entries >= MAX_ENTRIES)
|
|
113
|
+
throw new Error("Native draft journal exceeds its snapshot limit");
|
|
114
|
+
entries++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async read() {
|
|
118
|
+
const journal = await this.store.read();
|
|
119
|
+
if (!journal)
|
|
120
|
+
return undefined;
|
|
121
|
+
if (journal.root !== (await fs.realpath(this.root)) ||
|
|
122
|
+
journal.scope !== this.scope)
|
|
123
|
+
throw new Error("Native draft journal belongs to another application");
|
|
124
|
+
this.validate(journal.before);
|
|
125
|
+
this.validate(journal.originals);
|
|
126
|
+
return journal;
|
|
127
|
+
}
|
|
128
|
+
async snapshot() {
|
|
129
|
+
const files = new Map();
|
|
130
|
+
let bytes = 0;
|
|
131
|
+
let entries = 0;
|
|
132
|
+
const visit = async (directory) => {
|
|
133
|
+
for await (const entry of listLocalDirectory(directory, this.root, {
|
|
134
|
+
maxFileBytes: MAX_BYTES - bytes,
|
|
135
|
+
})) {
|
|
136
|
+
if (++entries > MAX_ENTRIES)
|
|
137
|
+
throw new Error("Native draft snapshot exceeds its entry limit");
|
|
138
|
+
if (entry.type === "l")
|
|
139
|
+
throw new Error("Native draft snapshots cannot track symbolic links");
|
|
140
|
+
if (entry.type === "d")
|
|
141
|
+
await visit(entry.localPath);
|
|
142
|
+
else {
|
|
143
|
+
bytes += entry.contents.length;
|
|
144
|
+
if (bytes > MAX_BYTES)
|
|
145
|
+
throw new Error("Native draft snapshot exceeds its byte limit");
|
|
146
|
+
files.set(path.relative(this.root, entry.localPath), entry.contents);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
await visit(this.root);
|
|
151
|
+
return files;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=native-draft-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-draft-session.js","sourceRoot":"","sources":["../src/native-draft-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ISocketClient, ServerMethods } from "@superblocksteam/shared";
|
|
2
|
+
/**
|
|
3
|
+
* The server RPC client the DBFS helpers call. Same type as
|
|
4
|
+
* `StdISocketRPCClient` in `vite-plugin-file-sync/src/server-rpc/client.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export type StdISocketRPCClient = ISocketClient<ServerMethods>;
|
|
7
|
+
//# sourceMappingURL=rpc-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../src/rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE5E;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-client.js","sourceRoot":"","sources":["../src/rpc-client.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type DirectoryEntry = {
|
|
2
|
+
type: "directory";
|
|
3
|
+
entries: string[];
|
|
4
|
+
} | {
|
|
5
|
+
type: "file";
|
|
6
|
+
content: Buffer;
|
|
7
|
+
};
|
|
8
|
+
export declare class SafeDirectoryReader {
|
|
9
|
+
private readonly root;
|
|
10
|
+
private readonly handle;
|
|
11
|
+
private constructor();
|
|
12
|
+
static open(root: string): Promise<SafeDirectoryReader>;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
static readLocalFile(filePath: string, maxBytes: number): Promise<{
|
|
15
|
+
content: Buffer;
|
|
16
|
+
executable: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
readEntry(relative: string, maxBytes: number): Promise<DirectoryEntry | undefined>;
|
|
19
|
+
readFile(relative: string, maxBytes: number): Promise<Buffer | undefined>;
|
|
20
|
+
private static get openFlags();
|
|
21
|
+
private withHandle;
|
|
22
|
+
private openRelative;
|
|
23
|
+
private assertUnchanged;
|
|
24
|
+
private static readRegularFile;
|
|
25
|
+
private static exceedsLimit;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=safe-directory-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-directory-reader.d.ts","sourceRoot":"","sources":["../src/safe-directory-reader.ts"],"names":[],"mappings":"AAKA,KAAK,cAAc,GACf;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFzB,OAAO,eAGH;IAEJ,OAAa,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAY5D;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,OAAa,aAAa,CACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC,CAanD;IAEK,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAiBrC;IAEK,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAI7B;IAED,OAAO,CAAC,MAAM,KAAK,SAAS,GAK3B;YAEa,UAAU;YAcV,YAAY;YA6CZ,eAAe;mBAcR,eAAe;IAsBpC,OAAO,CAAC,MAAM,CAAC,YAAY;CAK5B"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export class SafeDirectoryReader {
|
|
5
|
+
root;
|
|
6
|
+
handle;
|
|
7
|
+
constructor(root, handle) {
|
|
8
|
+
this.root = root;
|
|
9
|
+
this.handle = handle;
|
|
10
|
+
}
|
|
11
|
+
static async open(root) {
|
|
12
|
+
if (process.platform !== "linux" && process.platform !== "darwin")
|
|
13
|
+
throw new Error("Native draft snapshots require Linux or macOS");
|
|
14
|
+
const canonical = path.join(await fs.realpath(path.dirname(root)), path.basename(root));
|
|
15
|
+
const handle = await fs.open(canonical, this.openFlags | constants.O_DIRECTORY);
|
|
16
|
+
return new SafeDirectoryReader(canonical, handle);
|
|
17
|
+
}
|
|
18
|
+
async close() {
|
|
19
|
+
await this.handle.close();
|
|
20
|
+
}
|
|
21
|
+
static async readLocalFile(filePath, maxBytes) {
|
|
22
|
+
const handle = await fs.open(filePath, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
23
|
+
try {
|
|
24
|
+
return {
|
|
25
|
+
executable: ((await handle.stat()).mode & constants.S_IXUSR) !== 0,
|
|
26
|
+
content: await this.readRegularFile(handle, maxBytes),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
await handle.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async readEntry(relative, maxBytes) {
|
|
34
|
+
return this.withHandle(relative, async (handle) => {
|
|
35
|
+
const stats = await handle.stat();
|
|
36
|
+
if (stats.isDirectory()) {
|
|
37
|
+
const directory = process.platform === "linux"
|
|
38
|
+
? `/proc/self/fd/${handle.fd}`
|
|
39
|
+
: path.join(this.root, relative);
|
|
40
|
+
const entries = await fs.readdir(directory);
|
|
41
|
+
await this.assertUnchanged(relative, handle);
|
|
42
|
+
return { type: "directory", entries };
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
type: "file",
|
|
46
|
+
content: await SafeDirectoryReader.readRegularFile(handle, maxBytes),
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async readFile(relative, maxBytes) {
|
|
51
|
+
return this.withHandle(relative, (handle) => SafeDirectoryReader.readRegularFile(handle, maxBytes));
|
|
52
|
+
}
|
|
53
|
+
static get openFlags() {
|
|
54
|
+
// Darwin's O_NOFOLLOW_ANY rejects symlinks in every path component.
|
|
55
|
+
const noFollow = process.platform === "darwin" ? 0x20000000 : constants.O_NOFOLLOW;
|
|
56
|
+
return constants.O_RDONLY | constants.O_NONBLOCK | noFollow;
|
|
57
|
+
}
|
|
58
|
+
async withHandle(relative, read) {
|
|
59
|
+
const handle = await this.openRelative(relative);
|
|
60
|
+
if (!handle)
|
|
61
|
+
return undefined;
|
|
62
|
+
try {
|
|
63
|
+
await this.assertUnchanged(relative, handle);
|
|
64
|
+
return await read(handle);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await handle.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async openRelative(relative) {
|
|
71
|
+
if (!relative ||
|
|
72
|
+
path.isAbsolute(relative) ||
|
|
73
|
+
relative
|
|
74
|
+
.split(path.sep)
|
|
75
|
+
.some((segment) => !segment || segment === ".." || segment === "."))
|
|
76
|
+
throw new Error("Native draft snapshot path is outside its root");
|
|
77
|
+
const parents = [];
|
|
78
|
+
try {
|
|
79
|
+
if (process.platform === "darwin")
|
|
80
|
+
return await fs.open(path.join(this.root, relative), SafeDirectoryReader.openFlags);
|
|
81
|
+
let parent = this.handle;
|
|
82
|
+
const segments = relative.split(path.sep);
|
|
83
|
+
for (let index = 0; index < segments.length; index++) {
|
|
84
|
+
const last = index === segments.length - 1;
|
|
85
|
+
const child = await fs.open(`/proc/self/fd/${parent.fd}/${segments[index]}`, SafeDirectoryReader.openFlags | (last ? 0 : constants.O_DIRECTORY));
|
|
86
|
+
if (last)
|
|
87
|
+
return child;
|
|
88
|
+
parents.push(child);
|
|
89
|
+
parent = child;
|
|
90
|
+
}
|
|
91
|
+
throw new Error("Native draft snapshot path is empty");
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
const code = error instanceof Error && "code" in error ? error.code : undefined;
|
|
95
|
+
if (code === "ENOENT")
|
|
96
|
+
return undefined;
|
|
97
|
+
if (code === "ELOOP" || code === "ENOTDIR")
|
|
98
|
+
throw new Error("Native filesystem mutation cannot traverse symbolic links");
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
await Promise.all(parents.map((parent) => parent.close()));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async assertUnchanged(relative, handle) {
|
|
106
|
+
const [opened, current] = await Promise.all([
|
|
107
|
+
handle.stat(),
|
|
108
|
+
fs.lstat(path.join(this.root, relative)),
|
|
109
|
+
]);
|
|
110
|
+
if (opened.dev !== current.dev || opened.ino !== current.ino)
|
|
111
|
+
throw new Error("Native filesystem mutation path changed during snapshot");
|
|
112
|
+
}
|
|
113
|
+
static async readRegularFile(handle, maxBytes) {
|
|
114
|
+
const stats = await handle.stat();
|
|
115
|
+
if (!stats.isFile())
|
|
116
|
+
throw new Error("Native filesystem mutation path must contain regular files");
|
|
117
|
+
if (stats.size > maxBytes)
|
|
118
|
+
this.exceedsLimit();
|
|
119
|
+
const chunks = [];
|
|
120
|
+
let bytes = 0;
|
|
121
|
+
while (true) {
|
|
122
|
+
const buffer = Buffer.alloc(Math.min(64 * 1024, maxBytes - bytes + 1));
|
|
123
|
+
const { bytesRead } = await handle.read(buffer);
|
|
124
|
+
if (!bytesRead)
|
|
125
|
+
return Buffer.concat(chunks);
|
|
126
|
+
bytes += bytesRead;
|
|
127
|
+
if (bytes > maxBytes)
|
|
128
|
+
this.exceedsLimit();
|
|
129
|
+
chunks.push(buffer.subarray(0, bytesRead));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
static exceedsLimit() {
|
|
133
|
+
throw new Error("Native filesystem mutation exceeds the draft snapshot limit");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=safe-directory-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-directory-reader.js","sourceRoot":"","sources":["../src/safe-directory-reader.ts"],"names":[],"mappings":"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"}
|