@openfairygui/backend 0.2.0-alpha.2 → 0.2.0-alpha.20
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 +48 -2
- package/dist/index.cjs +146 -1
- package/dist/index.d.cts +33 -2
- package/dist/index.d.mts +33 -2
- package/dist/index.mjs +146 -2
- package/dist/node.cjs +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.mjs +1 -1
- package/dist/{runtime-OO1sHuCl.d.mts → runtime-B4SwHTRC.d.mts} +89 -10
- package/dist/{runtime-qcSlD_9-.d.cts → runtime-BB_3Ws5y.d.cts} +90 -11
- package/dist/{runtime-BPWzx-Tv.mjs → runtime-CqGK_D9A.mjs} +483 -87
- package/dist/{runtime-BL9Pkfc7.cjs → runtime-D3bShb1X.cjs} +482 -86
- package/package.json +5 -4
- package/src/contracts.ts +8 -0
- package/src/index.ts +25 -12
- package/src/runtime/capabilities.ts +126 -0
- package/src/runtime/contracts.ts +512 -0
- package/src/runtime.ts +67 -540
- package/src/services/authoring-service.ts +520 -80
- package/src/services/context.ts +12 -8
- package/src/services/runtime-service.ts +108 -12
- package/src/services/session-project-writer.ts +64 -0
- package/src/services/session-utils.ts +5 -1
- package/src/storage.ts +194 -0
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ It owns:
|
|
|
12
12
|
- revisioned request handling
|
|
13
13
|
- coordinated but non-atomic save semantics
|
|
14
14
|
- browser-safe project sessions
|
|
15
|
+
- browser-safe async project storage adapter
|
|
15
16
|
- adapter-backed file sessions and backend-local advisory locking
|
|
16
17
|
- capability discovery
|
|
17
18
|
- transport-neutral bootstrap
|
|
@@ -31,8 +32,16 @@ It also provides:
|
|
|
31
32
|
|
|
32
33
|
It does **not** redefine transaction grammar or expose `Document`.
|
|
33
34
|
It also does **not** implement MCP or any transport-specific wire protocol.
|
|
34
|
-
The root `@openfairygui/backend` entrypoint is browser-safe:
|
|
35
|
-
|
|
35
|
+
The root `@openfairygui/backend` entrypoint is browser-safe: pure authoring sessions can run in memory,
|
|
36
|
+
and browser editors can inject an async storage adapter for OPFS, IndexedDB, ZIP-backed virtual filesystems,
|
|
37
|
+
or File System Access API bridges. Storage adapters must implement `unlink()` so resource rename/move/remove
|
|
38
|
+
can clean up stale source files. The default Node filesystem/runtime lives under `@openfairygui/backend/node`.
|
|
39
|
+
File-backed `openSession` hydrates primary resource bytes so browser-safe transactions can rename/move
|
|
40
|
+
assets or add/replace/remove binary resources. `saveSession` writes replacement bytes before it removes
|
|
41
|
+
stale source files, preserving the prior file when a write fails.
|
|
42
|
+
It also compares the source project with a UAM round trip through `ProjectWriter`; sessions with
|
|
43
|
+
unrepresented persisted properties expose `uamFidelity: 'unsupported'`, and write attempts fail with
|
|
44
|
+
`uam_fidelity_unsupported`. Transactions, saves, and materialization are serialized per session.
|
|
36
45
|
|
|
37
46
|
## Relationship to other packages
|
|
38
47
|
|
|
@@ -58,6 +67,43 @@ const applied = await runtime.applyTransaction({
|
|
|
58
67
|
});
|
|
59
68
|
```
|
|
60
69
|
|
|
70
|
+
Browser-safe project session with injected storage:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { BackendRuntime, createBackendStorageFileSystem } from '@openfairygui/backend';
|
|
74
|
+
|
|
75
|
+
const fileSystem = createBackendStorageFileSystem({
|
|
76
|
+
async readFile(filePath) { return storage.readText(filePath); },
|
|
77
|
+
async readFileRaw(filePath) { return storage.readBytes(filePath); },
|
|
78
|
+
async writeFile(filePath, content) { await storage.writeText(filePath, content); },
|
|
79
|
+
async writeFileRaw(filePath, data) { await storage.writeBytes(filePath, data); },
|
|
80
|
+
async mkdir(dirPath) { await storage.mkdir(dirPath); },
|
|
81
|
+
async readdir(dirPath) { return storage.readdir(dirPath); },
|
|
82
|
+
async exists(filePath) { return storage.exists(filePath); },
|
|
83
|
+
async unlink(filePath) { await storage.remove(filePath); },
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const runtime = new BackendRuntime();
|
|
87
|
+
const opened = runtime.openProjectSession({
|
|
88
|
+
project: uamProject,
|
|
89
|
+
storage: {
|
|
90
|
+
fileSystem,
|
|
91
|
+
fairyPath: 'Project.fairy',
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
if (!opened.ok) throw new Error(opened.error.message);
|
|
95
|
+
|
|
96
|
+
const bootstrapped = await runtime.materializeSession({
|
|
97
|
+
sessionId: opened.data.sessionId,
|
|
98
|
+
expectedRevision: opened.data.revision,
|
|
99
|
+
mode: 'fullProject',
|
|
100
|
+
reason: 'workspace_bootstrap',
|
|
101
|
+
});
|
|
102
|
+
if (!bootstrapped.ok) throw new Error(bootstrapped.error.message);
|
|
103
|
+
|
|
104
|
+
console.log(bootstrapped.data.writtenPaths);
|
|
105
|
+
```
|
|
106
|
+
|
|
61
107
|
Node file-backed session:
|
|
62
108
|
|
|
63
109
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,151 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_runtime = require("./runtime-
|
|
2
|
+
const require_runtime = require("./runtime-D3bShb1X.cjs");
|
|
3
|
+
//#region src/storage.ts
|
|
4
|
+
var StorageFileStat = class {
|
|
5
|
+
constructor(kind) {
|
|
6
|
+
this.kind = kind;
|
|
7
|
+
}
|
|
8
|
+
isFile() {
|
|
9
|
+
return this.kind === "file";
|
|
10
|
+
}
|
|
11
|
+
isDirectory() {
|
|
12
|
+
return this.kind === "directory";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function createPathError(code, message) {
|
|
16
|
+
const error = new Error(message);
|
|
17
|
+
error.code = code;
|
|
18
|
+
return error;
|
|
19
|
+
}
|
|
20
|
+
function normalizeStoragePath(value) {
|
|
21
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
22
|
+
const absolute = normalized.startsWith("/");
|
|
23
|
+
const rawSegments = normalized.split("/").filter((segment) => segment.length > 0);
|
|
24
|
+
const segments = [];
|
|
25
|
+
for (const segment of rawSegments) {
|
|
26
|
+
if (segment === ".") continue;
|
|
27
|
+
if (segment === "..") {
|
|
28
|
+
if (segments.length > 0) segments.pop();
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
segments.push(segment);
|
|
32
|
+
}
|
|
33
|
+
const joined = segments.join("/");
|
|
34
|
+
if (absolute) return joined ? `/${joined}` : "/";
|
|
35
|
+
return joined || ".";
|
|
36
|
+
}
|
|
37
|
+
function joinStoragePath(...paths) {
|
|
38
|
+
return normalizeStoragePath(paths.filter((part) => part.length > 0).join("/"));
|
|
39
|
+
}
|
|
40
|
+
function dirnameStoragePath(filePath) {
|
|
41
|
+
const normalized = normalizeStoragePath(filePath);
|
|
42
|
+
if (normalized === "/" || normalized === ".") return ".";
|
|
43
|
+
const absolute = normalized.startsWith("/");
|
|
44
|
+
const parts = normalized.split("/").filter((part) => part.length > 0);
|
|
45
|
+
parts.pop();
|
|
46
|
+
if (parts.length === 0) return absolute ? "/" : ".";
|
|
47
|
+
return `${absolute ? "/" : ""}${parts.join("/")}`;
|
|
48
|
+
}
|
|
49
|
+
function statFromLike(stat) {
|
|
50
|
+
if (typeof stat.isFile === "function" && typeof stat.isDirectory === "function") return stat;
|
|
51
|
+
const kind = stat.kind ?? stat.type;
|
|
52
|
+
if (kind === "file" || kind === "directory") return new StorageFileStat(kind);
|
|
53
|
+
throw createPathError("EINVAL", "Storage stat must provide kind/type or isFile()/isDirectory().");
|
|
54
|
+
}
|
|
55
|
+
async function inferStat(storage, filePath) {
|
|
56
|
+
if (storage.stat) return statFromLike(await storage.stat(filePath));
|
|
57
|
+
try {
|
|
58
|
+
await storage.readdir(filePath);
|
|
59
|
+
return new StorageFileStat("directory");
|
|
60
|
+
} catch {}
|
|
61
|
+
try {
|
|
62
|
+
await storage.readFileRaw(filePath);
|
|
63
|
+
return new StorageFileStat("file");
|
|
64
|
+
} catch {
|
|
65
|
+
try {
|
|
66
|
+
await storage.readFile(filePath);
|
|
67
|
+
return new StorageFileStat("file");
|
|
68
|
+
} catch {
|
|
69
|
+
throw createPathError("ENOENT", `Storage path not found: ${filePath}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function createBackendStorageFileSystem(storage) {
|
|
74
|
+
if (typeof storage.unlink !== "function") throw createPathError("ENOTSUP", "Storage adapter must provide unlink() for project resource lifecycle writes.");
|
|
75
|
+
const lockedPaths = /* @__PURE__ */ new Set();
|
|
76
|
+
const fileSystem = {
|
|
77
|
+
stat(filePath) {
|
|
78
|
+
return inferStat(storage, fileSystem.resolve(filePath));
|
|
79
|
+
},
|
|
80
|
+
readdir(dirPath) {
|
|
81
|
+
return storage.readdir(fileSystem.resolve(dirPath));
|
|
82
|
+
},
|
|
83
|
+
readFile(filePath) {
|
|
84
|
+
return storage.readFile(fileSystem.resolve(filePath));
|
|
85
|
+
},
|
|
86
|
+
readFileRaw(filePath) {
|
|
87
|
+
return storage.readFileRaw(fileSystem.resolve(filePath));
|
|
88
|
+
},
|
|
89
|
+
writeFile(filePath, content) {
|
|
90
|
+
return storage.writeFile(fileSystem.resolve(filePath), content);
|
|
91
|
+
},
|
|
92
|
+
writeFileRaw(filePath, data) {
|
|
93
|
+
return storage.writeFileRaw(fileSystem.resolve(filePath), data);
|
|
94
|
+
},
|
|
95
|
+
mkdir(dirPath, options) {
|
|
96
|
+
return storage.mkdir(fileSystem.resolve(dirPath), options);
|
|
97
|
+
},
|
|
98
|
+
async exists(filePath) {
|
|
99
|
+
if (storage.exists) return storage.exists(fileSystem.resolve(filePath));
|
|
100
|
+
try {
|
|
101
|
+
await fileSystem.stat(filePath);
|
|
102
|
+
return true;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
resolvePath(filePath) {
|
|
108
|
+
const resolved = fileSystem.resolve(filePath);
|
|
109
|
+
return storage.resolvePath ? storage.resolvePath(resolved) : Promise.resolve(resolved);
|
|
110
|
+
},
|
|
111
|
+
async openExclusive(filePath) {
|
|
112
|
+
const resolved = fileSystem.resolve(filePath);
|
|
113
|
+
if (storage.openExclusive) return storage.openExclusive(resolved);
|
|
114
|
+
if (lockedPaths.has(resolved) || await fileSystem.exists(resolved)) throw createPathError("EEXIST", `Storage path already exists: ${resolved}`);
|
|
115
|
+
lockedPaths.add(resolved);
|
|
116
|
+
let closed = false;
|
|
117
|
+
return {
|
|
118
|
+
async writeFile(content) {
|
|
119
|
+
if (closed) throw createPathError("EBADF", `Storage lock handle is closed: ${resolved}`);
|
|
120
|
+
await fileSystem.mkdir(fileSystem.dirname(resolved), { recursive: true });
|
|
121
|
+
await storage.writeFile(resolved, content);
|
|
122
|
+
},
|
|
123
|
+
async close() {
|
|
124
|
+
closed = true;
|
|
125
|
+
lockedPaths.delete(resolved);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
unlink(filePath) {
|
|
130
|
+
const resolved = fileSystem.resolve(filePath);
|
|
131
|
+
lockedPaths.delete(resolved);
|
|
132
|
+
return storage.unlink(resolved);
|
|
133
|
+
},
|
|
134
|
+
join(...paths) {
|
|
135
|
+
return storage.join ? storage.join(...paths) : joinStoragePath(...paths);
|
|
136
|
+
},
|
|
137
|
+
dirname(filePath) {
|
|
138
|
+
return storage.dirname ? storage.dirname(filePath) : dirnameStoragePath(filePath);
|
|
139
|
+
},
|
|
140
|
+
resolve(...paths) {
|
|
141
|
+
return storage.resolve ? storage.resolve(...paths) : joinStoragePath(...paths);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
return fileSystem;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
3
147
|
exports.BACKEND_CAPABILITY_SCHEMA_VERSION = require_runtime.BACKEND_CAPABILITY_SCHEMA_VERSION;
|
|
4
148
|
exports.BACKEND_COMPATIBILITY_POLICY = require_runtime.BACKEND_COMPATIBILITY_POLICY;
|
|
5
149
|
exports.BACKEND_CONTRACT_VERSION = require_runtime.BACKEND_CONTRACT_VERSION;
|
|
6
150
|
exports.BackendRuntime = require_runtime.BackendRuntime;
|
|
151
|
+
exports.createBackendStorageFileSystem = createBackendStorageFileSystem;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
|
|
1
|
+
import { $ as BACKEND_COMPATIBILITY_POLICY, A as BackendSessionSnapshot, B as ListJobsInput, C as BackendJobNotFoundError, D as BackendProjectSessionStorage, E as BackendJobStatus, F as GetCacheSnapshotInput, G as OpenProjectSessionInput, H as MaterializeSessionSnapshot, I as GetEventsInput, J as SaveSessionInput, K as RefreshCacheInput, L as GetEventsSnapshot, M as CacheRefreshFailedError, N as CancelJobInput, O as BackendResult, P as EventCursorInvalidError, Q as BACKEND_CAPABILITY_SCHEMA_VERSION, R as GetJobInput, S as BackendJobNotCancellableError, T as BackendJobSnapshot, U as MaterializeValidationFailedError, V as MaterializeSessionInput, W as MaterializeWriteFailedError, X as SessionStaleWriteError, Y as SessionNotFoundError, Z as UamFidelityUnsupportedError, _ as BackendHostAdapter, a as BackendCacheEntry, b as BackendJobListSnapshot, c as BackendCapabilityManifest, d as BackendEvent, et as BACKEND_CONTRACT_VERSION, f as BackendEventKind, g as BackendFileSystem, h as BackendFileStat, i as BackendArtifactBridgeCapability, it as BackendStage, j as BackendSuccess, k as BackendRuntimeOptions, l as BackendCapabilityUnavailableError, m as BackendFileHandle, n as AdvisoryLockConflictError, nt as BackendMessage, o as BackendCacheSnapshot, p as BackendFailure, q as SavePartialFailureError, r as ApplySessionTransactionInput, rt as BackendResponseMeta, s as BackendCapabilities, t as BackendRuntime, tt as BackendDiagnostic, u as BackendError, v as BackendJobErrors, w as BackendJobProgress, x as BackendJobListStatusFilter, y as BackendJobKind, z as InProcessLockConflictError } from "./runtime-BB_3Ws5y.cjs";
|
|
2
|
+
import { FileSystem } from "@openfairygui/core/project-io";
|
|
3
|
+
|
|
4
|
+
//#region src/storage.d.ts
|
|
5
|
+
type StorageStatKind = 'file' | 'directory';
|
|
6
|
+
interface BackendStorageStatLike {
|
|
7
|
+
kind?: StorageStatKind;
|
|
8
|
+
type?: StorageStatKind;
|
|
9
|
+
isFile?(): boolean;
|
|
10
|
+
isDirectory?(): boolean;
|
|
11
|
+
}
|
|
12
|
+
interface BackendAsyncStorageAdapter {
|
|
13
|
+
readFile(filePath: string): Promise<string>;
|
|
14
|
+
readFileRaw(filePath: string): Promise<Uint8Array>;
|
|
15
|
+
writeFile(filePath: string, content: string): Promise<void>;
|
|
16
|
+
writeFileRaw(filePath: string, data: Uint8Array): Promise<void>;
|
|
17
|
+
mkdir(dirPath: string, options?: {
|
|
18
|
+
recursive?: boolean;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
readdir(dirPath: string): Promise<string[]>;
|
|
21
|
+
exists?(filePath: string): Promise<boolean>;
|
|
22
|
+
stat?(filePath: string): Promise<BackendStorageStatLike>;
|
|
23
|
+
resolvePath?(filePath: string): Promise<string>;
|
|
24
|
+
openExclusive?(filePath: string): Promise<BackendFileHandle>;
|
|
25
|
+
unlink(filePath: string): Promise<void>;
|
|
26
|
+
join?(...paths: string[]): string;
|
|
27
|
+
dirname?(filePath: string): string;
|
|
28
|
+
resolve?(...paths: string[]): string;
|
|
29
|
+
}
|
|
30
|
+
type BackendStorageFileSystem = BackendFileSystem & FileSystem;
|
|
31
|
+
declare function createBackendStorageFileSystem(storage: BackendAsyncStorageAdapter): BackendStorageFileSystem;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileHandle, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
|
|
1
|
+
import { $ as BACKEND_COMPATIBILITY_POLICY, A as BackendSessionSnapshot, B as ListJobsInput, C as BackendJobNotFoundError, D as BackendProjectSessionStorage, E as BackendJobStatus, F as GetCacheSnapshotInput, G as OpenProjectSessionInput, H as MaterializeSessionSnapshot, I as GetEventsInput, J as SaveSessionInput, K as RefreshCacheInput, L as GetEventsSnapshot, M as CacheRefreshFailedError, N as CancelJobInput, O as BackendResult, P as EventCursorInvalidError, Q as BACKEND_CAPABILITY_SCHEMA_VERSION, R as GetJobInput, S as BackendJobNotCancellableError, T as BackendJobSnapshot, U as MaterializeValidationFailedError, V as MaterializeSessionInput, W as MaterializeWriteFailedError, X as SessionStaleWriteError, Y as SessionNotFoundError, Z as UamFidelityUnsupportedError, _ as BackendHostAdapter, a as BackendCacheEntry, b as BackendJobListSnapshot, c as BackendCapabilityManifest, d as BackendEvent, et as BACKEND_CONTRACT_VERSION, f as BackendEventKind, g as BackendFileSystem, h as BackendFileStat, i as BackendArtifactBridgeCapability, it as BackendStage, j as BackendSuccess, k as BackendRuntimeOptions, l as BackendCapabilityUnavailableError, m as BackendFileHandle, n as AdvisoryLockConflictError, nt as BackendMessage, o as BackendCacheSnapshot, p as BackendFailure, q as SavePartialFailureError, r as ApplySessionTransactionInput, rt as BackendResponseMeta, s as BackendCapabilities, t as BackendRuntime, tt as BackendDiagnostic, u as BackendError, v as BackendJobErrors, w as BackendJobProgress, x as BackendJobListStatusFilter, y as BackendJobKind, z as InProcessLockConflictError } from "./runtime-B4SwHTRC.mjs";
|
|
2
|
+
import { FileSystem } from "@openfairygui/core/project-io";
|
|
3
|
+
|
|
4
|
+
//#region src/storage.d.ts
|
|
5
|
+
type StorageStatKind = 'file' | 'directory';
|
|
6
|
+
interface BackendStorageStatLike {
|
|
7
|
+
kind?: StorageStatKind;
|
|
8
|
+
type?: StorageStatKind;
|
|
9
|
+
isFile?(): boolean;
|
|
10
|
+
isDirectory?(): boolean;
|
|
11
|
+
}
|
|
12
|
+
interface BackendAsyncStorageAdapter {
|
|
13
|
+
readFile(filePath: string): Promise<string>;
|
|
14
|
+
readFileRaw(filePath: string): Promise<Uint8Array>;
|
|
15
|
+
writeFile(filePath: string, content: string): Promise<void>;
|
|
16
|
+
writeFileRaw(filePath: string, data: Uint8Array): Promise<void>;
|
|
17
|
+
mkdir(dirPath: string, options?: {
|
|
18
|
+
recursive?: boolean;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
readdir(dirPath: string): Promise<string[]>;
|
|
21
|
+
exists?(filePath: string): Promise<boolean>;
|
|
22
|
+
stat?(filePath: string): Promise<BackendStorageStatLike>;
|
|
23
|
+
resolvePath?(filePath: string): Promise<string>;
|
|
24
|
+
openExclusive?(filePath: string): Promise<BackendFileHandle>;
|
|
25
|
+
unlink(filePath: string): Promise<void>;
|
|
26
|
+
join?(...paths: string[]): string;
|
|
27
|
+
dirname?(filePath: string): string;
|
|
28
|
+
resolve?(...paths: string[]): string;
|
|
29
|
+
}
|
|
30
|
+
type BackendStorageFileSystem = BackendFileSystem & FileSystem;
|
|
31
|
+
declare function createBackendStorageFileSystem(storage: BackendAsyncStorageAdapter): BackendStorageFileSystem;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileHandle, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,146 @@
|
|
|
1
|
-
import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-
|
|
2
|
-
|
|
1
|
+
import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-CqGK_D9A.mjs";
|
|
2
|
+
//#region src/storage.ts
|
|
3
|
+
var StorageFileStat = class {
|
|
4
|
+
constructor(kind) {
|
|
5
|
+
this.kind = kind;
|
|
6
|
+
}
|
|
7
|
+
isFile() {
|
|
8
|
+
return this.kind === "file";
|
|
9
|
+
}
|
|
10
|
+
isDirectory() {
|
|
11
|
+
return this.kind === "directory";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function createPathError(code, message) {
|
|
15
|
+
const error = new Error(message);
|
|
16
|
+
error.code = code;
|
|
17
|
+
return error;
|
|
18
|
+
}
|
|
19
|
+
function normalizeStoragePath(value) {
|
|
20
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
21
|
+
const absolute = normalized.startsWith("/");
|
|
22
|
+
const rawSegments = normalized.split("/").filter((segment) => segment.length > 0);
|
|
23
|
+
const segments = [];
|
|
24
|
+
for (const segment of rawSegments) {
|
|
25
|
+
if (segment === ".") continue;
|
|
26
|
+
if (segment === "..") {
|
|
27
|
+
if (segments.length > 0) segments.pop();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
segments.push(segment);
|
|
31
|
+
}
|
|
32
|
+
const joined = segments.join("/");
|
|
33
|
+
if (absolute) return joined ? `/${joined}` : "/";
|
|
34
|
+
return joined || ".";
|
|
35
|
+
}
|
|
36
|
+
function joinStoragePath(...paths) {
|
|
37
|
+
return normalizeStoragePath(paths.filter((part) => part.length > 0).join("/"));
|
|
38
|
+
}
|
|
39
|
+
function dirnameStoragePath(filePath) {
|
|
40
|
+
const normalized = normalizeStoragePath(filePath);
|
|
41
|
+
if (normalized === "/" || normalized === ".") return ".";
|
|
42
|
+
const absolute = normalized.startsWith("/");
|
|
43
|
+
const parts = normalized.split("/").filter((part) => part.length > 0);
|
|
44
|
+
parts.pop();
|
|
45
|
+
if (parts.length === 0) return absolute ? "/" : ".";
|
|
46
|
+
return `${absolute ? "/" : ""}${parts.join("/")}`;
|
|
47
|
+
}
|
|
48
|
+
function statFromLike(stat) {
|
|
49
|
+
if (typeof stat.isFile === "function" && typeof stat.isDirectory === "function") return stat;
|
|
50
|
+
const kind = stat.kind ?? stat.type;
|
|
51
|
+
if (kind === "file" || kind === "directory") return new StorageFileStat(kind);
|
|
52
|
+
throw createPathError("EINVAL", "Storage stat must provide kind/type or isFile()/isDirectory().");
|
|
53
|
+
}
|
|
54
|
+
async function inferStat(storage, filePath) {
|
|
55
|
+
if (storage.stat) return statFromLike(await storage.stat(filePath));
|
|
56
|
+
try {
|
|
57
|
+
await storage.readdir(filePath);
|
|
58
|
+
return new StorageFileStat("directory");
|
|
59
|
+
} catch {}
|
|
60
|
+
try {
|
|
61
|
+
await storage.readFileRaw(filePath);
|
|
62
|
+
return new StorageFileStat("file");
|
|
63
|
+
} catch {
|
|
64
|
+
try {
|
|
65
|
+
await storage.readFile(filePath);
|
|
66
|
+
return new StorageFileStat("file");
|
|
67
|
+
} catch {
|
|
68
|
+
throw createPathError("ENOENT", `Storage path not found: ${filePath}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function createBackendStorageFileSystem(storage) {
|
|
73
|
+
if (typeof storage.unlink !== "function") throw createPathError("ENOTSUP", "Storage adapter must provide unlink() for project resource lifecycle writes.");
|
|
74
|
+
const lockedPaths = /* @__PURE__ */ new Set();
|
|
75
|
+
const fileSystem = {
|
|
76
|
+
stat(filePath) {
|
|
77
|
+
return inferStat(storage, fileSystem.resolve(filePath));
|
|
78
|
+
},
|
|
79
|
+
readdir(dirPath) {
|
|
80
|
+
return storage.readdir(fileSystem.resolve(dirPath));
|
|
81
|
+
},
|
|
82
|
+
readFile(filePath) {
|
|
83
|
+
return storage.readFile(fileSystem.resolve(filePath));
|
|
84
|
+
},
|
|
85
|
+
readFileRaw(filePath) {
|
|
86
|
+
return storage.readFileRaw(fileSystem.resolve(filePath));
|
|
87
|
+
},
|
|
88
|
+
writeFile(filePath, content) {
|
|
89
|
+
return storage.writeFile(fileSystem.resolve(filePath), content);
|
|
90
|
+
},
|
|
91
|
+
writeFileRaw(filePath, data) {
|
|
92
|
+
return storage.writeFileRaw(fileSystem.resolve(filePath), data);
|
|
93
|
+
},
|
|
94
|
+
mkdir(dirPath, options) {
|
|
95
|
+
return storage.mkdir(fileSystem.resolve(dirPath), options);
|
|
96
|
+
},
|
|
97
|
+
async exists(filePath) {
|
|
98
|
+
if (storage.exists) return storage.exists(fileSystem.resolve(filePath));
|
|
99
|
+
try {
|
|
100
|
+
await fileSystem.stat(filePath);
|
|
101
|
+
return true;
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
resolvePath(filePath) {
|
|
107
|
+
const resolved = fileSystem.resolve(filePath);
|
|
108
|
+
return storage.resolvePath ? storage.resolvePath(resolved) : Promise.resolve(resolved);
|
|
109
|
+
},
|
|
110
|
+
async openExclusive(filePath) {
|
|
111
|
+
const resolved = fileSystem.resolve(filePath);
|
|
112
|
+
if (storage.openExclusive) return storage.openExclusive(resolved);
|
|
113
|
+
if (lockedPaths.has(resolved) || await fileSystem.exists(resolved)) throw createPathError("EEXIST", `Storage path already exists: ${resolved}`);
|
|
114
|
+
lockedPaths.add(resolved);
|
|
115
|
+
let closed = false;
|
|
116
|
+
return {
|
|
117
|
+
async writeFile(content) {
|
|
118
|
+
if (closed) throw createPathError("EBADF", `Storage lock handle is closed: ${resolved}`);
|
|
119
|
+
await fileSystem.mkdir(fileSystem.dirname(resolved), { recursive: true });
|
|
120
|
+
await storage.writeFile(resolved, content);
|
|
121
|
+
},
|
|
122
|
+
async close() {
|
|
123
|
+
closed = true;
|
|
124
|
+
lockedPaths.delete(resolved);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
unlink(filePath) {
|
|
129
|
+
const resolved = fileSystem.resolve(filePath);
|
|
130
|
+
lockedPaths.delete(resolved);
|
|
131
|
+
return storage.unlink(resolved);
|
|
132
|
+
},
|
|
133
|
+
join(...paths) {
|
|
134
|
+
return storage.join ? storage.join(...paths) : joinStoragePath(...paths);
|
|
135
|
+
},
|
|
136
|
+
dirname(filePath) {
|
|
137
|
+
return storage.dirname ? storage.dirname(filePath) : dirnameStoragePath(filePath);
|
|
138
|
+
},
|
|
139
|
+
resolve(...paths) {
|
|
140
|
+
return storage.resolve ? storage.resolve(...paths) : joinStoragePath(...paths);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return fileSystem;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, BackendRuntime, createBackendStorageFileSystem };
|
package/dist/node.cjs
CHANGED
|
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
|
-
const require_runtime = require("./runtime-
|
|
24
|
+
const require_runtime = require("./runtime-D3bShb1X.cjs");
|
|
25
25
|
let node_fs_promises = require("node:fs/promises");
|
|
26
26
|
node_fs_promises = __toESM(node_fs_promises);
|
|
27
27
|
let node_path = require("node:path");
|
package/dist/node.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as BackendHostAdapter, g as BackendFileSystem, h as BackendFileStat, k as BackendRuntimeOptions, m as BackendFileHandle, t as BackendRuntime } from "./runtime-BB_3Ws5y.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/node.d.ts
|
|
4
4
|
declare function createNodeBackendFileSystem(): BackendFileSystem;
|
package/dist/node.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as BackendHostAdapter, g as BackendFileSystem, h as BackendFileStat, k as BackendRuntimeOptions, m as BackendFileHandle, t as BackendRuntime } from "./runtime-B4SwHTRC.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/node.d.ts
|
|
4
4
|
declare function createNodeBackendFileSystem(): BackendFileSystem;
|
package/dist/node.mjs
CHANGED