@womp/kakapo-sdk 0.3.0 → 0.3.1
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 +19 -12
- package/dist/api.d.ts +2 -0
- package/dist/api.js +16 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,10 +53,10 @@ dynamically in Node.js.
|
|
|
53
53
|
|
|
54
54
|
Applications that already own a renderer connection can pass a `KakapoAPITransport` as
|
|
55
55
|
`new KakapoAPI({ transport })`. The adapter defines connection lifecycle, RPC, and token responses.
|
|
56
|
-
`captureScreenshot({ view: "current" })` requests the renderer's JPEG without changing the camera
|
|
57
|
-
or requiring a cached scene. Current-view captures cannot include `targetId` or `targetIds`.
|
|
58
|
-
Framed captures restore the camera they replaced after capture. If another client moves the camera
|
|
59
|
-
while capture is pending, the SDK detects that change and preserves the newer camera instead.
|
|
56
|
+
`captureScreenshot({ view: "current" })` requests the renderer's JPEG without changing the camera
|
|
57
|
+
or requiring a cached scene. Current-view captures cannot include `targetId` or `targetIds`.
|
|
58
|
+
Framed captures restore the camera they replaced after capture. If another client moves the camera
|
|
59
|
+
while capture is pending, the SDK detects that change and preserves the newer camera instead.
|
|
60
60
|
|
|
61
61
|
All public inputs are checked at runtime as well as by TypeScript. Invalid calls throw structured
|
|
62
62
|
`KakapoValidationError` objects with a stable `code`, offending `path`, expected rule, and a
|
|
@@ -80,15 +80,22 @@ typed `points` array replaces that data; use the granular operations when editin
|
|
|
80
80
|
Engine-backed reads such as bounding boxes and screenshots remain asynchronous. Run them before the
|
|
81
81
|
first draft mutation or after `editScene()` commits.
|
|
82
82
|
|
|
83
|
-
Each `editScene()` refreshes before creating its private draft. Top-level edits are serialized per
|
|
84
|
-
client. Changed drafts reread canonical state before submission and reject a changed baseline;
|
|
85
|
-
camera movement alone does not invalidate an ordinary scene edit. This read does not eliminate
|
|
86
|
-
a cross-client race between validation and submission through a backend wrapper. Commit patches add
|
|
87
|
-
RFC 6902 `test` guards only for the wrapper partitions the draft changes: `/ext` and the remaining
|
|
88
|
-
scene. This avoids turning a geometry-only edit into an unnecessary extension operation. Adding a
|
|
89
|
-
missing `/ext` root is rejected because the existing wrapper cannot guard that cross-partition change;
|
|
90
|
-
refresh or migrate the scene before retrying. Calling a scene-mutating method through raw `rpc()`
|
|
83
|
+
Each `editScene()` refreshes before creating its private draft. Top-level edits are serialized per
|
|
84
|
+
client. Changed drafts reread canonical state before submission and reject a changed baseline;
|
|
85
|
+
camera movement alone does not invalidate an ordinary scene edit. This read does not eliminate
|
|
86
|
+
a cross-client race between validation and submission through a backend wrapper. Commit patches add
|
|
87
|
+
RFC 6902 `test` guards only for the wrapper partitions the draft changes: `/ext` and the remaining
|
|
88
|
+
scene. This avoids turning a geometry-only edit into an unnecessary extension operation. Adding a
|
|
89
|
+
missing `/ext` root is rejected because the existing wrapper cannot guard that cross-partition change;
|
|
90
|
+
refresh or migrate the scene before retrying. Calling a scene-mutating method through raw `rpc()`
|
|
91
91
|
deliberately marks the cache stale.
|
|
92
|
+
|
|
93
|
+
Node IDs allocated by `createNode()` and `cloneNode()` increase for the lifetime of a `KakapoAPI`
|
|
94
|
+
instance. IDs observed in scene snapshots, draft patches, or numeric node-extension keys remain
|
|
95
|
+
reserved after deletion, rollback, and reconnect. This prevents delete-and-create edits from changing
|
|
96
|
+
an existing renderer object's type by reusing its ID. A new API instance starts above IDs in its current
|
|
97
|
+
snapshot; this is not a persistent project-wide allocator. Raw patches supply their own IDs and must
|
|
98
|
+
preserve object identity; concurrent clients remain subject to the scene revision guards.
|
|
92
99
|
|
|
93
100
|
`editSceneAndSave(callback)` submits the standard `scene_state_patch` command and, after
|
|
94
101
|
acknowledgement, calls `save_scene` once on the same connection. No new Kakapo command is required.
|
package/dist/api.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ export declare class KakapoAPI {
|
|
|
84
84
|
private draftScene?;
|
|
85
85
|
private draftDirty;
|
|
86
86
|
private rendererSyncRequired;
|
|
87
|
+
private nextNodeId;
|
|
87
88
|
constructor(options?: KakapoAPIOptions);
|
|
88
89
|
get isConnected(): boolean;
|
|
89
90
|
connect(): Promise<void>;
|
|
@@ -137,6 +138,7 @@ export declare class KakapoAPI {
|
|
|
137
138
|
private ensureRendererReady;
|
|
138
139
|
private captureRendererFrame;
|
|
139
140
|
private screenshotDirection;
|
|
141
|
+
private reserveNodeIds;
|
|
140
142
|
private createNode;
|
|
141
143
|
private cloneNode;
|
|
142
144
|
private updateNode;
|
package/dist/api.js
CHANGED
|
@@ -24,6 +24,7 @@ export class KakapoAPI {
|
|
|
24
24
|
draftScene;
|
|
25
25
|
draftDirty = false;
|
|
26
26
|
rendererSyncRequired = false;
|
|
27
|
+
nextNodeId = 1;
|
|
27
28
|
constructor(options = {}) {
|
|
28
29
|
this.transport = options.transport ?? new KakapoTransport({
|
|
29
30
|
url: options.url ?? "ws://127.0.0.1:5502",
|
|
@@ -77,6 +78,7 @@ export class KakapoAPI {
|
|
|
77
78
|
const result = await this.call("scene_state_get");
|
|
78
79
|
const scene = parseJsonResult(result, "scene_state_get");
|
|
79
80
|
assertScene(scene, "refreshScene");
|
|
81
|
+
this.reserveNodeIds(scene);
|
|
80
82
|
this.rawScene = scene;
|
|
81
83
|
this.cacheValid = true;
|
|
82
84
|
return this.getScene();
|
|
@@ -207,6 +209,7 @@ export class KakapoAPI {
|
|
|
207
209
|
applyScenePatch(operations) {
|
|
208
210
|
const candidate = applyJsonPatch(this.requireDraft("applyScenePatch"), operations);
|
|
209
211
|
assertScene(candidate, "applyScenePatch");
|
|
212
|
+
this.reserveNodeIds(candidate);
|
|
210
213
|
this.draftScene = candidate;
|
|
211
214
|
this.draftDirty = true;
|
|
212
215
|
return this.getScene();
|
|
@@ -439,12 +442,24 @@ export class KakapoAPI {
|
|
|
439
442
|
};
|
|
440
443
|
return directions[view];
|
|
441
444
|
}
|
|
445
|
+
reserveNodeIds(scene) {
|
|
446
|
+
// Never rewind after deletion, rollback, or reconnect: old IDs may still be referenced.
|
|
447
|
+
for (const record of [scene.nodes, scene.ext ?? {}]) {
|
|
448
|
+
for (const key of Object.keys(record)) {
|
|
449
|
+
const id = Number(key);
|
|
450
|
+
if (Number.isSafeInteger(id) && id >= this.nextNodeId)
|
|
451
|
+
this.nextNodeId = id + 1;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
442
455
|
createNode(input) {
|
|
443
456
|
const scene = this.requireDraft("createNode");
|
|
444
457
|
assertId(input.parentId, "createNode", "parentId", true);
|
|
445
458
|
if (!scene.nodes[String(input.parentId)])
|
|
446
459
|
throw missingNode(input.parentId, "createNode");
|
|
447
|
-
const id =
|
|
460
|
+
const id = this.nextNodeId;
|
|
461
|
+
assertId(id, "createNode", "nodeId");
|
|
462
|
+
this.nextNodeId++;
|
|
448
463
|
const initial = defaultNode(input.kind, id, input.name ?? "");
|
|
449
464
|
const node = this.mergeNode(initial, input.properties ?? {});
|
|
450
465
|
const children = this.treeArrays(scene);
|