@skenora/editor 0.1.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.
Files changed (78) hide show
  1. package/README.md +51 -0
  2. package/dist/commands/annotation-commands.d.ts +12 -0
  3. package/dist/commands/annotation-commands.d.ts.map +1 -0
  4. package/dist/commands/annotation-commands.js +37 -0
  5. package/dist/commands/annotation-commands.js.map +1 -0
  6. package/dist/commands/camera-entity-commands.d.ts +12 -0
  7. package/dist/commands/camera-entity-commands.d.ts.map +1 -0
  8. package/dist/commands/camera-entity-commands.js +60 -0
  9. package/dist/commands/camera-entity-commands.js.map +1 -0
  10. package/dist/commands/camera-path-commands.d.ts +9 -0
  11. package/dist/commands/camera-path-commands.d.ts.map +1 -0
  12. package/dist/commands/camera-path-commands.js +95 -0
  13. package/dist/commands/camera-path-commands.js.map +1 -0
  14. package/dist/commands/flow-commands.d.ts +10 -0
  15. package/dist/commands/flow-commands.d.ts.map +1 -0
  16. package/dist/commands/flow-commands.js +86 -0
  17. package/dist/commands/flow-commands.js.map +1 -0
  18. package/dist/commands/geometry-commands.d.ts +8 -0
  19. package/dist/commands/geometry-commands.d.ts.map +1 -0
  20. package/dist/commands/geometry-commands.js +85 -0
  21. package/dist/commands/geometry-commands.js.map +1 -0
  22. package/dist/commands/material-assignment.d.ts +7 -0
  23. package/dist/commands/material-assignment.d.ts.map +1 -0
  24. package/dist/commands/material-assignment.js +69 -0
  25. package/dist/commands/material-assignment.js.map +1 -0
  26. package/dist/commands/material-commands.d.ts +13 -0
  27. package/dist/commands/material-commands.d.ts.map +1 -0
  28. package/dist/commands/material-commands.js +182 -0
  29. package/dist/commands/material-commands.js.map +1 -0
  30. package/dist/commands/model-import-commands.d.ts +6 -0
  31. package/dist/commands/model-import-commands.d.ts.map +1 -0
  32. package/dist/commands/model-import-commands.js +120 -0
  33. package/dist/commands/model-import-commands.js.map +1 -0
  34. package/dist/commands/particle-commands.d.ts +13 -0
  35. package/dist/commands/particle-commands.d.ts.map +1 -0
  36. package/dist/commands/particle-commands.js +47 -0
  37. package/dist/commands/particle-commands.js.map +1 -0
  38. package/dist/commands/primitive-commands.d.ts +18 -0
  39. package/dist/commands/primitive-commands.d.ts.map +1 -0
  40. package/dist/commands/primitive-commands.js +24 -0
  41. package/dist/commands/primitive-commands.js.map +1 -0
  42. package/dist/commands/procedural-commands.d.ts +13 -0
  43. package/dist/commands/procedural-commands.d.ts.map +1 -0
  44. package/dist/commands/procedural-commands.js +20 -0
  45. package/dist/commands/procedural-commands.js.map +1 -0
  46. package/dist/commands/scene-commands.d.ts +16 -0
  47. package/dist/commands/scene-commands.d.ts.map +1 -0
  48. package/dist/commands/scene-commands.js +146 -0
  49. package/dist/commands/scene-commands.js.map +1 -0
  50. package/dist/commands/shape-commands.d.ts +24 -0
  51. package/dist/commands/shape-commands.d.ts.map +1 -0
  52. package/dist/commands/shape-commands.js +95 -0
  53. package/dist/commands/shape-commands.js.map +1 -0
  54. package/dist/commands/texture-animation-commands.d.ts +5 -0
  55. package/dist/commands/texture-animation-commands.d.ts.map +1 -0
  56. package/dist/commands/texture-animation-commands.js +23 -0
  57. package/dist/commands/texture-animation-commands.js.map +1 -0
  58. package/dist/core/candidate-commit.d.ts +59 -0
  59. package/dist/core/candidate-commit.d.ts.map +1 -0
  60. package/dist/core/candidate-commit.js +54 -0
  61. package/dist/core/candidate-commit.js.map +1 -0
  62. package/dist/core/commands.d.ts +20 -0
  63. package/dist/core/commands.d.ts.map +1 -0
  64. package/dist/core/commands.js +282 -0
  65. package/dist/core/commands.js.map +1 -0
  66. package/dist/core/editor-session.d.ts +92 -0
  67. package/dist/core/editor-session.d.ts.map +1 -0
  68. package/dist/core/editor-session.js +496 -0
  69. package/dist/core/editor-session.js.map +1 -0
  70. package/dist/index.d.ts +18 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +18 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/properties/property-descriptors.d.ts +58 -0
  75. package/dist/properties/property-descriptors.d.ts.map +1 -0
  76. package/dist/properties/property-descriptors.js +832 -0
  77. package/dist/properties/property-descriptors.js.map +1 -0
  78. package/package.json +34 -0
@@ -0,0 +1,146 @@
1
+ import { toMaterialDefinition } from "@skenora/contracts";
2
+ import { createCommandId, setPropertyCommand, } from "../core/commands.js";
3
+ import { synchronizeMaterialBindings } from "./material-assignment.js";
4
+ export function upsertAssetCommand(asset) {
5
+ return setPropertyCommand(["assets", asset.id], asset, "Add or update asset");
6
+ }
7
+ export function removeAssetCommand(assetId) {
8
+ return {
9
+ id: createCommandId("remove-asset"),
10
+ label: "Remove asset",
11
+ createPatches(document) {
12
+ const asset = document.assets[assetId];
13
+ if (!asset)
14
+ return [];
15
+ const usedByEntity = Object.values(document.entities).some((entity) => entity.assetId === assetId ||
16
+ entity.properties?.textureAssetId === assetId);
17
+ const usedByMaterial = Object.values(document.materials).some((material) => Object.values(material.textures ?? {}).some((texture) => texture?.assetId === assetId));
18
+ if (usedByEntity ||
19
+ usedByMaterial ||
20
+ document.environment.assetId === assetId ||
21
+ document.environment.background.assetId === assetId ||
22
+ skyboxReferencesAsset(document.environment.background.skybox, assetId) ||
23
+ document.weather.textureAssetId === assetId) {
24
+ throw new Error(`Asset is still referenced: ${assetId}`);
25
+ }
26
+ return [
27
+ {
28
+ op: "delete",
29
+ path: ["assets", assetId],
30
+ previousValue: asset,
31
+ },
32
+ ];
33
+ },
34
+ };
35
+ }
36
+ function skyboxReferencesAsset(skybox, assetId) {
37
+ if (!skybox || skybox.source.kind === "procedural")
38
+ return false;
39
+ if (skybox.source.kind !== "cubemap") {
40
+ return skybox.source.assetId === assetId;
41
+ }
42
+ return Object.values(skybox.source.faces).includes(assetId);
43
+ }
44
+ export function upsertMaterialCommand(material) {
45
+ return {
46
+ id: createCommandId("material"),
47
+ label: "Add or update material",
48
+ createPatches(document) {
49
+ const hasLegacyBinding = Object.hasOwn(material, "targetEntityId") ||
50
+ Object.hasOwn(material, "targetName");
51
+ if (hasLegacyBinding && material.creation) {
52
+ throw new Error("Owned materials use explicit binding records, not legacy target fields");
53
+ }
54
+ if (material.targetEntityId &&
55
+ !document.entities[material.targetEntityId]) {
56
+ throw new Error(`Material target entity not found: ${material.targetEntityId}`);
57
+ }
58
+ const bindingPatches = hasLegacyBinding
59
+ ? synchronizeMaterialBindings(document, [material.id], material.targetEntityId ?? null, material.targetName ? { [material.id]: material.targetName } : {})
60
+ : [];
61
+ return [
62
+ ...bindingPatches,
63
+ ...setPropertyCommand(["materials", material.id], toMaterialDefinition(material), "Add or update material").createPatches(document),
64
+ ];
65
+ },
66
+ };
67
+ }
68
+ export function setViewportCameraCommand(camera) {
69
+ return setPropertyCommand(["camera"], camera, "Update viewport camera");
70
+ }
71
+ export function setEnvironmentCommand(environment) {
72
+ return setPropertyCommand(["environment"], environment, "Update environment");
73
+ }
74
+ export function setGroundCommand(ground) {
75
+ return setPropertyCommand(["ground"], ground, "Update ground");
76
+ }
77
+ export function setFogCommand(fog) {
78
+ return setPropertyCommand(["fog"], fog, "Update fog");
79
+ }
80
+ export function setWeatherCommand(weather) {
81
+ return setPropertyCommand(["weather"], weather, "Update weather");
82
+ }
83
+ export function setPostProcessCommand(postProcess) {
84
+ return setPropertyCommand(["postProcess"], postProcess, "Update post processing");
85
+ }
86
+ export function upsertLightCommand(light) {
87
+ return {
88
+ id: createCommandId("light"),
89
+ label: "Add or update light",
90
+ createPatches(document) {
91
+ const index = document.lights.findIndex((item) => item.id === light.id);
92
+ const next = index < 0
93
+ ? [...document.lights, light]
94
+ : document.lights.map((item, itemIndex) => itemIndex === index ? light : item);
95
+ return [
96
+ {
97
+ op: "set",
98
+ path: ["lights"],
99
+ value: next,
100
+ previousValue: document.lights,
101
+ },
102
+ ];
103
+ },
104
+ };
105
+ }
106
+ export function setMaterialTextureCommand(materialId, slot, texture) {
107
+ return setPropertyCommand(["materials", materialId, "textures", slot], texture, `Set ${slot} texture`);
108
+ }
109
+ export function removeMaterialTextureCommand(materialId, slot) {
110
+ return {
111
+ id: createCommandId("remove-material-texture"),
112
+ label: `Remove ${slot} texture`,
113
+ createPatches(document) {
114
+ const previous = document.materials[materialId]?.textures?.[slot];
115
+ if (!previous)
116
+ return [];
117
+ return [
118
+ {
119
+ op: "delete",
120
+ path: ["materials", materialId, "textures", slot],
121
+ previousValue: previous,
122
+ },
123
+ ];
124
+ },
125
+ };
126
+ }
127
+ export function removeLightCommand(lightId) {
128
+ return {
129
+ id: createCommandId("remove-light"),
130
+ label: "Remove light",
131
+ createPatches(document) {
132
+ const next = document.lights.filter((light) => light.id !== lightId);
133
+ if (next.length === document.lights.length)
134
+ return [];
135
+ return [
136
+ {
137
+ op: "set",
138
+ path: ["lights"],
139
+ value: next,
140
+ previousValue: document.lights,
141
+ },
142
+ ];
143
+ },
144
+ };
145
+ }
146
+ //# sourceMappingURL=scene-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-commands.js","sourceRoot":"","sources":["../../src/commands/scene-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type ShapeEntityProperties, type TransformValue, type Vector3Value } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export interface ShapeOptions {
4
+ id: string;
5
+ shape: ShapeEntityProperties["shape"];
6
+ name?: string;
7
+ parentId?: string | null;
8
+ transform?: TransformValue;
9
+ points?: readonly Vector3Value[];
10
+ width?: number;
11
+ height?: number;
12
+ radius?: number;
13
+ depth?: number;
14
+ tubeRadius?: number;
15
+ wallHeight?: number;
16
+ segments?: number;
17
+ closed?: boolean;
18
+ }
19
+ export declare function createShapeCommand(options: ShapeOptions): EditorCommand;
20
+ export declare function setShapePointsCommand(entityId: string, points: readonly Vector3Value[]): EditorCommand;
21
+ export declare function addShapePointCommand(entityId: string, point: Vector3Value, index?: number): EditorCommand;
22
+ export declare function updateShapePointCommand(entityId: string, index: number, point: Vector3Value): EditorCommand;
23
+ export declare function removeShapePointCommand(entityId: string, index: number): EditorCommand;
24
+ //# sourceMappingURL=shape-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape-commands.d.ts","sourceRoot":"","sources":["../../src/commands/shape-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa,CAmDvE;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,YAAY,EAAE,GAC9B,aAAa,CAEf;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,CAMf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,YAAY,GAClB,aAAa,CAOf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,aAAa,CAIf"}
@@ -0,0 +1,95 @@
1
+ import { createIdentityTransform, } from "@skenora/contracts";
2
+ import { circlePoints, rectanglePoints } from "@skenora/geometry";
3
+ import { addEntityCommand, createCommandId, } from "../core/commands.js";
4
+ export function createShapeCommand(options) {
5
+ const closed = options.closed ??
6
+ ["rectangle", "circle", "polygon", "box"].includes(options.shape);
7
+ const points = options.shape === "rectangle" || options.shape === "box"
8
+ ? rectanglePoints(options.width ?? 1, options.shape === "box"
9
+ ? (options.depth ?? 1)
10
+ : (options.height ?? 1))
11
+ : options.shape === "circle"
12
+ ? circlePoints(options.radius ?? 0.5, options.segments)
13
+ : (options.points ?? []);
14
+ const minimum = closed ? 3 : 2;
15
+ if (points.length < minimum) {
16
+ throw new Error(`A shape requires at least ${minimum} points`);
17
+ }
18
+ const properties = {
19
+ shape: options.shape,
20
+ points,
21
+ closed,
22
+ fillColor: { r: 0.2, g: 0.55, b: 1 },
23
+ fillAlpha: 0.35,
24
+ strokeColor: { r: 0.3, g: 0.7, b: 1 },
25
+ ...(options.width === undefined ? {} : { width: options.width }),
26
+ ...(options.height === undefined ? {} : { height: options.height }),
27
+ ...(options.radius === undefined ? {} : { radius: options.radius }),
28
+ ...(options.depth === undefined ? {} : { depth: options.depth }),
29
+ ...(options.tubeRadius === undefined
30
+ ? {}
31
+ : { tubeRadius: options.tubeRadius }),
32
+ ...(options.wallHeight === undefined
33
+ ? {}
34
+ : { wallHeight: options.wallHeight }),
35
+ ...(options.segments === undefined ? {} : { segments: options.segments }),
36
+ };
37
+ const entity = {
38
+ id: options.id,
39
+ name: options.name ?? options.shape,
40
+ type: "shape",
41
+ parentId: options.parentId ?? null,
42
+ enabled: true,
43
+ visible: true,
44
+ transform: options.transform ?? createIdentityTransform(),
45
+ properties,
46
+ };
47
+ return addEntityCommand(entity);
48
+ }
49
+ export function setShapePointsCommand(entityId, points) {
50
+ return updateShapePoints(entityId, "Update shape points", () => points);
51
+ }
52
+ export function addShapePointCommand(entityId, point, index) {
53
+ return updateShapePoints(entityId, "Add shape point", (points) => {
54
+ const next = [...points];
55
+ next.splice(index ?? next.length, 0, point);
56
+ return next;
57
+ });
58
+ }
59
+ export function updateShapePointCommand(entityId, index, point) {
60
+ return updateShapePoints(entityId, "Move shape point", (points) => {
61
+ if (!points[index])
62
+ throw new Error(`Shape point not found: ${index}`);
63
+ return points.map((value, itemIndex) => itemIndex === index ? point : value);
64
+ });
65
+ }
66
+ export function removeShapePointCommand(entityId, index) {
67
+ return updateShapePoints(entityId, "Remove shape point", (points) => points.filter((_, itemIndex) => itemIndex !== index));
68
+ }
69
+ function updateShapePoints(entityId, label, update) {
70
+ return {
71
+ id: createCommandId("shape-points"),
72
+ label,
73
+ createPatches(document) {
74
+ const entity = document.entities[entityId];
75
+ if (!entity || entity.type !== "shape") {
76
+ throw new Error(`Shape entity not found: ${entityId}`);
77
+ }
78
+ const properties = entity.properties;
79
+ const points = update(properties.points);
80
+ const minimum = properties.closed ? 3 : 2;
81
+ if (points.length < minimum) {
82
+ throw new Error(`Shape requires at least ${minimum} points`);
83
+ }
84
+ return [
85
+ {
86
+ op: "set",
87
+ path: ["entities", entityId, "properties", "points"],
88
+ value: points,
89
+ previousValue: properties.points,
90
+ },
91
+ ];
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=shape-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape-commands.js","sourceRoot":"","sources":["../../src/commands/shape-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { TextureAnimationRecord } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export declare function upsertTextureAnimationCommand(animation: TextureAnimationRecord): EditorCommand;
4
+ export declare function removeTextureAnimationCommand(animationId: string): EditorCommand;
5
+ //# sourceMappingURL=texture-animation-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"texture-animation-commands.d.ts","sourceRoot":"","sources":["../../src/commands/texture-animation-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,sBAAsB,GAChC,aAAa,CAMf;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,MAAM,GAClB,aAAa,CAiBf"}
@@ -0,0 +1,23 @@
1
+ import { createCommandId, setPropertyCommand, } from "../core/commands.js";
2
+ export function upsertTextureAnimationCommand(animation) {
3
+ return setPropertyCommand(["textureAnimations", animation.id], { ...animation, durationMs: Math.max(1, animation.durationMs) }, "Add or update texture animation");
4
+ }
5
+ export function removeTextureAnimationCommand(animationId) {
6
+ return {
7
+ id: createCommandId("remove-texture-animation"),
8
+ label: "Remove texture animation",
9
+ createPatches(document) {
10
+ const animation = document.textureAnimations[animationId];
11
+ return animation
12
+ ? [
13
+ {
14
+ op: "delete",
15
+ path: ["textureAnimations", animationId],
16
+ previousValue: animation,
17
+ },
18
+ ]
19
+ : [];
20
+ },
21
+ };
22
+ }
23
+ //# sourceMappingURL=texture-animation-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"texture-animation-commands.js","sourceRoot":"","sources":["../../src/commands/texture-animation-commands.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,kBAAkB,GAEnB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,6BAA6B,CAC3C,SAAiC;IAEjC,OAAO,kBAAkB,CACvB,CAAC,mBAAmB,EAAE,SAAS,CAAC,EAAE,CAAC,EACnC,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,EAC/D,iCAAiC,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,WAAmB;IAEnB,OAAO;QACL,EAAE,EAAE,eAAe,CAAC,0BAA0B,CAAC;QAC/C,KAAK,EAAE,0BAA0B;QACjC,aAAa,CAAC,QAAQ;YACpB,MAAM,SAAS,GAAG,QAAQ,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YAC1D,OAAO,SAAS;gBACd,CAAC,CAAC;oBACE;wBACE,EAAE,EAAE,QAAiB;wBACrB,IAAI,EAAE,CAAC,mBAAmB,EAAE,WAAW,CAAC;wBACxC,aAAa,EAAE,SAAS;qBACzB;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { type SceneDocumentData } from "@skenora/contracts";
2
+ import type { DocumentChange } from "@skenora/document";
3
+ export interface CandidateCommitOptions {
4
+ /** The document revision the candidate was compiled against. */
5
+ expectedRevision: number;
6
+ /** Optional opaque hash of the document the candidate was compiled against. */
7
+ expectedDocumentHash?: string;
8
+ /** History/event label for the atomic candidate commit. */
9
+ label?: string;
10
+ }
11
+ export interface CandidateCommitResult {
12
+ /** The Editor change record containing the candidate's granular patches. */
13
+ readonly change: DocumentChange;
14
+ /** Alias for change.id for adapters that expose metadata separately. */
15
+ readonly changeId: string;
16
+ /** The revision immediately before this candidate was committed. */
17
+ readonly baseRevision: number;
18
+ /** The revision assigned to this candidate commit. */
19
+ readonly revision: number;
20
+ /** Stable opaque hash of the committed candidate document. */
21
+ readonly documentHash: string;
22
+ }
23
+ export type EditorRevisionConflictReason = "revision" | "document-hash";
24
+ export interface EditorRevisionConflictDetails {
25
+ readonly reason: EditorRevisionConflictReason;
26
+ readonly expectedRevision: number;
27
+ readonly actualRevision: number;
28
+ readonly expectedDocumentHash: string | null;
29
+ readonly actualDocumentHash: string | null;
30
+ }
31
+ /**
32
+ * Thrown when a candidate's revision precondition no longer matches the
33
+ * synchronous Editor state. The error never contains the document itself.
34
+ */
35
+ export declare class EditorRevisionConflictError extends Error {
36
+ readonly code: "editor.revision-conflict";
37
+ readonly reason: EditorRevisionConflictReason;
38
+ readonly expectedRevision: number;
39
+ readonly actualRevision: number;
40
+ readonly expectedDocumentHash: string | null;
41
+ readonly actualDocumentHash: string | null;
42
+ readonly expected: Readonly<{
43
+ revision: number;
44
+ documentHash: string | null;
45
+ }>;
46
+ readonly actual: Readonly<{
47
+ revision: number;
48
+ documentHash: string | null;
49
+ }>;
50
+ constructor(details: EditorRevisionConflictDetails);
51
+ }
52
+ /**
53
+ * Creates the opaque hash used by the optional Editor candidate CAS check.
54
+ *
55
+ * The input is canonicalized by the existing SceneDocument serializer. This
56
+ * is a stable concurrency token, not a cryptographic integrity digest.
57
+ */
58
+ export declare function createSceneDocumentRevisionHash(document: Readonly<SceneDocumentData>): string;
59
+ //# sourceMappingURL=candidate-commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidate-commit.d.ts","sourceRoot":"","sources":["../../src/core/candidate-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,4BAA4B,GAAG,UAAU,GAAG,eAAe,CAAC;AAExE,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,4BAA4B,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,IAAI,EAAG,0BAA0B,CAAU;IACpD,QAAQ,CAAC,MAAM,EAAE,4BAA4B,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC1B,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC,CAAC;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC,CAAC;gBAES,OAAO,EAAE,6BAA6B;CAuBnD;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACpC,MAAM,CASR"}
@@ -0,0 +1,54 @@
1
+ import { serializeSceneDocument, } from "@skenora/contracts";
2
+ /**
3
+ * Thrown when a candidate's revision precondition no longer matches the
4
+ * synchronous Editor state. The error never contains the document itself.
5
+ */
6
+ export class EditorRevisionConflictError extends Error {
7
+ code = "editor.revision-conflict";
8
+ reason;
9
+ expectedRevision;
10
+ actualRevision;
11
+ expectedDocumentHash;
12
+ actualDocumentHash;
13
+ expected;
14
+ actual;
15
+ constructor(details) {
16
+ const expectedDocumentHash = details.expectedDocumentHash;
17
+ const actualDocumentHash = details.actualDocumentHash;
18
+ const message = details.reason === "revision"
19
+ ? `Editor candidate revision conflict: expected ${details.expectedRevision}, current ${details.actualRevision}`
20
+ : `Editor candidate document hash conflict: expected ${expectedDocumentHash}, current ${actualDocumentHash}`;
21
+ super(message);
22
+ this.name = "EditorRevisionConflictError";
23
+ this.reason = details.reason;
24
+ this.expectedRevision = details.expectedRevision;
25
+ this.actualRevision = details.actualRevision;
26
+ this.expectedDocumentHash = expectedDocumentHash;
27
+ this.actualDocumentHash = actualDocumentHash;
28
+ this.expected = Object.freeze({
29
+ revision: details.expectedRevision,
30
+ documentHash: expectedDocumentHash,
31
+ });
32
+ this.actual = Object.freeze({
33
+ revision: details.actualRevision,
34
+ documentHash: actualDocumentHash,
35
+ });
36
+ }
37
+ }
38
+ /**
39
+ * Creates the opaque hash used by the optional Editor candidate CAS check.
40
+ *
41
+ * The input is canonicalized by the existing SceneDocument serializer. This
42
+ * is a stable concurrency token, not a cryptographic integrity digest.
43
+ */
44
+ export function createSceneDocumentRevisionHash(document) {
45
+ const serialized = serializeSceneDocument(document, 0);
46
+ let hash = 0xcbf29ce484222325n;
47
+ const prime = 0x100000001b3n;
48
+ for (let index = 0; index < serialized.length; index += 1) {
49
+ hash ^= BigInt(serialized.charCodeAt(index));
50
+ hash = BigInt.asUintN(64, hash * prime);
51
+ }
52
+ return `fnv1a64:${hash.toString(16).padStart(16, "0")}`;
53
+ }
54
+ //# sourceMappingURL=candidate-commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidate-commit.js","sourceRoot":"","sources":["../../src/core/candidate-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAEvB,MAAM,oBAAoB,CAAC;AAmC5B;;;GAGG;AACH,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IAC3C,IAAI,GAAG,0BAAmC,CAAC;IAC3C,MAAM,CAA+B;IACrC,gBAAgB,CAAS;IACzB,cAAc,CAAS;IACvB,oBAAoB,CAAgB;IACpC,kBAAkB,CAAgB;IAClC,QAAQ,CAGd;IACM,MAAM,CAGZ;IAEH,YAAY,OAAsC;QAChD,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;QAC1D,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACtD,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,KAAK,UAAU;YAC3B,CAAC,CAAC,gDAAgD,OAAO,CAAC,gBAAgB,aAAa,OAAO,CAAC,cAAc,EAAE;YAC/G,CAAC,CAAC,qDAAqD,oBAAoB,aAAa,kBAAkB,EAAE,CAAC;QACjH,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACjD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QACjD,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;YAC5B,QAAQ,EAAE,OAAO,CAAC,gBAAgB;YAClC,YAAY,EAAE,oBAAoB;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC1B,QAAQ,EAAE,OAAO,CAAC,cAAc;YAChC,YAAY,EAAE,kBAAkB;SACjC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAqC;IAErC,MAAM,UAAU,GAAG,sBAAsB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACvD,IAAI,IAAI,GAAG,mBAAmB,CAAC;IAC/B,MAAM,KAAK,GAAG,cAAc,CAAC;IAC7B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1D,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,WAAW,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,20 @@
1
+ /** Core command contract and reusable document operations. */
2
+ import { type EntityRecord, type SceneDocumentData, type TransformValue } from "@skenora/contracts";
3
+ import { type DocumentPatch, type DocumentPath } from "@skenora/document";
4
+ export interface EditorCommand {
5
+ id: string;
6
+ label: string;
7
+ createPatches(document: Readonly<SceneDocumentData>): DocumentPatch[];
8
+ }
9
+ export declare function createCommandId(prefix?: string): string;
10
+ export declare function setPropertyCommand(path: DocumentPath, value: unknown, label?: string): EditorCommand;
11
+ export declare function replaceDocumentCommand(document: SceneDocumentData, label?: string): EditorCommand;
12
+ export declare function addEntityCommand(entity: EntityRecord): EditorCommand;
13
+ export declare function removeEntityCommand(entityId: string): EditorCommand;
14
+ export declare function setEntityTransformCommand(entityId: string, transform: TransformValue): EditorCommand;
15
+ export declare function renameEntityCommand(entityId: string, name: string): EditorCommand;
16
+ export declare function setEntityEnabledCommand(entityId: string, enabled: boolean): EditorCommand;
17
+ export declare function setEntityVisibleCommand(entityId: string, visible: boolean): EditorCommand;
18
+ export declare function reparentEntityCommand(entityId: string, parentId: string | null): EditorCommand;
19
+ export declare function duplicateEntityTreeCommand(entityId: string, createId?: (sourceId: string) => string): EditorCommand;
20
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/core/commands.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,aAAa,EAAE,CAAC;CACvE;AAID,wBAAgB,eAAe,CAAC,MAAM,SAAY,GAAG,MAAM,CAG1D;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,OAAO,EACd,KAAK,SAAiB,GACrB,aAAa,CAUf;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,SAAqB,GACzB,aAAa,CAEf;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CA2BpE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAgDnE;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,cAAc,GACxB,aAAa,CAMf;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,aAAa,CAMf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,aAAa,CAMf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,aAAa,CAMf;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,aAAa,CA4Cf;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MACiB,GAChD,aAAa,CA4Hf"}