@openfairygui/backend 0.2.0-alpha.13 → 0.2.0-alpha.15
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 +9 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- 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-GyNVxAQ0.d.mts → runtime-B6UjcyIt.d.cts} +11 -4
- package/dist/{runtime-Jec6FcF5.d.cts → runtime-BihiQW-H.d.mts} +11 -4
- package/dist/{runtime-GKzsXJdO.cjs → runtime-C5N7GLsG.cjs} +159 -4
- package/dist/{runtime-DFatY9W0.mjs → runtime-CxH7aT_v.mjs} +160 -5
- package/package.json +3 -3
- package/src/index.ts +17 -16
- package/src/runtime.ts +17 -2
- package/src/services/authoring-service.ts +201 -41
- package/src/services/context.ts +11 -8
- package/src/services/runtime-service.ts +103 -15
- package/src/services/session-utils.ts +5 -1
- package/src/storage.ts +5 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UAM_SUPPORTED_MATERIALIZATION_SCOPE, UAM_SUPPORTED_TRANSACTION_SCOPE, liftDocumentToUamProject, materializeUamProject, normalizeUamProject, validateUamProject } from "@openfairygui/core/uam";
|
|
1
|
+
import { UAM_SUPPORTED_MATERIALIZATION_SCOPE, UAM_SUPPORTED_TRANSACTION_SCOPE, commitUamProjectSourcePaths, liftDocumentToUamProject, materializeUamProject, normalizeUamProject, validateUamProject } from "@openfairygui/core/uam";
|
|
2
2
|
import { ProjectReader, ProjectWriter } from "@openfairygui/core/project-io";
|
|
3
3
|
import { applyUamTransactionApp } from "@openfairygui/functions/uam";
|
|
4
4
|
//#region src/contracts.ts
|
|
@@ -179,6 +179,7 @@ function toSessionSnapshot(session, capabilities) {
|
|
|
179
179
|
revision: session.revision,
|
|
180
180
|
lastSavedRevision: session.lastSavedRevision,
|
|
181
181
|
dirty: session.dirty,
|
|
182
|
+
uamFidelity: session.uamFidelity,
|
|
182
183
|
lockHeld: session.lockHeld,
|
|
183
184
|
capabilities: cloneCapabilitiesSnapshot(capabilities)
|
|
184
185
|
};
|
|
@@ -251,9 +252,45 @@ function createWriterFileSystem(fileSystem, committedPaths, failedPaths) {
|
|
|
251
252
|
},
|
|
252
253
|
dirname(filePath) {
|
|
253
254
|
return fileSystem.dirname(filePath);
|
|
255
|
+
},
|
|
256
|
+
async unlink(filePath) {
|
|
257
|
+
await trackWrite(filePath, () => fileSystem.unlink(filePath));
|
|
254
258
|
}
|
|
255
259
|
};
|
|
256
260
|
}
|
|
261
|
+
function projectAssetSourceFiles(project) {
|
|
262
|
+
const result = /* @__PURE__ */ new Map();
|
|
263
|
+
for (const pkg of project.packages) for (const resource of pkg.resources) {
|
|
264
|
+
if (resource.kind === "component") continue;
|
|
265
|
+
const fileName = resource.fileName ?? resource.file ?? "";
|
|
266
|
+
if (!fileName) continue;
|
|
267
|
+
result.set(`${pkg.id}/${resource.id}`, {
|
|
268
|
+
packageName: pkg.name,
|
|
269
|
+
branch: resource.branch,
|
|
270
|
+
path: resource.path,
|
|
271
|
+
fileName
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
function sourceFileKey(source) {
|
|
277
|
+
return [
|
|
278
|
+
source.branch,
|
|
279
|
+
source.packageName,
|
|
280
|
+
source.path,
|
|
281
|
+
source.fileName
|
|
282
|
+
].join("\0");
|
|
283
|
+
}
|
|
284
|
+
function recordStaleResourceSources(session, previousProject, nextProject) {
|
|
285
|
+
if (!session.fileSystem) return;
|
|
286
|
+
const previousSources = projectAssetSourceFiles(previousProject);
|
|
287
|
+
const nextSourceKeys = new Set([...projectAssetSourceFiles(nextProject).values()].map(sourceFileKey));
|
|
288
|
+
for (const source of previousSources.values()) {
|
|
289
|
+
const key = sourceFileKey(source);
|
|
290
|
+
if (!nextSourceKeys.has(key)) session.pendingStaleSourceFiles.set(key, source);
|
|
291
|
+
}
|
|
292
|
+
for (const key of nextSourceKeys) session.pendingStaleSourceFiles.delete(key);
|
|
293
|
+
}
|
|
257
294
|
function toBackendDiagnostics(error) {
|
|
258
295
|
return error.diagnostics.length > 0 ? error.diagnostics.map((diagnostic) => ({ ...diagnostic })) : [{
|
|
259
296
|
code: error.code,
|
|
@@ -272,6 +309,14 @@ function createCapabilityUnavailableError$1(message) {
|
|
|
272
309
|
requiredAdapter: "BackendFileSystem"
|
|
273
310
|
};
|
|
274
311
|
}
|
|
312
|
+
function createUamFidelityUnsupportedError(session) {
|
|
313
|
+
return {
|
|
314
|
+
code: "uam_fidelity_unsupported",
|
|
315
|
+
message: "The source project contains formal properties that the current UAM cannot preserve.",
|
|
316
|
+
sessionId: session.sessionId,
|
|
317
|
+
canonicalPathKey: session.canonicalPathKey
|
|
318
|
+
};
|
|
319
|
+
}
|
|
275
320
|
function validationDiagnostics(sessionProject) {
|
|
276
321
|
return validateUamProject(sessionProject).map((issue) => ({
|
|
277
322
|
code: "materialize_validation_failed",
|
|
@@ -303,12 +348,32 @@ function storageCanonicalTarget(input) {
|
|
|
303
348
|
};
|
|
304
349
|
}
|
|
305
350
|
var AuthoringService = class {
|
|
351
|
+
sessionOperations = /* @__PURE__ */ new Map();
|
|
306
352
|
constructor(context, cacheService, eventService) {
|
|
307
353
|
this.context = context;
|
|
308
354
|
this.cacheService = cacheService;
|
|
309
355
|
this.eventService = eventService;
|
|
310
356
|
}
|
|
357
|
+
async runSessionExclusive(sessionId, operation) {
|
|
358
|
+
const previous = this.sessionOperations.get(sessionId) ?? Promise.resolve();
|
|
359
|
+
let release = () => void 0;
|
|
360
|
+
const current = new Promise((resolve) => {
|
|
361
|
+
release = resolve;
|
|
362
|
+
});
|
|
363
|
+
const tail = previous.then(() => current);
|
|
364
|
+
this.sessionOperations.set(sessionId, tail);
|
|
365
|
+
await previous;
|
|
366
|
+
try {
|
|
367
|
+
return await operation();
|
|
368
|
+
} finally {
|
|
369
|
+
release();
|
|
370
|
+
if (this.sessionOperations.get(sessionId) === tail) this.sessionOperations.delete(sessionId);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
311
373
|
async applyTransaction(input) {
|
|
374
|
+
return this.runSessionExclusive(input.sessionId, () => this.applyTransactionExclusive(input));
|
|
375
|
+
}
|
|
376
|
+
async applyTransactionExclusive(input) {
|
|
312
377
|
const startedAt = Date.now();
|
|
313
378
|
const session = this.context.sessions.get(input.sessionId);
|
|
314
379
|
if (!session || session.closed) return failure("authoring", startedAt, createSessionNotFoundError(input.sessionId));
|
|
@@ -343,6 +408,7 @@ var AuthoringService = class {
|
|
|
343
408
|
diagnostics
|
|
344
409
|
});
|
|
345
410
|
}
|
|
411
|
+
recordStaleResourceSources(session, session.project, result.project);
|
|
346
412
|
session.project = result.project;
|
|
347
413
|
session.revision += 1;
|
|
348
414
|
session.dirty = true;
|
|
@@ -374,10 +440,13 @@ var AuthoringService = class {
|
|
|
374
440
|
mode: "fullProject",
|
|
375
441
|
reason: "force_save"
|
|
376
442
|
});
|
|
443
|
+
return this.runSessionExclusive(input.sessionId, () => this.saveSessionExclusive(input));
|
|
444
|
+
}
|
|
445
|
+
async saveSessionExclusive(input) {
|
|
377
446
|
const startedAt = Date.now();
|
|
378
447
|
const session = this.context.sessions.get(input.sessionId);
|
|
379
448
|
if (!session || session.closed) return failure("authoring", startedAt, createSessionNotFoundError(input.sessionId));
|
|
380
|
-
const fileSystem =
|
|
449
|
+
const fileSystem = session.fileSystem ?? input.fileSystem ?? this.context.fileSystem;
|
|
381
450
|
if (!fileSystem) return failure("authoring", startedAt, createCapabilityUnavailableError$1("saveSession requires an injected BackendFileSystem adapter."), toSessionSnapshot(session, this.context.capabilities), {
|
|
382
451
|
sessionId: session.sessionId,
|
|
383
452
|
revision: session.revision
|
|
@@ -395,6 +464,10 @@ var AuthoringService = class {
|
|
|
395
464
|
sessionId: session.sessionId,
|
|
396
465
|
revision: session.revision
|
|
397
466
|
});
|
|
467
|
+
if (session.uamFidelity === "unsupported") return failure("authoring", startedAt, createUamFidelityUnsupportedError(session), toSessionSnapshot(session, this.context.capabilities), {
|
|
468
|
+
sessionId: session.sessionId,
|
|
469
|
+
revision: session.revision
|
|
470
|
+
});
|
|
398
471
|
const committedPaths = [];
|
|
399
472
|
const failedPaths = [];
|
|
400
473
|
this.eventService.emit({
|
|
@@ -404,7 +477,10 @@ var AuthoringService = class {
|
|
|
404
477
|
revision: session.revision
|
|
405
478
|
});
|
|
406
479
|
try {
|
|
407
|
-
await new ProjectWriter(createWriterFileSystem(fileSystem, committedPaths, failedPaths)).write(materializeUamProject(session.project), session.fairyPath);
|
|
480
|
+
await new ProjectWriter(createWriterFileSystem(fileSystem, committedPaths, failedPaths)).write(materializeUamProject(session.project), session.fairyPath, { staleSourceFiles: [...session.pendingStaleSourceFiles.values()] });
|
|
481
|
+
session.fileSystem ??= fileSystem;
|
|
482
|
+
session.pendingStaleSourceFiles.clear();
|
|
483
|
+
commitUamProjectSourcePaths(session.project);
|
|
408
484
|
session.lastSavedRevision = session.revision;
|
|
409
485
|
session.dirty = false;
|
|
410
486
|
const cacheEntry = this.cacheService.refreshSession(session);
|
|
@@ -450,6 +526,9 @@ var AuthoringService = class {
|
|
|
450
526
|
}
|
|
451
527
|
}
|
|
452
528
|
async materializeSession(input) {
|
|
529
|
+
return this.runSessionExclusive(input.sessionId, () => this.materializeSessionExclusive(input));
|
|
530
|
+
}
|
|
531
|
+
async materializeSessionExclusive(input) {
|
|
453
532
|
const startedAt = Date.now();
|
|
454
533
|
const session = this.context.sessions.get(input.sessionId);
|
|
455
534
|
if (!session || session.closed) return failure("authoring", startedAt, createSessionNotFoundError(input.sessionId));
|
|
@@ -482,6 +561,10 @@ var AuthoringService = class {
|
|
|
482
561
|
revision: session.revision
|
|
483
562
|
});
|
|
484
563
|
}
|
|
564
|
+
if (session.uamFidelity === "unsupported") return failure("authoring", startedAt, createUamFidelityUnsupportedError(session), toSessionSnapshot(session, this.context.capabilities), {
|
|
565
|
+
sessionId: session.sessionId,
|
|
566
|
+
revision: session.revision
|
|
567
|
+
});
|
|
485
568
|
const diagnostics = validationDiagnostics(session.project);
|
|
486
569
|
if (diagnostics.length > 0) return failure("authoring", startedAt, {
|
|
487
570
|
code: "materialize_validation_failed",
|
|
@@ -528,7 +611,12 @@ var AuthoringService = class {
|
|
|
528
611
|
revision: session.revision
|
|
529
612
|
});
|
|
530
613
|
try {
|
|
531
|
-
|
|
614
|
+
const writer = new ProjectWriter(createWriterFileSystem(fileSystem, writtenPaths, failedPaths));
|
|
615
|
+
const isSessionStorageTarget = fileSystem === session.fileSystem && fairyPath === session.fairyPath;
|
|
616
|
+
await writer.write(document, fairyPath, { staleSourceFiles: isSessionStorageTarget ? [...session.pendingStaleSourceFiles.values()] : [] });
|
|
617
|
+
if (isSessionStorageTarget) session.pendingStaleSourceFiles.clear();
|
|
618
|
+
if (storageTarget && !isSessionStorageTarget) session.pendingStaleSourceFiles.clear();
|
|
619
|
+
if (isSessionStorageTarget || storageTarget) commitUamProjectSourcePaths(session.project);
|
|
532
620
|
if (storageTarget) {
|
|
533
621
|
this.context.sessionsByPath.delete(session.canonicalPathKey);
|
|
534
622
|
session.fileSystem = storageTarget.fileSystem;
|
|
@@ -1055,6 +1143,68 @@ function createProjectReaderFileSystem(fileSystem) {
|
|
|
1055
1143
|
}
|
|
1056
1144
|
};
|
|
1057
1145
|
}
|
|
1146
|
+
function createCaptureFileSystem(files) {
|
|
1147
|
+
const normalize = (filePath) => filePath.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
1148
|
+
return {
|
|
1149
|
+
async readFile(filePath) {
|
|
1150
|
+
const value = files.get(normalize(filePath));
|
|
1151
|
+
if (typeof value !== "string") throw new Error(`Captured text file was not found: ${filePath}`);
|
|
1152
|
+
return value;
|
|
1153
|
+
},
|
|
1154
|
+
async readFileRaw(filePath) {
|
|
1155
|
+
const value = files.get(normalize(filePath));
|
|
1156
|
+
if (!(value instanceof Uint8Array)) throw new Error(`Captured binary file was not found: ${filePath}`);
|
|
1157
|
+
return value.slice();
|
|
1158
|
+
},
|
|
1159
|
+
async writeFile(filePath, content) {
|
|
1160
|
+
files.set(normalize(filePath), content);
|
|
1161
|
+
},
|
|
1162
|
+
async writeFileRaw(filePath, data) {
|
|
1163
|
+
files.set(normalize(filePath), data.slice());
|
|
1164
|
+
},
|
|
1165
|
+
async mkdir() {},
|
|
1166
|
+
async readdir() {
|
|
1167
|
+
return [];
|
|
1168
|
+
},
|
|
1169
|
+
async exists(filePath) {
|
|
1170
|
+
return files.has(normalize(filePath));
|
|
1171
|
+
},
|
|
1172
|
+
join(...paths) {
|
|
1173
|
+
return normalize(paths.filter(Boolean).join("/"));
|
|
1174
|
+
},
|
|
1175
|
+
dirname(filePath) {
|
|
1176
|
+
const normalized = normalize(filePath);
|
|
1177
|
+
const separator = normalized.lastIndexOf("/");
|
|
1178
|
+
return separator < 0 ? "" : normalized.slice(0, separator);
|
|
1179
|
+
},
|
|
1180
|
+
async unlink(filePath) {
|
|
1181
|
+
files.delete(normalize(filePath));
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
function capturedFilesEqual(left, right) {
|
|
1186
|
+
if (left.size !== right.size) return false;
|
|
1187
|
+
for (const [filePath, leftValue] of left) {
|
|
1188
|
+
const rightValue = right.get(filePath);
|
|
1189
|
+
if (typeof leftValue === "string") {
|
|
1190
|
+
if (leftValue !== rightValue) return false;
|
|
1191
|
+
continue;
|
|
1192
|
+
}
|
|
1193
|
+
if (!(rightValue instanceof Uint8Array) || leftValue.length !== rightValue.length) return false;
|
|
1194
|
+
for (let index = 0; index < leftValue.length; index += 1) if (leftValue[index] !== rightValue[index]) return false;
|
|
1195
|
+
}
|
|
1196
|
+
return true;
|
|
1197
|
+
}
|
|
1198
|
+
async function hasFullUamFidelity(document, project) {
|
|
1199
|
+
const sourceFiles = /* @__PURE__ */ new Map();
|
|
1200
|
+
const materializedFiles = /* @__PURE__ */ new Map();
|
|
1201
|
+
try {
|
|
1202
|
+
await Promise.all([new ProjectWriter(createCaptureFileSystem(sourceFiles)).write(document, "Project.fairy"), new ProjectWriter(createCaptureFileSystem(materializedFiles)).write(materializeUamProject(project), "Project.fairy")]);
|
|
1203
|
+
} catch {
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1206
|
+
return capturedFilesEqual(sourceFiles, materializedFiles);
|
|
1207
|
+
}
|
|
1058
1208
|
var RuntimeService = class {
|
|
1059
1209
|
constructor(context, cacheService, eventService, jobService) {
|
|
1060
1210
|
this.context = context;
|
|
@@ -1089,7 +1239,8 @@ var RuntimeService = class {
|
|
|
1089
1239
|
canonicalPathKey
|
|
1090
1240
|
}));
|
|
1091
1241
|
await advisoryLock.close();
|
|
1092
|
-
const
|
|
1242
|
+
const document = await new ProjectReader(createProjectReaderFileSystem(fileSystem)).read(fairyPath, { hydrateResourceBytes: true });
|
|
1243
|
+
const project = liftDocumentToUamProject(document);
|
|
1093
1244
|
const sessionId = randomId();
|
|
1094
1245
|
const session = {
|
|
1095
1246
|
sessionId,
|
|
@@ -1099,8 +1250,10 @@ var RuntimeService = class {
|
|
|
1099
1250
|
lockFilePath,
|
|
1100
1251
|
fileSystem,
|
|
1101
1252
|
project,
|
|
1253
|
+
uamFidelity: await hasFullUamFidelity(document, project) ? "full" : "unsupported",
|
|
1102
1254
|
revision: 0,
|
|
1103
1255
|
lastSavedRevision: 0,
|
|
1256
|
+
pendingStaleSourceFiles: /* @__PURE__ */ new Map(),
|
|
1104
1257
|
dirty: false,
|
|
1105
1258
|
lockHeld: true,
|
|
1106
1259
|
closed: false
|
|
@@ -1156,8 +1309,10 @@ var RuntimeService = class {
|
|
|
1156
1309
|
lockFilePath: "",
|
|
1157
1310
|
fileSystem: storage?.fileSystem,
|
|
1158
1311
|
project: normalizeUamProject(input.project),
|
|
1312
|
+
uamFidelity: "full",
|
|
1159
1313
|
revision: 0,
|
|
1160
1314
|
lastSavedRevision: 0,
|
|
1315
|
+
pendingStaleSourceFiles: /* @__PURE__ */ new Map(),
|
|
1161
1316
|
dirty: false,
|
|
1162
1317
|
lockHeld: false,
|
|
1163
1318
|
closed: false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfairygui/backend",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.15",
|
|
4
4
|
"description": "FairyGUI Headless Authoring SDK — stateful backend runtime and session services.",
|
|
5
5
|
"author": "OpenFairyGUI Contributors",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"runtime"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@openfairygui/core": "0.2.0-alpha.
|
|
56
|
-
"@openfairygui/functions": "0.2.0-alpha.
|
|
55
|
+
"@openfairygui/core": "0.2.0-alpha.15",
|
|
56
|
+
"@openfairygui/functions": "0.2.0-alpha.15"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"ava": "^7.0.0",
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
export {
|
|
2
|
-
|
|
2
|
+
BACKEND_CAPABILITY_SCHEMA_VERSION,
|
|
3
|
+
BACKEND_COMPATIBILITY_POLICY,
|
|
4
|
+
BACKEND_CONTRACT_VERSION,
|
|
5
|
+
type BackendDiagnostic,
|
|
6
|
+
type BackendMessage,
|
|
7
|
+
type BackendResponseMeta,
|
|
8
|
+
type BackendStage,
|
|
9
|
+
} from './contracts.js';
|
|
10
|
+
export {
|
|
3
11
|
type AdvisoryLockConflictError,
|
|
4
12
|
type ApplySessionTransactionInput,
|
|
5
13
|
type BackendArtifactBridgeCapability,
|
|
6
14
|
type BackendCacheEntry,
|
|
7
15
|
type BackendCacheSnapshot,
|
|
16
|
+
type BackendCapabilities,
|
|
8
17
|
type BackendCapabilityManifest,
|
|
9
18
|
type BackendCapabilityUnavailableError,
|
|
10
|
-
type BackendCapabilities,
|
|
11
19
|
type BackendError,
|
|
12
20
|
type BackendEvent,
|
|
13
21
|
type BackendEventKind,
|
|
@@ -16,6 +24,7 @@ export {
|
|
|
16
24
|
type BackendFileStat,
|
|
17
25
|
type BackendFileSystem,
|
|
18
26
|
type BackendHostAdapter,
|
|
27
|
+
type BackendJobErrors,
|
|
19
28
|
type BackendJobKind,
|
|
20
29
|
type BackendJobListSnapshot,
|
|
21
30
|
type BackendJobListStatusFilter,
|
|
@@ -24,11 +33,12 @@ export {
|
|
|
24
33
|
type BackendJobProgress,
|
|
25
34
|
type BackendJobSnapshot,
|
|
26
35
|
type BackendJobStatus,
|
|
27
|
-
type
|
|
36
|
+
type BackendProjectSessionStorage,
|
|
28
37
|
type BackendResult,
|
|
38
|
+
BackendRuntime,
|
|
39
|
+
type BackendRuntimeOptions,
|
|
29
40
|
type BackendSessionSnapshot,
|
|
30
41
|
type BackendSuccess,
|
|
31
|
-
type BackendRuntimeOptions,
|
|
32
42
|
type CacheRefreshFailedError,
|
|
33
43
|
type CancelJobInput,
|
|
34
44
|
type EventCursorInvalidError,
|
|
@@ -43,25 +53,16 @@ export {
|
|
|
43
53
|
type MaterializeValidationFailedError,
|
|
44
54
|
type MaterializeWriteFailedError,
|
|
45
55
|
type OpenProjectSessionInput,
|
|
46
|
-
type BackendProjectSessionStorage,
|
|
47
56
|
type RefreshCacheInput,
|
|
48
|
-
type SaveSessionInput,
|
|
49
57
|
type SavePartialFailureError,
|
|
58
|
+
type SaveSessionInput,
|
|
50
59
|
type SessionNotFoundError,
|
|
51
60
|
type SessionStaleWriteError,
|
|
61
|
+
type UamFidelityUnsupportedError,
|
|
52
62
|
} from './runtime.js';
|
|
53
63
|
export {
|
|
54
|
-
createBackendStorageFileSystem,
|
|
55
64
|
type BackendAsyncStorageAdapter,
|
|
56
65
|
type BackendStorageFileSystem,
|
|
57
66
|
type BackendStorageStatLike,
|
|
67
|
+
createBackendStorageFileSystem,
|
|
58
68
|
} from './storage.js';
|
|
59
|
-
export {
|
|
60
|
-
type BackendDiagnostic,
|
|
61
|
-
type BackendMessage,
|
|
62
|
-
type BackendResponseMeta,
|
|
63
|
-
type BackendStage,
|
|
64
|
-
BACKEND_CAPABILITY_SCHEMA_VERSION,
|
|
65
|
-
BACKEND_COMPATIBILITY_POLICY,
|
|
66
|
-
BACKEND_CONTRACT_VERSION,
|
|
67
|
-
} from './contracts.js';
|
package/src/runtime.ts
CHANGED
|
@@ -181,6 +181,7 @@ export interface BackendSessionSnapshot {
|
|
|
181
181
|
revision: number;
|
|
182
182
|
lastSavedRevision: number;
|
|
183
183
|
dirty: boolean;
|
|
184
|
+
uamFidelity: 'full' | 'unsupported';
|
|
184
185
|
lockHeld: boolean;
|
|
185
186
|
capabilities: BackendCapabilities;
|
|
186
187
|
}
|
|
@@ -255,6 +256,13 @@ export interface SavePartialFailureError {
|
|
|
255
256
|
diskMayBePartiallyUpdated: true;
|
|
256
257
|
}
|
|
257
258
|
|
|
259
|
+
export interface UamFidelityUnsupportedError {
|
|
260
|
+
code: 'uam_fidelity_unsupported';
|
|
261
|
+
message: string;
|
|
262
|
+
sessionId: string;
|
|
263
|
+
canonicalPathKey: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
258
266
|
export interface MaterializeValidationFailedError {
|
|
259
267
|
code: 'materialize_validation_failed';
|
|
260
268
|
message: string;
|
|
@@ -458,6 +466,7 @@ export type BackendError =
|
|
|
458
466
|
| InProcessLockConflictError
|
|
459
467
|
| AdvisoryLockConflictError
|
|
460
468
|
| SavePartialFailureError
|
|
469
|
+
| UamFidelityUnsupportedError
|
|
461
470
|
| MaterializeValidationFailedError
|
|
462
471
|
| MaterializeWriteFailedError
|
|
463
472
|
| PathPolicyViolationError
|
|
@@ -704,12 +713,15 @@ export class BackendRuntime {
|
|
|
704
713
|
return this.authoringService.applyTransaction(input);
|
|
705
714
|
}
|
|
706
715
|
|
|
707
|
-
public async saveSession(
|
|
716
|
+
public async saveSession(
|
|
717
|
+
input: SaveSessionInput,
|
|
718
|
+
): Promise<
|
|
708
719
|
BackendResult<
|
|
709
720
|
BackendSessionSnapshot | MaterializeSessionSnapshot,
|
|
710
721
|
| SessionNotFoundError
|
|
711
722
|
| SessionStaleWriteError
|
|
712
723
|
| SavePartialFailureError
|
|
724
|
+
| UamFidelityUnsupportedError
|
|
713
725
|
| MaterializeValidationFailedError
|
|
714
726
|
| MaterializeWriteFailedError
|
|
715
727
|
| PathPolicyViolationError
|
|
@@ -720,11 +732,14 @@ export class BackendRuntime {
|
|
|
720
732
|
return this.authoringService.saveSession(input);
|
|
721
733
|
}
|
|
722
734
|
|
|
723
|
-
public async materializeSession(
|
|
735
|
+
public async materializeSession(
|
|
736
|
+
input: MaterializeSessionInput,
|
|
737
|
+
): Promise<
|
|
724
738
|
BackendResult<
|
|
725
739
|
MaterializeSessionSnapshot,
|
|
726
740
|
| SessionNotFoundError
|
|
727
741
|
| SessionStaleWriteError
|
|
742
|
+
| UamFidelityUnsupportedError
|
|
728
743
|
| MaterializeValidationFailedError
|
|
729
744
|
| MaterializeWriteFailedError
|
|
730
745
|
| PathPolicyViolationError
|