@openfairygui/backend 0.2.0-alpha.1 → 0.2.0-alpha.2
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 +21 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- 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-BXbt135W.cjs → runtime-BL9Pkfc7.cjs} +10 -9
- package/dist/{runtime-DLWLghmH.mjs → runtime-BPWzx-Tv.mjs} +3 -2
- package/dist/{runtime-C5JY_kRI.d.cts → runtime-OO1sHuCl.d.mts} +2 -2
- package/dist/{runtime-C5ZsWMnH.d.mts → runtime-qcSlD_9-.d.cts} +2 -2
- package/package.json +65 -65
- package/src/runtime.ts +53 -27
- package/src/services/authoring-service.ts +145 -44
- package/src/services/context.ts +1 -1
- package/src/services/runtime-service.ts +50 -21
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/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_runtime = require("./runtime-
|
|
2
|
+
const require_runtime = require("./runtime-BL9Pkfc7.cjs");
|
|
3
3
|
exports.BACKEND_CAPABILITY_SCHEMA_VERSION = require_runtime.BACKEND_CAPABILITY_SCHEMA_VERSION;
|
|
4
4
|
exports.BACKEND_COMPATIBILITY_POLICY = require_runtime.BACKEND_COMPATIBILITY_POLICY;
|
|
5
5
|
exports.BACKEND_CONTRACT_VERSION = require_runtime.BACKEND_CONTRACT_VERSION;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-qcSlD_9-.cjs";
|
|
2
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 };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-OO1sHuCl.mjs";
|
|
2
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-
|
|
1
|
+
import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-BPWzx-Tv.mjs";
|
|
2
2
|
export { BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, BackendRuntime };
|
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-BL9Pkfc7.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-
|
|
1
|
+
import { D as BackendRuntime, O as BackendRuntimeOptions, g as BackendHostAdapter, h as BackendFileSystem, m as BackendFileStat, p as BackendFileHandle } from "./runtime-qcSlD_9-.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-
|
|
1
|
+
import { D as BackendRuntime, O as BackendRuntimeOptions, g as BackendHostAdapter, h as BackendFileSystem, m as BackendFileStat, p as BackendFileHandle } from "./runtime-OO1sHuCl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/node.d.ts
|
|
4
4
|
declare function createNodeBackendFileSystem(): BackendFileSystem;
|
package/dist/node.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require("./node.cjs");
|
|
2
|
-
let
|
|
3
|
-
let
|
|
2
|
+
let _openfairygui_core_uam = require("@openfairygui/core/uam");
|
|
3
|
+
let _openfairygui_core_project_io = require("@openfairygui/core/project-io");
|
|
4
|
+
let _openfairygui_functions_uam = require("@openfairygui/functions/uam");
|
|
4
5
|
//#region src/contracts.ts
|
|
5
6
|
const BACKEND_CONTRACT_VERSION = "1.1.0-p2";
|
|
6
7
|
const BACKEND_CAPABILITY_SCHEMA_VERSION = 2;
|
|
@@ -276,7 +277,7 @@ var AuthoringService = class {
|
|
|
276
277
|
revision: session.revision
|
|
277
278
|
});
|
|
278
279
|
}
|
|
279
|
-
const result = (0,
|
|
280
|
+
const result = (0, _openfairygui_functions_uam.applyUamTransactionApp)({
|
|
280
281
|
project: session.project,
|
|
281
282
|
operations: input.operations
|
|
282
283
|
});
|
|
@@ -355,7 +356,7 @@ var AuthoringService = class {
|
|
|
355
356
|
revision: session.revision
|
|
356
357
|
});
|
|
357
358
|
try {
|
|
358
|
-
await new
|
|
359
|
+
await new _openfairygui_core_project_io.ProjectWriter(createWriterFileSystem(fileSystem, committedPaths, failedPaths)).write((0, _openfairygui_core_uam.materializeUamProject)(session.project), session.fairyPath);
|
|
359
360
|
session.lastSavedRevision = session.revision;
|
|
360
361
|
session.dirty = false;
|
|
361
362
|
const cacheEntry = this.cacheService.refreshSession(session);
|
|
@@ -892,7 +893,7 @@ var RuntimeService = class {
|
|
|
892
893
|
canonicalPathKey
|
|
893
894
|
}));
|
|
894
895
|
await advisoryLock.close();
|
|
895
|
-
const project = (0,
|
|
896
|
+
const project = (0, _openfairygui_core_uam.liftDocumentToUamProject)(await new _openfairygui_core_project_io.ProjectReader(createProjectReaderFileSystem(fileSystem)).read(fairyPath));
|
|
896
897
|
const sessionId = randomId();
|
|
897
898
|
const session = {
|
|
898
899
|
sessionId,
|
|
@@ -954,7 +955,7 @@ var RuntimeService = class {
|
|
|
954
955
|
canonicalProjectPath,
|
|
955
956
|
canonicalPathKey,
|
|
956
957
|
lockFilePath: "",
|
|
957
|
-
project: (0,
|
|
958
|
+
project: (0, _openfairygui_core_uam.normalizeUamProject)(input.project),
|
|
958
959
|
revision: 0,
|
|
959
960
|
lastSavedRevision: 0,
|
|
960
961
|
dirty: false,
|
|
@@ -1047,9 +1048,9 @@ function createCapabilities() {
|
|
|
1047
1048
|
authoring: {
|
|
1048
1049
|
applyTransaction: true,
|
|
1049
1050
|
saveSession: true,
|
|
1050
|
-
resourceKinds: [...
|
|
1051
|
-
nodeKinds: [...
|
|
1052
|
-
gearKinds: [...
|
|
1051
|
+
resourceKinds: [..._openfairygui_core_uam.UAM_SUPPORTED_MATERIALIZATION_SCOPE.resourceKinds],
|
|
1052
|
+
nodeKinds: [..._openfairygui_core_uam.UAM_SUPPORTED_MATERIALIZATION_SCOPE.nodeKinds],
|
|
1053
|
+
gearKinds: [..._openfairygui_core_uam.UAM_SUPPORTED_MATERIALIZATION_SCOPE.gearKinds],
|
|
1053
1054
|
unsupported: ["artifact.publish", "artifact.restore"]
|
|
1054
1055
|
},
|
|
1055
1056
|
artifact: createArtifactCapabilities(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { UAM_SUPPORTED_MATERIALIZATION_SCOPE, liftDocumentToUamProject, materializeUamProject, normalizeUamProject } from "@openfairygui/core/uam";
|
|
2
|
+
import { ProjectReader, ProjectWriter } from "@openfairygui/core/project-io";
|
|
3
|
+
import { applyUamTransactionApp } from "@openfairygui/functions/uam";
|
|
3
4
|
//#region src/contracts.ts
|
|
4
5
|
const BACKEND_CONTRACT_VERSION = "1.1.0-p2";
|
|
5
6
|
const BACKEND_CAPABILITY_SCHEMA_VERSION = 2;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UamProject, UamTransactionOperation } from "@openfairygui/core";
|
|
2
|
-
import { ApplyUamTransactionAppError } from "@openfairygui/functions";
|
|
1
|
+
import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
|
|
2
|
+
import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
|
|
3
3
|
|
|
4
4
|
//#region src/contracts.d.ts
|
|
5
5
|
declare const BACKEND_CONTRACT_VERSION: "1.1.0-p2";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UamProject, UamTransactionOperation } from "@openfairygui/core";
|
|
2
|
-
import { ApplyUamTransactionAppError } from "@openfairygui/functions";
|
|
1
|
+
import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
|
|
2
|
+
import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
|
|
3
3
|
|
|
4
4
|
//#region src/contracts.d.ts
|
|
5
5
|
declare const BACKEND_CONTRACT_VERSION: "1.1.0-p2";
|
package/package.json
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
2
|
+
"name": "@openfairygui/backend",
|
|
3
|
+
"version": "0.2.0-alpha.2",
|
|
4
|
+
"description": "FairyGUI Headless Authoring SDK — stateful backend runtime and session services.",
|
|
5
|
+
"author": "OpenFairyGUI Contributors",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/OpenFairyGUI/OpenFairyGUI.git",
|
|
10
|
+
"directory": "packages/backend"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/OpenFairyGUI/OpenFairyGUI#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/OpenFairyGUI/OpenFairYGUI/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"main": "./dist/index.cjs",
|
|
19
|
+
"module": "./dist/index.mjs",
|
|
20
|
+
"types": "./dist/index.d.mts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"require": {
|
|
24
|
+
"types": "./dist/index.d.cts",
|
|
25
|
+
"default": "./dist/index.cjs"
|
|
26
|
+
},
|
|
27
|
+
"default": {
|
|
28
|
+
"types": "./dist/index.d.mts",
|
|
29
|
+
"default": "./dist/index.mjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"./node": {
|
|
33
|
+
"require": {
|
|
34
|
+
"types": "./dist/node.d.cts",
|
|
35
|
+
"default": "./dist/node.cjs"
|
|
36
|
+
},
|
|
37
|
+
"default": {
|
|
38
|
+
"types": "./dist/node.d.mts",
|
|
39
|
+
"default": "./dist/node.mjs"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"src/"
|
|
46
|
+
],
|
|
47
|
+
"keywords": [
|
|
48
|
+
"fairygui",
|
|
49
|
+
"backend",
|
|
50
|
+
"session",
|
|
51
|
+
"authoring",
|
|
52
|
+
"runtime"
|
|
53
|
+
],
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@openfairygui/core": "0.2.0-alpha.2",
|
|
56
|
+
"@openfairygui/functions": "0.2.0-alpha.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"ava": "^7.0.0",
|
|
60
|
+
"tsx": "^4.0.0"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsdown src/index.ts src/node.ts --format esm,cjs --platform node --external node:fs --external node:fs/promises --external node:path --env.PACKAGE_VERSION=$npm_package_version",
|
|
64
|
+
"build:watch": "tsdown src/index.ts src/node.ts --watch --format esm,cjs --platform node --external node:fs --external node:fs/promises --external node:path --env.PACKAGE_VERSION=$npm_package_version"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/runtime.ts
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
UAM_SUPPORTED_MATERIALIZATION_SCOPE,
|
|
3
3
|
type UamProject,
|
|
4
4
|
type UamTransactionOperation,
|
|
5
|
-
} from '@openfairygui/core';
|
|
6
|
-
import type { ApplyUamTransactionAppError } from '@openfairygui/functions';
|
|
5
|
+
} from '@openfairygui/core/uam';
|
|
6
|
+
import type { ApplyUamTransactionAppError } from '@openfairygui/functions/uam';
|
|
7
7
|
import {
|
|
8
8
|
BACKEND_CAPABILITY_SCHEMA_VERSION,
|
|
9
9
|
BACKEND_COMPATIBILITY_POLICY,
|
|
@@ -47,11 +47,7 @@ export interface BackendFileSystem {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export interface BackendHostAdapter {
|
|
50
|
-
lockMetadata?(input: {
|
|
51
|
-
canonicalPathKey: string;
|
|
52
|
-
canonicalProjectPath: string;
|
|
53
|
-
lockFilePath: string;
|
|
54
|
-
}): unknown;
|
|
50
|
+
lockMetadata?(input: { canonicalPathKey: string; canonicalProjectPath: string; lockFilePath: string }): unknown;
|
|
55
51
|
}
|
|
56
52
|
|
|
57
53
|
export interface BackendArtifactBridgeCapability {
|
|
@@ -189,9 +185,7 @@ export interface BackendFailure<E extends BackendError = BackendError> {
|
|
|
189
185
|
session?: BackendSessionSnapshot;
|
|
190
186
|
}
|
|
191
187
|
|
|
192
|
-
export type BackendResult<T, E extends BackendError = BackendError> =
|
|
193
|
-
| BackendSuccess<T>
|
|
194
|
-
| BackendFailure<E>;
|
|
188
|
+
export type BackendResult<T, E extends BackendError = BackendError> = BackendSuccess<T> | BackendFailure<E>;
|
|
195
189
|
|
|
196
190
|
export interface SessionNotFoundError {
|
|
197
191
|
code: 'session_not_found';
|
|
@@ -446,10 +440,10 @@ export interface BackendRuntimeOptions {
|
|
|
446
440
|
}
|
|
447
441
|
|
|
448
442
|
const BACKEND_METHODS = [
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
443
|
+
'getCapabilities',
|
|
444
|
+
'openSession',
|
|
445
|
+
'openProjectSession',
|
|
446
|
+
'getSession',
|
|
453
447
|
'applyTransaction',
|
|
454
448
|
'saveSession',
|
|
455
449
|
'closeSession',
|
|
@@ -457,8 +451,8 @@ const BACKEND_METHODS = [
|
|
|
457
451
|
'getJob',
|
|
458
452
|
'listJobs',
|
|
459
453
|
'cancelJob',
|
|
460
|
-
|
|
461
|
-
|
|
454
|
+
'getCacheSnapshot',
|
|
455
|
+
'refreshCache',
|
|
462
456
|
] as const;
|
|
463
457
|
|
|
464
458
|
const ARTIFACT_BRIDGE_CAPABILITY = {
|
|
@@ -593,7 +587,14 @@ export class BackendRuntime {
|
|
|
593
587
|
return this.readService.getCapabilities() as BackendSuccess<BackendCapabilities>;
|
|
594
588
|
}
|
|
595
589
|
|
|
596
|
-
public async openSession(input: {
|
|
590
|
+
public async openSession(input: {
|
|
591
|
+
projectPath: string;
|
|
592
|
+
}): Promise<
|
|
593
|
+
BackendResult<
|
|
594
|
+
BackendSessionSnapshot,
|
|
595
|
+
InProcessLockConflictError | AdvisoryLockConflictError | BackendCapabilityUnavailableError
|
|
596
|
+
>
|
|
597
|
+
> {
|
|
597
598
|
return this.runtimeService.openSession(input);
|
|
598
599
|
}
|
|
599
600
|
|
|
@@ -607,27 +608,47 @@ export class BackendRuntime {
|
|
|
607
608
|
|
|
608
609
|
public async applyTransaction(
|
|
609
610
|
input: ApplySessionTransactionInput,
|
|
610
|
-
): Promise<
|
|
611
|
+
): Promise<
|
|
612
|
+
BackendResult<
|
|
613
|
+
BackendSessionSnapshot,
|
|
614
|
+
SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError
|
|
615
|
+
>
|
|
616
|
+
> {
|
|
611
617
|
return this.authoringService.applyTransaction(input);
|
|
612
618
|
}
|
|
613
619
|
|
|
614
|
-
public async saveSession(
|
|
615
|
-
|
|
616
|
-
|
|
620
|
+
public async saveSession(input: {
|
|
621
|
+
sessionId: string;
|
|
622
|
+
expectedRevision?: number;
|
|
623
|
+
targetPath?: string;
|
|
624
|
+
}): Promise<
|
|
625
|
+
BackendResult<
|
|
626
|
+
BackendSessionSnapshot,
|
|
627
|
+
| SessionNotFoundError
|
|
628
|
+
| SessionStaleWriteError
|
|
629
|
+
| SavePartialFailureError
|
|
630
|
+
| PathPolicyViolationError
|
|
631
|
+
| BackendCapabilityUnavailableError
|
|
632
|
+
>
|
|
633
|
+
> {
|
|
617
634
|
return this.authoringService.saveSession(input);
|
|
618
635
|
}
|
|
619
636
|
|
|
620
|
-
public async closeSession(
|
|
621
|
-
|
|
622
|
-
): Promise<BackendResult<{ sessionId: string; closed: true }, SessionNotFoundError>> {
|
|
637
|
+
public async closeSession(input: {
|
|
638
|
+
sessionId: string;
|
|
639
|
+
}): Promise<BackendResult<{ sessionId: string; closed: true }, SessionNotFoundError>> {
|
|
623
640
|
return this.runtimeService.closeSession(input);
|
|
624
641
|
}
|
|
625
642
|
|
|
626
|
-
public getEvents(
|
|
643
|
+
public getEvents(
|
|
644
|
+
input: GetEventsInput,
|
|
645
|
+
): BackendResult<GetEventsSnapshot, SessionNotFoundError | EventCursorInvalidError> {
|
|
627
646
|
return this.eventService.getEvents(input);
|
|
628
647
|
}
|
|
629
648
|
|
|
630
|
-
public getJob(
|
|
649
|
+
public getJob(
|
|
650
|
+
input: GetJobInput,
|
|
651
|
+
): BackendResult<BackendJobSnapshot, SessionNotFoundError | BackendJobNotFoundError> {
|
|
631
652
|
return this.jobService.getJob(input);
|
|
632
653
|
}
|
|
633
654
|
|
|
@@ -635,7 +656,12 @@ export class BackendRuntime {
|
|
|
635
656
|
return this.jobService.listJobs(input);
|
|
636
657
|
}
|
|
637
658
|
|
|
638
|
-
public cancelJob(
|
|
659
|
+
public cancelJob(
|
|
660
|
+
input: CancelJobInput,
|
|
661
|
+
): BackendResult<
|
|
662
|
+
BackendJobSnapshot,
|
|
663
|
+
SessionNotFoundError | BackendJobNotFoundError | BackendJobNotCancellableError
|
|
664
|
+
> {
|
|
639
665
|
return this.jobService.cancelJob(input);
|
|
640
666
|
}
|
|
641
667
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ProjectWriter, type FileSystem } from '@openfairygui/core/project-io';
|
|
2
|
+
import { materializeUamProject } from '@openfairygui/core/uam';
|
|
3
|
+
import { applyUamTransactionApp, type ApplyUamTransactionAppError } from '@openfairygui/functions/uam';
|
|
3
4
|
import type { CacheService } from './cache-service.js';
|
|
4
5
|
import { failure, success, type BackendContext } from './context.js';
|
|
5
6
|
import type { EventService } from './event-service.js';
|
|
@@ -20,7 +21,7 @@ function createWriterFileSystem(
|
|
|
20
21
|
fileSystem: BackendFileSystem,
|
|
21
22
|
committedPaths: string[],
|
|
22
23
|
failedPaths: string[],
|
|
23
|
-
):
|
|
24
|
+
): FileSystem {
|
|
24
25
|
async function trackWrite<T>(targetPath: string, fn: () => Promise<T>): Promise<T> {
|
|
25
26
|
try {
|
|
26
27
|
const result = await fn();
|
|
@@ -83,18 +84,34 @@ export class AuthoringService {
|
|
|
83
84
|
|
|
84
85
|
public async applyTransaction(
|
|
85
86
|
input: ApplySessionTransactionInput,
|
|
86
|
-
): Promise<
|
|
87
|
+
): Promise<
|
|
88
|
+
BackendResult<
|
|
89
|
+
BackendSessionSnapshot,
|
|
90
|
+
SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError
|
|
91
|
+
>
|
|
92
|
+
> {
|
|
87
93
|
const startedAt = Date.now();
|
|
88
94
|
const session = this.context.sessions.get(input.sessionId);
|
|
89
95
|
if (!session || session.closed) {
|
|
90
96
|
return failure('authoring', startedAt, createSessionNotFoundError(input.sessionId));
|
|
91
97
|
}
|
|
92
98
|
if (input.expectedRevision !== session.revision) {
|
|
93
|
-
this.eventService.emit({
|
|
94
|
-
|
|
99
|
+
this.eventService.emit({
|
|
100
|
+
kind: 'transaction.rejected',
|
|
95
101
|
sessionId: session.sessionId,
|
|
102
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
96
103
|
revision: session.revision,
|
|
97
104
|
});
|
|
105
|
+
return failure(
|
|
106
|
+
'authoring',
|
|
107
|
+
startedAt,
|
|
108
|
+
createStaleWriteError(session, input.expectedRevision),
|
|
109
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
110
|
+
{
|
|
111
|
+
sessionId: session.sessionId,
|
|
112
|
+
revision: session.revision,
|
|
113
|
+
},
|
|
114
|
+
);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
const result = applyUamTransactionApp({
|
|
@@ -102,19 +119,47 @@ export class AuthoringService {
|
|
|
102
119
|
operations: input.operations,
|
|
103
120
|
});
|
|
104
121
|
if (result.ok === false) {
|
|
105
|
-
this.eventService.emit({
|
|
106
|
-
|
|
122
|
+
this.eventService.emit({
|
|
123
|
+
kind: 'transaction.rejected',
|
|
107
124
|
sessionId: session.sessionId,
|
|
125
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
108
126
|
revision: session.revision,
|
|
127
|
+
diagnostics:
|
|
128
|
+
result.error.issues?.map((issue) => ({
|
|
129
|
+
code: result.error.code,
|
|
130
|
+
message: issue.message,
|
|
131
|
+
severity: 'error' as const,
|
|
132
|
+
})) ?? [],
|
|
109
133
|
});
|
|
134
|
+
return failure(
|
|
135
|
+
'authoring',
|
|
136
|
+
startedAt,
|
|
137
|
+
result.error,
|
|
138
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
139
|
+
{
|
|
140
|
+
sessionId: session.sessionId,
|
|
141
|
+
revision: session.revision,
|
|
142
|
+
},
|
|
143
|
+
);
|
|
110
144
|
}
|
|
111
145
|
|
|
112
146
|
session.project = result.project;
|
|
113
147
|
session.revision += 1;
|
|
114
148
|
session.dirty = true;
|
|
115
149
|
const cacheEntry = this.cacheService.invalidateSession(session);
|
|
116
|
-
this.eventService.emit({
|
|
117
|
-
|
|
150
|
+
this.eventService.emit({
|
|
151
|
+
kind: 'transaction.applied',
|
|
152
|
+
sessionId: session.sessionId,
|
|
153
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
154
|
+
revision: session.revision,
|
|
155
|
+
});
|
|
156
|
+
this.eventService.emit({
|
|
157
|
+
kind: 'cache.invalidated',
|
|
158
|
+
sessionId: session.sessionId,
|
|
159
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
160
|
+
revision: session.revision,
|
|
161
|
+
cacheRevision: cacheEntry.revision,
|
|
162
|
+
});
|
|
118
163
|
|
|
119
164
|
return success('authoring', startedAt, toSessionSnapshot(session, this.context.capabilities), {
|
|
120
165
|
sessionId: session.sessionId,
|
|
@@ -122,38 +167,67 @@ export class AuthoringService {
|
|
|
122
167
|
});
|
|
123
168
|
}
|
|
124
169
|
|
|
125
|
-
public async saveSession(
|
|
126
|
-
|
|
127
|
-
|
|
170
|
+
public async saveSession(input: {
|
|
171
|
+
sessionId: string;
|
|
172
|
+
expectedRevision?: number;
|
|
173
|
+
targetPath?: string;
|
|
174
|
+
}): Promise<
|
|
175
|
+
BackendResult<
|
|
176
|
+
BackendSessionSnapshot,
|
|
177
|
+
| SessionNotFoundError
|
|
178
|
+
| SessionStaleWriteError
|
|
179
|
+
| SavePartialFailureError
|
|
180
|
+
| PathPolicyViolationError
|
|
181
|
+
| BackendCapabilityUnavailableError
|
|
182
|
+
>
|
|
183
|
+
> {
|
|
128
184
|
const startedAt = Date.now();
|
|
129
185
|
const session = this.context.sessions.get(input.sessionId);
|
|
130
186
|
if (!session || session.closed) {
|
|
131
187
|
return failure('authoring', startedAt, createSessionNotFoundError(input.sessionId));
|
|
132
188
|
}
|
|
133
189
|
if (!this.context.fileSystem) {
|
|
134
|
-
return failure(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
190
|
+
return failure(
|
|
191
|
+
'authoring',
|
|
192
|
+
startedAt,
|
|
193
|
+
{
|
|
194
|
+
code: 'capability_unavailable',
|
|
195
|
+
message: 'saveSession requires an injected BackendFileSystem adapter.',
|
|
196
|
+
capability: 'fileSystem',
|
|
197
|
+
requiredAdapter: 'BackendFileSystem',
|
|
198
|
+
},
|
|
199
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
200
|
+
{
|
|
201
|
+
sessionId: session.sessionId,
|
|
202
|
+
revision: session.revision,
|
|
203
|
+
},
|
|
204
|
+
);
|
|
143
205
|
}
|
|
144
206
|
if (input.expectedRevision !== undefined && input.expectedRevision !== session.revision) {
|
|
145
|
-
return failure(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
207
|
+
return failure(
|
|
208
|
+
'authoring',
|
|
209
|
+
startedAt,
|
|
210
|
+
createStaleWriteError(session, input.expectedRevision),
|
|
211
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
212
|
+
{
|
|
213
|
+
sessionId: session.sessionId,
|
|
214
|
+
revision: session.revision,
|
|
215
|
+
},
|
|
216
|
+
);
|
|
149
217
|
}
|
|
150
218
|
const fileSystem = this.context.fileSystem;
|
|
151
219
|
const targetViolation = await validateSaveTarget(fileSystem, session.fairyPath, input.targetPath);
|
|
152
220
|
if (targetViolation) {
|
|
153
|
-
return failure(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
221
|
+
return failure(
|
|
222
|
+
'authoring',
|
|
223
|
+
startedAt,
|
|
224
|
+
targetViolation,
|
|
225
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
226
|
+
{
|
|
227
|
+
sessionId: session.sessionId,
|
|
228
|
+
revision: session.revision,
|
|
229
|
+
},
|
|
230
|
+
);
|
|
157
231
|
}
|
|
158
232
|
if (!session.dirty) {
|
|
159
233
|
return success('authoring', startedAt, toSessionSnapshot(session, this.context.capabilities), {
|
|
@@ -164,36 +238,63 @@ export class AuthoringService {
|
|
|
164
238
|
|
|
165
239
|
const committedPaths: string[] = [];
|
|
166
240
|
const failedPaths: string[] = [];
|
|
167
|
-
this.eventService.emit({
|
|
241
|
+
this.eventService.emit({
|
|
242
|
+
kind: 'save.started',
|
|
243
|
+
sessionId: session.sessionId,
|
|
244
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
245
|
+
revision: session.revision,
|
|
246
|
+
});
|
|
168
247
|
try {
|
|
169
248
|
const writer = new ProjectWriter(createWriterFileSystem(fileSystem, committedPaths, failedPaths));
|
|
170
249
|
await writer.write(materializeUamProject(session.project), session.fairyPath);
|
|
171
250
|
session.lastSavedRevision = session.revision;
|
|
172
251
|
session.dirty = false;
|
|
173
252
|
const cacheEntry = this.cacheService.refreshSession(session);
|
|
174
|
-
this.eventService.emit({
|
|
175
|
-
|
|
253
|
+
this.eventService.emit({
|
|
254
|
+
kind: 'save.completed',
|
|
255
|
+
sessionId: session.sessionId,
|
|
256
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
257
|
+
revision: session.revision,
|
|
258
|
+
});
|
|
259
|
+
this.eventService.emit({
|
|
260
|
+
kind: 'cache.updated',
|
|
261
|
+
sessionId: session.sessionId,
|
|
262
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
263
|
+
revision: session.revision,
|
|
264
|
+
cacheRevision: cacheEntry.revision,
|
|
265
|
+
});
|
|
176
266
|
return success('authoring', startedAt, toSessionSnapshot(session, this.context.capabilities), {
|
|
177
267
|
sessionId: session.sessionId,
|
|
178
268
|
revision: session.revision,
|
|
179
269
|
});
|
|
180
270
|
} catch (error) {
|
|
181
271
|
this.cacheService.invalidateSession(session);
|
|
182
|
-
this.eventService.emit({
|
|
183
|
-
|
|
184
|
-
code: 'save_partial_failure',
|
|
185
|
-
message: error instanceof Error ? error.message : String(error),
|
|
272
|
+
this.eventService.emit({
|
|
273
|
+
kind: 'save.failed',
|
|
186
274
|
sessionId: session.sessionId,
|
|
187
275
|
canonicalPathKey: session.canonicalPathKey,
|
|
188
|
-
attemptedRevision: session.revision,
|
|
189
|
-
lastSavedRevision: session.lastSavedRevision,
|
|
190
|
-
committedPaths,
|
|
191
|
-
failedPaths,
|
|
192
|
-
diskMayBePartiallyUpdated: true,
|
|
193
|
-
}, toSessionSnapshot(session, this.context.capabilities), {
|
|
194
|
-
sessionId: session.sessionId,
|
|
195
276
|
revision: session.revision,
|
|
196
277
|
});
|
|
278
|
+
return failure(
|
|
279
|
+
'authoring',
|
|
280
|
+
startedAt,
|
|
281
|
+
{
|
|
282
|
+
code: 'save_partial_failure',
|
|
283
|
+
message: error instanceof Error ? error.message : String(error),
|
|
284
|
+
sessionId: session.sessionId,
|
|
285
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
286
|
+
attemptedRevision: session.revision,
|
|
287
|
+
lastSavedRevision: session.lastSavedRevision,
|
|
288
|
+
committedPaths,
|
|
289
|
+
failedPaths,
|
|
290
|
+
diskMayBePartiallyUpdated: true,
|
|
291
|
+
},
|
|
292
|
+
toSessionSnapshot(session, this.context.capabilities),
|
|
293
|
+
{
|
|
294
|
+
sessionId: session.sessionId,
|
|
295
|
+
revision: session.revision,
|
|
296
|
+
},
|
|
297
|
+
);
|
|
197
298
|
}
|
|
198
299
|
}
|
|
199
300
|
}
|
package/src/services/context.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface BackendSessionState {
|
|
|
25
25
|
canonicalProjectPath: string;
|
|
26
26
|
canonicalPathKey: string;
|
|
27
27
|
lockFilePath: string;
|
|
28
|
-
project: import('@openfairygui/core').UamProject;
|
|
28
|
+
project: import('@openfairygui/core/uam').UamProject;
|
|
29
29
|
revision: number;
|
|
30
30
|
lastSavedRevision: number;
|
|
31
31
|
dirty: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ProjectReader,
|
|
1
|
+
import { ProjectReader, type FileSystem } from '@openfairygui/core/project-io';
|
|
2
|
+
import { liftDocumentToUamProject, normalizeUamProject } from '@openfairygui/core/uam';
|
|
2
3
|
import { failure, success, type BackendContext, type BackendSessionState } from './context.js';
|
|
3
4
|
import type { CacheService } from './cache-service.js';
|
|
4
5
|
import type { EventService } from './event-service.js';
|
|
@@ -20,7 +21,9 @@ function randomId(): string {
|
|
|
20
21
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
function createCapabilityUnavailableError(
|
|
24
|
+
function createCapabilityUnavailableError(
|
|
25
|
+
capability: BackendCapabilityUnavailableError['capability'],
|
|
26
|
+
): BackendCapabilityUnavailableError {
|
|
24
27
|
const artifactCapability = capability === 'artifact.publish' || capability === 'artifact.restore';
|
|
25
28
|
return {
|
|
26
29
|
code: 'capability_unavailable',
|
|
@@ -34,7 +37,7 @@ function createCapabilityUnavailableError(capability: BackendCapabilityUnavailab
|
|
|
34
37
|
};
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
function createProjectReaderFileSystem(fileSystem: NonNullable<BackendContext['fileSystem']>):
|
|
40
|
+
function createProjectReaderFileSystem(fileSystem: NonNullable<BackendContext['fileSystem']>): FileSystem {
|
|
38
41
|
return {
|
|
39
42
|
readFile(filePath: string): Promise<string> {
|
|
40
43
|
return fileSystem.readFile(filePath);
|
|
@@ -79,7 +82,14 @@ export class RuntimeService {
|
|
|
79
82
|
private readonly jobService: JobService,
|
|
80
83
|
) {}
|
|
81
84
|
|
|
82
|
-
public async openSession(input: {
|
|
85
|
+
public async openSession(input: {
|
|
86
|
+
projectPath: string;
|
|
87
|
+
}): Promise<
|
|
88
|
+
BackendResult<
|
|
89
|
+
BackendSessionSnapshot,
|
|
90
|
+
InProcessLockConflictError | AdvisoryLockConflictError | BackendCapabilityUnavailableError
|
|
91
|
+
>
|
|
92
|
+
> {
|
|
83
93
|
const startedAt = Date.now();
|
|
84
94
|
if (!this.context.fileSystem) {
|
|
85
95
|
return failure('runtime', startedAt, createCapabilityUnavailableError('fileSystem'));
|
|
@@ -104,14 +114,18 @@ export class RuntimeService {
|
|
|
104
114
|
let advisoryLock: BackendFileHandle | null = null;
|
|
105
115
|
try {
|
|
106
116
|
advisoryLock = await fileSystem.openExclusive(lockFilePath);
|
|
107
|
-
await advisoryLock.writeFile(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
await advisoryLock.writeFile(
|
|
118
|
+
JSON.stringify(
|
|
119
|
+
this.context.host?.lockMetadata?.({
|
|
120
|
+
canonicalPathKey,
|
|
121
|
+
canonicalProjectPath,
|
|
122
|
+
lockFilePath,
|
|
123
|
+
}) ?? {
|
|
124
|
+
createdAt: new Date().toISOString(),
|
|
125
|
+
canonicalPathKey,
|
|
126
|
+
},
|
|
127
|
+
),
|
|
128
|
+
);
|
|
115
129
|
await advisoryLock.close();
|
|
116
130
|
|
|
117
131
|
const reader = new ProjectReader(createProjectReaderFileSystem(fileSystem));
|
|
@@ -197,16 +211,21 @@ export class RuntimeService {
|
|
|
197
211
|
});
|
|
198
212
|
}
|
|
199
213
|
|
|
200
|
-
public async closeSession(
|
|
201
|
-
|
|
202
|
-
): Promise<BackendResult<{ sessionId: string; closed: true }, SessionNotFoundError>> {
|
|
214
|
+
public async closeSession(input: {
|
|
215
|
+
sessionId: string;
|
|
216
|
+
}): Promise<BackendResult<{ sessionId: string; closed: true }, SessionNotFoundError>> {
|
|
203
217
|
const startedAt = Date.now();
|
|
204
218
|
const session = this.context.sessions.get(input.sessionId);
|
|
205
219
|
if (!session || session.closed) {
|
|
206
220
|
return failure('runtime', startedAt, createSessionNotFoundError(input.sessionId));
|
|
207
221
|
}
|
|
208
222
|
|
|
209
|
-
this.eventService.emit({
|
|
223
|
+
this.eventService.emit({
|
|
224
|
+
kind: 'session.closeRequested',
|
|
225
|
+
sessionId: session.sessionId,
|
|
226
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
227
|
+
revision: session.revision,
|
|
228
|
+
});
|
|
210
229
|
if (this.context.fileSystem && session.lockFilePath) {
|
|
211
230
|
await this.context.fileSystem.unlink(session.lockFilePath).catch(() => undefined);
|
|
212
231
|
}
|
|
@@ -216,12 +235,22 @@ export class RuntimeService {
|
|
|
216
235
|
this.context.sessionsByPath.delete(session.canonicalPathKey);
|
|
217
236
|
this.cacheService.removeSession(session.sessionId);
|
|
218
237
|
this.jobService.removeSession(session.sessionId);
|
|
219
|
-
this.eventService.emit({
|
|
238
|
+
this.eventService.emit({
|
|
239
|
+
kind: 'session.closed',
|
|
240
|
+
sessionId: session.sessionId,
|
|
241
|
+
canonicalPathKey: session.canonicalPathKey,
|
|
242
|
+
revision: session.revision,
|
|
243
|
+
});
|
|
220
244
|
this.eventService.removeSession(session.sessionId);
|
|
221
245
|
|
|
222
|
-
return success(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
246
|
+
return success(
|
|
247
|
+
'runtime',
|
|
248
|
+
startedAt,
|
|
249
|
+
{
|
|
250
|
+
sessionId: session.sessionId,
|
|
251
|
+
closed: true,
|
|
252
|
+
},
|
|
253
|
+
{ sessionId: session.sessionId, revision: session.revision },
|
|
254
|
+
);
|
|
226
255
|
}
|
|
227
256
|
}
|