@openfairygui/backend 0.2.0-alpha.32 → 0.2.0-alpha.34

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/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_runtime = require("./runtime-DtcaaVfy.cjs");
2
+ const require_runtime = require("./runtime-CTA1SNix.cjs");
3
3
  //#region src/storage.ts
4
4
  var StorageFileStat = class {
5
5
  constructor(kind) {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-BDkZmTFN.mjs";
1
+ import { i as BACKEND_CONTRACT_VERSION, n as BACKEND_CAPABILITY_SCHEMA_VERSION, r as BACKEND_COMPATIBILITY_POLICY, t as BackendRuntime } from "./runtime-D8kpBZmu.mjs";
2
2
  //#region src/storage.ts
3
3
  var StorageFileStat = class {
4
4
  constructor(kind) {
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-DtcaaVfy.cjs");
24
+ const require_runtime = require("./runtime-CTA1SNix.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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as BackendRuntime } from "./runtime-BDkZmTFN.mjs";
1
+ import { t as BackendRuntime } from "./runtime-D8kpBZmu.mjs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  //#region src/node.ts
@@ -276,6 +276,17 @@ function storageCanonicalTarget(input) {
276
276
  canonicalPathKey: input.canonicalPathKey ?? normalizeComparablePath(canonicalProjectPath)
277
277
  };
278
278
  }
279
+ function detachSharedByteViews(value, seen = /* @__PURE__ */ new WeakSet()) {
280
+ if (!value || typeof value !== "object" || seen.has(value)) return;
281
+ seen.add(value);
282
+ for (const [key, child] of Object.entries(value)) {
283
+ if (child instanceof Uint8Array) {
284
+ if (typeof SharedArrayBuffer !== "undefined" && child.buffer instanceof SharedArrayBuffer) value[key] = new Uint8Array(child);
285
+ continue;
286
+ }
287
+ detachSharedByteViews(child, seen);
288
+ }
289
+ }
279
290
  var AuthoringService = class {
280
291
  sessionOperations = /* @__PURE__ */ new Map();
281
292
  constructor(context, cacheService, eventService) {
@@ -300,7 +311,9 @@ var AuthoringService = class {
300
311
  }
301
312
  }
302
313
  async applyTransaction(input) {
303
- return this.runSessionExclusive(input.sessionId, () => this.applyTransactionExclusive(input));
314
+ const queuedInput = structuredClone(input);
315
+ detachSharedByteViews(queuedInput);
316
+ return this.runSessionExclusive(queuedInput.sessionId, () => this.applyTransactionExclusive(queuedInput));
304
317
  }
305
318
  async applyTransactionExclusive(input) {
306
319
  const startedAt = Date.now();
@@ -318,10 +331,11 @@ var AuthoringService = class {
318
331
  revision: session.revision
319
332
  });
320
333
  }
321
- const result = (0, _openfairygui_functions_uam.applyUamTransactionApp)({
334
+ const result = await (0, _openfairygui_functions_uam.applyUamTransactionAppAsync)({
322
335
  project: session.project,
323
336
  operations: input.operations
324
337
  });
338
+ if (this.context.sessions.get(input.sessionId) !== session || session.closed) return failure("authoring", startedAt, createSessionNotFoundError(input.sessionId));
325
339
  if (result.ok === false) {
326
340
  const diagnostics = toBackendDiagnostics(result.error);
327
341
  this.eventService.emit({
@@ -1,5 +1,5 @@
1
1
  import { UAM_SUPPORTED_MATERIALIZATION_SCOPE, UAM_SUPPORTED_TRANSACTION_SCOPE, commitUamProjectSourcePaths, liftDocumentToUamProject, materializeUamProject, normalizeUamProject, staleResourceFolders, staleSourceFiles, validateUamProject } from "@openfairygui/core/uam";
2
- import { applyUamTransactionApp } from "@openfairygui/functions/uam";
2
+ import { applyUamTransactionAppAsync } from "@openfairygui/functions/uam";
3
3
  import { ProjectReader, ProjectWriter } from "@openfairygui/core/project-io";
4
4
  //#region src/contracts.ts
5
5
  const BACKEND_CONTRACT_VERSION = "1.1.0-p2";
@@ -275,6 +275,17 @@ function storageCanonicalTarget(input) {
275
275
  canonicalPathKey: input.canonicalPathKey ?? normalizeComparablePath(canonicalProjectPath)
276
276
  };
277
277
  }
278
+ function detachSharedByteViews(value, seen = /* @__PURE__ */ new WeakSet()) {
279
+ if (!value || typeof value !== "object" || seen.has(value)) return;
280
+ seen.add(value);
281
+ for (const [key, child] of Object.entries(value)) {
282
+ if (child instanceof Uint8Array) {
283
+ if (typeof SharedArrayBuffer !== "undefined" && child.buffer instanceof SharedArrayBuffer) value[key] = new Uint8Array(child);
284
+ continue;
285
+ }
286
+ detachSharedByteViews(child, seen);
287
+ }
288
+ }
278
289
  var AuthoringService = class {
279
290
  sessionOperations = /* @__PURE__ */ new Map();
280
291
  constructor(context, cacheService, eventService) {
@@ -299,7 +310,9 @@ var AuthoringService = class {
299
310
  }
300
311
  }
301
312
  async applyTransaction(input) {
302
- return this.runSessionExclusive(input.sessionId, () => this.applyTransactionExclusive(input));
313
+ const queuedInput = structuredClone(input);
314
+ detachSharedByteViews(queuedInput);
315
+ return this.runSessionExclusive(queuedInput.sessionId, () => this.applyTransactionExclusive(queuedInput));
303
316
  }
304
317
  async applyTransactionExclusive(input) {
305
318
  const startedAt = Date.now();
@@ -317,10 +330,11 @@ var AuthoringService = class {
317
330
  revision: session.revision
318
331
  });
319
332
  }
320
- const result = applyUamTransactionApp({
333
+ const result = await applyUamTransactionAppAsync({
321
334
  project: session.project,
322
335
  operations: input.operations
323
336
  });
337
+ if (this.context.sessions.get(input.sessionId) !== session || session.closed) return failure("authoring", startedAt, createSessionNotFoundError(input.sessionId));
324
338
  if (result.ok === false) {
325
339
  const diagnostics = toBackendDiagnostics(result.error);
326
340
  this.eventService.emit({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfairygui/backend",
3
- "version": "0.2.0-alpha.32",
3
+ "version": "0.2.0-alpha.34",
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.32",
56
- "@openfairygui/functions": "0.2.0-alpha.32"
55
+ "@openfairygui/core": "0.2.0-alpha.34",
56
+ "@openfairygui/functions": "0.2.0-alpha.34"
57
57
  },
58
58
  "devDependencies": {
59
59
  "ava": "^7.0.0",
@@ -7,7 +7,7 @@ import {
7
7
  type UamProject,
8
8
  validateUamProject,
9
9
  } from '@openfairygui/core/uam';
10
- import { type ApplyUamTransactionAppError, applyUamTransactionApp } from '@openfairygui/functions/uam';
10
+ import { type ApplyUamTransactionAppError, applyUamTransactionAppAsync } from '@openfairygui/functions/uam';
11
11
  import type { BackendDiagnostic } from '../contracts.js';
12
12
  import { normalizeComparablePath, type PathPolicyViolationError, validateSaveTarget } from '../path-policy.js';
13
13
  import type {
@@ -144,6 +144,20 @@ function storageCanonicalTarget(input: NonNullable<MaterializeSessionInput['stor
144
144
  };
145
145
  }
146
146
 
147
+ function detachSharedByteViews(value: unknown, seen = new WeakSet<object>()): void {
148
+ if (!value || typeof value !== 'object' || seen.has(value)) return;
149
+ seen.add(value);
150
+ for (const [key, child] of Object.entries(value)) {
151
+ if (child instanceof Uint8Array) {
152
+ if (typeof SharedArrayBuffer !== 'undefined' && child.buffer instanceof SharedArrayBuffer) {
153
+ (value as Record<string, unknown>)[key] = new Uint8Array(child);
154
+ }
155
+ continue;
156
+ }
157
+ detachSharedByteViews(child, seen);
158
+ }
159
+ }
160
+
147
161
  export class AuthoringService {
148
162
  private readonly sessionOperations = new Map<string, Promise<void>>();
149
163
 
@@ -178,7 +192,9 @@ export class AuthoringService {
178
192
  SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError
179
193
  >
180
194
  > {
181
- return this.runSessionExclusive(input.sessionId, () => this.applyTransactionExclusive(input));
195
+ const queuedInput = structuredClone(input);
196
+ detachSharedByteViews(queuedInput);
197
+ return this.runSessionExclusive(queuedInput.sessionId, () => this.applyTransactionExclusive(queuedInput));
182
198
  }
183
199
 
184
200
  private async applyTransactionExclusive(
@@ -213,10 +229,13 @@ export class AuthoringService {
213
229
  );
214
230
  }
215
231
 
216
- const result = applyUamTransactionApp({
232
+ const result = await applyUamTransactionAppAsync({
217
233
  project: session.project,
218
234
  operations: input.operations,
219
235
  });
236
+ if (this.context.sessions.get(input.sessionId) !== session || session.closed) {
237
+ return failure('authoring', startedAt, createSessionNotFoundError(input.sessionId));
238
+ }
220
239
  if (result.ok === false) {
221
240
  const diagnostics = toBackendDiagnostics(result.error);
222
241
  this.eventService.emit({