@openfairygui/backend 0.2.0-alpha.1 → 0.2.0-alpha.10

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenFairyGUI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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,9 @@ 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: file-backed sessions require an injected
35
- `BackendFileSystem`, while the default Node filesystem/runtime lives under `@openfairygui/backend/node`.
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. The default Node filesystem/runtime lives under `@openfairygui/backend/node`.
36
38
 
37
39
  ## Relationship to other packages
38
40
 
@@ -58,6 +60,42 @@ const applied = await runtime.applyTransaction({
58
60
  });
59
61
  ```
60
62
 
63
+ Browser-safe project session with injected storage:
64
+
65
+ ```ts
66
+ import { BackendRuntime, createBackendStorageFileSystem } from '@openfairygui/backend';
67
+
68
+ const fileSystem = createBackendStorageFileSystem({
69
+ async readFile(filePath) { return storage.readText(filePath); },
70
+ async readFileRaw(filePath) { return storage.readBytes(filePath); },
71
+ async writeFile(filePath, content) { await storage.writeText(filePath, content); },
72
+ async writeFileRaw(filePath, data) { await storage.writeBytes(filePath, data); },
73
+ async mkdir(dirPath) { await storage.mkdir(dirPath); },
74
+ async readdir(dirPath) { return storage.readdir(dirPath); },
75
+ async exists(filePath) { return storage.exists(filePath); },
76
+ });
77
+
78
+ const runtime = new BackendRuntime();
79
+ const opened = runtime.openProjectSession({
80
+ project: uamProject,
81
+ storage: {
82
+ fileSystem,
83
+ fairyPath: 'Project.fairy',
84
+ },
85
+ });
86
+ if (!opened.ok) throw new Error(opened.error.message);
87
+
88
+ const bootstrapped = await runtime.materializeSession({
89
+ sessionId: opened.data.sessionId,
90
+ expectedRevision: opened.data.revision,
91
+ mode: 'fullProject',
92
+ reason: 'workspace_bootstrap',
93
+ });
94
+ if (!bootstrapped.ok) throw new Error(bootstrapped.error.message);
95
+
96
+ console.log(bootstrapped.data.writtenPaths);
97
+ ```
98
+
61
99
  Node file-backed session:
62
100
 
63
101
  ```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-BXbt135W.cjs");
2
+ const require_runtime = require("./runtime-GKzsXJdO.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
+ 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
+ if (storage.unlink) return storage.unlink(resolved);
132
+ throw createPathError("ENOTSUP", "Storage adapter does not provide unlink().");
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 BackendSuccess, B as OpenProjectSessionInput, C as BackendJobProgress, D as BackendRuntime, E as BackendResult, F as GetEventsInput, G as BACKEND_CAPABILITY_SCHEMA_VERSION, H as SavePartialFailureError, I as GetEventsSnapshot, J as BackendDiagnostic, K as BACKEND_COMPATIBILITY_POLICY, L as GetJobInput, M as CancelJobInput, N as EventCursorInvalidError, O as BackendRuntimeOptions, P as GetCacheSnapshotInput, R as InProcessLockConflictError, S as BackendJobNotFoundError, T as BackendJobStatus, U as SessionNotFoundError, V as RefreshCacheInput, W as SessionStaleWriteError, X as BackendResponseMeta, Y as BackendMessage, Z as BackendStage, _ as BackendJobErrors, a as BackendCacheSnapshot, b as BackendJobListStatusFilter, c as BackendCapabilityUnavailableError, d as BackendEventKind, f as BackendFailure, g as BackendHostAdapter, h as BackendFileSystem, i as BackendCacheEntry, j as CacheRefreshFailedError, k as BackendSessionSnapshot, l as BackendError, m as BackendFileStat, n as ApplySessionTransactionInput, o as BackendCapabilities, p as BackendFileHandle, q as BACKEND_CONTRACT_VERSION, r as BackendArtifactBridgeCapability, s as BackendCapabilityManifest, t as AdvisoryLockConflictError, u as BackendEvent, v as BackendJobKind, w as BackendJobSnapshot, x as BackendJobNotCancellableError, y as BackendJobListSnapshot, z as ListJobsInput } from "./runtime-C5JY_kRI.cjs";
2
- export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, 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 BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionSnapshot, type BackendStage, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SessionNotFoundError, type SessionStaleWriteError };
1
+ import { $ as BACKEND_CONTRACT_VERSION, A as BackendSessionSnapshot, B as ListJobsInput, C as BackendJobProgress, D as BackendResult, E as BackendProjectSessionStorage, 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 BackendRuntime, P as EventCursorInvalidError, Q as BACKEND_COMPATIBILITY_POLICY, R as GetJobInput, S as BackendJobNotFoundError, T as BackendJobStatus, U as MaterializeValidationFailedError, V as MaterializeSessionInput, W as MaterializeWriteFailedError, X as SessionStaleWriteError, Y as SessionNotFoundError, Z as BACKEND_CAPABILITY_SCHEMA_VERSION, _ as BackendJobErrors, a as BackendCacheSnapshot, b as BackendJobListStatusFilter, c as BackendCapabilityUnavailableError, d as BackendEventKind, et as BackendDiagnostic, f as BackendFailure, g as BackendHostAdapter, h as BackendFileSystem, i as BackendCacheEntry, j as BackendSuccess, k as BackendRuntimeOptions, l as BackendError, m as BackendFileStat, n as ApplySessionTransactionInput, nt as BackendResponseMeta, o as BackendCapabilities, p as BackendFileHandle, q as SavePartialFailureError, r as BackendArtifactBridgeCapability, rt as BackendStage, s as BackendCapabilityManifest, t as AdvisoryLockConflictError, tt as BackendMessage, u as BackendEvent, v as BackendJobKind, w as BackendJobSnapshot, x as BackendJobNotCancellableError, y as BackendJobListSnapshot, z as InProcessLockConflictError } from "./runtime-Jec6FcF5.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, createBackendStorageFileSystem };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,33 @@
1
- import { A as BackendSuccess, B as OpenProjectSessionInput, C as BackendJobProgress, D as BackendRuntime, E as BackendResult, F as GetEventsInput, G as BACKEND_CAPABILITY_SCHEMA_VERSION, H as SavePartialFailureError, I as GetEventsSnapshot, J as BackendDiagnostic, K as BACKEND_COMPATIBILITY_POLICY, L as GetJobInput, M as CancelJobInput, N as EventCursorInvalidError, O as BackendRuntimeOptions, P as GetCacheSnapshotInput, R as InProcessLockConflictError, S as BackendJobNotFoundError, T as BackendJobStatus, U as SessionNotFoundError, V as RefreshCacheInput, W as SessionStaleWriteError, X as BackendResponseMeta, Y as BackendMessage, Z as BackendStage, _ as BackendJobErrors, a as BackendCacheSnapshot, b as BackendJobListStatusFilter, c as BackendCapabilityUnavailableError, d as BackendEventKind, f as BackendFailure, g as BackendHostAdapter, h as BackendFileSystem, i as BackendCacheEntry, j as CacheRefreshFailedError, k as BackendSessionSnapshot, l as BackendError, m as BackendFileStat, n as ApplySessionTransactionInput, o as BackendCapabilities, p as BackendFileHandle, q as BACKEND_CONTRACT_VERSION, r as BackendArtifactBridgeCapability, s as BackendCapabilityManifest, t as AdvisoryLockConflictError, u as BackendEvent, v as BackendJobKind, w as BackendJobSnapshot, x as BackendJobNotCancellableError, y as BackendJobListSnapshot, z as ListJobsInput } from "./runtime-C5ZsWMnH.mjs";
2
- export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, 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 BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionSnapshot, type BackendStage, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SessionNotFoundError, type SessionStaleWriteError };
1
+ import { $ as BACKEND_CONTRACT_VERSION, A as BackendSessionSnapshot, B as ListJobsInput, C as BackendJobProgress, D as BackendResult, E as BackendProjectSessionStorage, 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 BackendRuntime, P as EventCursorInvalidError, Q as BACKEND_COMPATIBILITY_POLICY, R as GetJobInput, S as BackendJobNotFoundError, T as BackendJobStatus, U as MaterializeValidationFailedError, V as MaterializeSessionInput, W as MaterializeWriteFailedError, X as SessionStaleWriteError, Y as SessionNotFoundError, Z as BACKEND_CAPABILITY_SCHEMA_VERSION, _ as BackendJobErrors, a as BackendCacheSnapshot, b as BackendJobListStatusFilter, c as BackendCapabilityUnavailableError, d as BackendEventKind, et as BackendDiagnostic, f as BackendFailure, g as BackendHostAdapter, h as BackendFileSystem, i as BackendCacheEntry, j as BackendSuccess, k as BackendRuntimeOptions, l as BackendError, m as BackendFileStat, n as ApplySessionTransactionInput, nt as BackendResponseMeta, o as BackendCapabilities, p as BackendFileHandle, q as SavePartialFailureError, r as BackendArtifactBridgeCapability, rt as BackendStage, s as BackendCapabilityManifest, t as AdvisoryLockConflictError, tt as BackendMessage, u as BackendEvent, v as BackendJobKind, w as BackendJobSnapshot, x as BackendJobNotCancellableError, y as BackendJobListSnapshot, z as InProcessLockConflictError } from "./runtime-GyNVxAQ0.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, 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-DLWLghmH.mjs";
2
- export { BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, BackendRuntime };
1
+ import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-DFatY9W0.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
+ const lockedPaths = /* @__PURE__ */ new Set();
74
+ const fileSystem = {
75
+ stat(filePath) {
76
+ return inferStat(storage, fileSystem.resolve(filePath));
77
+ },
78
+ readdir(dirPath) {
79
+ return storage.readdir(fileSystem.resolve(dirPath));
80
+ },
81
+ readFile(filePath) {
82
+ return storage.readFile(fileSystem.resolve(filePath));
83
+ },
84
+ readFileRaw(filePath) {
85
+ return storage.readFileRaw(fileSystem.resolve(filePath));
86
+ },
87
+ writeFile(filePath, content) {
88
+ return storage.writeFile(fileSystem.resolve(filePath), content);
89
+ },
90
+ writeFileRaw(filePath, data) {
91
+ return storage.writeFileRaw(fileSystem.resolve(filePath), data);
92
+ },
93
+ mkdir(dirPath, options) {
94
+ return storage.mkdir(fileSystem.resolve(dirPath), options);
95
+ },
96
+ async exists(filePath) {
97
+ if (storage.exists) return storage.exists(fileSystem.resolve(filePath));
98
+ try {
99
+ await fileSystem.stat(filePath);
100
+ return true;
101
+ } catch {
102
+ return false;
103
+ }
104
+ },
105
+ resolvePath(filePath) {
106
+ const resolved = fileSystem.resolve(filePath);
107
+ return storage.resolvePath ? storage.resolvePath(resolved) : Promise.resolve(resolved);
108
+ },
109
+ async openExclusive(filePath) {
110
+ const resolved = fileSystem.resolve(filePath);
111
+ if (storage.openExclusive) return storage.openExclusive(resolved);
112
+ if (lockedPaths.has(resolved) || await fileSystem.exists(resolved)) throw createPathError("EEXIST", `Storage path already exists: ${resolved}`);
113
+ lockedPaths.add(resolved);
114
+ let closed = false;
115
+ return {
116
+ async writeFile(content) {
117
+ if (closed) throw createPathError("EBADF", `Storage lock handle is closed: ${resolved}`);
118
+ await fileSystem.mkdir(fileSystem.dirname(resolved), { recursive: true });
119
+ await storage.writeFile(resolved, content);
120
+ },
121
+ async close() {
122
+ closed = true;
123
+ lockedPaths.delete(resolved);
124
+ }
125
+ };
126
+ },
127
+ unlink(filePath) {
128
+ const resolved = fileSystem.resolve(filePath);
129
+ lockedPaths.delete(resolved);
130
+ if (storage.unlink) return storage.unlink(resolved);
131
+ throw createPathError("ENOTSUP", "Storage adapter does not provide unlink().");
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-BXbt135W.cjs");
24
+ const require_runtime = require("./runtime-GKzsXJdO.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 { D as BackendRuntime, O as BackendRuntimeOptions, g as BackendHostAdapter, h as BackendFileSystem, m as BackendFileStat, p as BackendFileHandle } from "./runtime-C5JY_kRI.cjs";
1
+ import { O as BackendRuntime, g as BackendHostAdapter, h as BackendFileSystem, k as BackendRuntimeOptions, m as BackendFileStat, p as BackendFileHandle } from "./runtime-Jec6FcF5.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 { D as BackendRuntime, O as BackendRuntimeOptions, g as BackendHostAdapter, h as BackendFileSystem, m as BackendFileStat, p as BackendFileHandle } from "./runtime-C5ZsWMnH.mjs";
1
+ import { O as BackendRuntime, g as BackendHostAdapter, h as BackendFileSystem, k as BackendRuntimeOptions, m as BackendFileStat, p as BackendFileHandle } from "./runtime-GyNVxAQ0.mjs";
2
2
 
3
3
  //#region src/node.d.ts
4
4
  declare function createNodeBackendFileSystem(): BackendFileSystem;
package/dist/node.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as BackendRuntime } from "./runtime-DLWLghmH.mjs";
1
+ import { t as BackendRuntime } from "./runtime-DFatY9W0.mjs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  //#region src/node.ts