@adea-ai/spatial 0.118.4 → 0.118.5
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.
|
@@ -51,9 +51,15 @@ export type SimFrameRequestMessage = Readonly<{
|
|
|
51
51
|
}>;
|
|
52
52
|
}> | Readonly<{
|
|
53
53
|
type: 'frame.character.save';
|
|
54
|
+
/**
|
|
55
|
+
* `revision` orders saves from one frame: it increases with every save request the frame
|
|
56
|
+
* makes, so the host can refuse one older than a save it already committed. Optional so
|
|
57
|
+
* frames built before it keep working.
|
|
58
|
+
*/
|
|
54
59
|
payload: Readonly<{
|
|
55
60
|
requestId: string;
|
|
56
61
|
character: string;
|
|
62
|
+
revision?: number;
|
|
57
63
|
}>;
|
|
58
64
|
}>;
|
|
59
65
|
/** The scene channel's acknowledgements, refusals and measurements (see `scene.ts`). */
|
|
@@ -136,11 +136,23 @@ export function parseFrameMessage(event, context) {
|
|
|
136
136
|
: fail('invalid_payload');
|
|
137
137
|
}
|
|
138
138
|
case 'frame.character.save': {
|
|
139
|
-
const body = strictRecord(payload, ['requestId', 'character']);
|
|
139
|
+
const body = strictRecord(payload, ['requestId', 'character'], ['revision']);
|
|
140
140
|
const requestId = boundedString(body?.requestId, REQUEST_ID);
|
|
141
141
|
const character = parseSimCharacterValue(body?.character);
|
|
142
|
+
const revision = body?.revision;
|
|
143
|
+
if (revision !== undefined &&
|
|
144
|
+
(typeof revision !== 'number' || !Number.isSafeInteger(revision) || revision < 1))
|
|
145
|
+
return fail('invalid_payload');
|
|
142
146
|
return requestId && character
|
|
143
|
-
? {
|
|
147
|
+
? {
|
|
148
|
+
ok: true,
|
|
149
|
+
message: {
|
|
150
|
+
type,
|
|
151
|
+
payload: revision === undefined
|
|
152
|
+
? { requestId, character }
|
|
153
|
+
: { requestId, character, revision },
|
|
154
|
+
},
|
|
155
|
+
}
|
|
144
156
|
: fail('invalid_payload');
|
|
145
157
|
}
|
|
146
158
|
case 'frame.scene.ack':
|
|
@@ -8,7 +8,10 @@ import type { SimFrameRequestMessage, SimHostMessage } from './messages';
|
|
|
8
8
|
* `false`, so the engine never shows a saved value the host did not commit.
|
|
9
9
|
*/
|
|
10
10
|
export type CharacterSaveClient = Readonly<{
|
|
11
|
-
|
|
11
|
+
/** `revision` (a positive integer that increases per save) lets the host refuse an older save. */
|
|
12
|
+
save(character: string, options?: Readonly<{
|
|
13
|
+
revision?: number;
|
|
14
|
+
}>): Promise<boolean>;
|
|
12
15
|
/** Feed every parsed host message in; unrelated ones are ignored. */
|
|
13
16
|
receive(message: SimHostMessage): void;
|
|
14
17
|
/** Fails any open save. Call when the frame is torn down. */
|
|
@@ -15,8 +15,12 @@ export function createCharacterSaveClient(options) {
|
|
|
15
15
|
open?.settle(false);
|
|
16
16
|
}
|
|
17
17
|
return {
|
|
18
|
-
save(character) {
|
|
19
|
-
|
|
18
|
+
save(character, saveOptions) {
|
|
19
|
+
const revision = saveOptions?.revision;
|
|
20
|
+
if (disposed ||
|
|
21
|
+
open ||
|
|
22
|
+
parseSimCharacterValue(character) === null ||
|
|
23
|
+
(revision !== undefined && (!Number.isSafeInteger(revision) || revision < 1)))
|
|
20
24
|
return Promise.resolve(false);
|
|
21
25
|
const requestId = mint();
|
|
22
26
|
return new Promise((resolve) => {
|
|
@@ -33,7 +37,12 @@ export function createCharacterSaveClient(options) {
|
|
|
33
37
|
};
|
|
34
38
|
open = entry;
|
|
35
39
|
try {
|
|
36
|
-
options.post({
|
|
40
|
+
options.post({
|
|
41
|
+
type: 'frame.character.save',
|
|
42
|
+
payload: revision === undefined
|
|
43
|
+
? { requestId, character }
|
|
44
|
+
: { requestId, character, revision },
|
|
45
|
+
});
|
|
37
46
|
}
|
|
38
47
|
catch {
|
|
39
48
|
entry.settle(false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adea-ai/spatial",
|
|
3
|
-
"version": "0.118.
|
|
3
|
+
"version": "0.118.5",
|
|
4
4
|
"description": "Scene and asset manifest contracts plus the shell-to-engine spatial protocol for Adea workspaces: scene mount manifests, spawn URL helpers, and scene telemetry schemas. Pure types — no rendering, no binaries.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assets",
|
|
@@ -57,7 +57,12 @@ export type SimFrameRequestMessage =
|
|
|
57
57
|
}>
|
|
58
58
|
| Readonly<{
|
|
59
59
|
type: 'frame.character.save'
|
|
60
|
-
|
|
60
|
+
/**
|
|
61
|
+
* `revision` orders saves from one frame: it increases with every save request the frame
|
|
62
|
+
* makes, so the host can refuse one older than a save it already committed. Optional so
|
|
63
|
+
* frames built before it keep working.
|
|
64
|
+
*/
|
|
65
|
+
payload: Readonly<{ requestId: string; character: string; revision?: number }>
|
|
61
66
|
}>
|
|
62
67
|
|
|
63
68
|
/** The scene channel's acknowledgements, refusals and measurements (see `scene.ts`). */
|
|
@@ -204,11 +209,26 @@ export function parseFrameMessage(
|
|
|
204
209
|
: fail('invalid_payload')
|
|
205
210
|
}
|
|
206
211
|
case 'frame.character.save': {
|
|
207
|
-
const body = strictRecord(payload, ['requestId', 'character'])
|
|
212
|
+
const body = strictRecord(payload, ['requestId', 'character'], ['revision'])
|
|
208
213
|
const requestId = boundedString(body?.requestId, REQUEST_ID)
|
|
209
214
|
const character = parseSimCharacterValue(body?.character)
|
|
215
|
+
const revision = body?.revision
|
|
216
|
+
if (
|
|
217
|
+
revision !== undefined &&
|
|
218
|
+
(typeof revision !== 'number' || !Number.isSafeInteger(revision) || revision < 1)
|
|
219
|
+
)
|
|
220
|
+
return fail('invalid_payload')
|
|
210
221
|
return requestId && character
|
|
211
|
-
? {
|
|
222
|
+
? {
|
|
223
|
+
ok: true,
|
|
224
|
+
message: {
|
|
225
|
+
type,
|
|
226
|
+
payload:
|
|
227
|
+
revision === undefined
|
|
228
|
+
? { requestId, character }
|
|
229
|
+
: { requestId, character, revision },
|
|
230
|
+
},
|
|
231
|
+
}
|
|
212
232
|
: fail('invalid_payload')
|
|
213
233
|
}
|
|
214
234
|
case 'frame.scene.ack':
|
|
@@ -11,7 +11,8 @@ import type { SimFrameRequestMessage, SimHostMessage } from './messages'
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
export type CharacterSaveClient = Readonly<{
|
|
14
|
-
|
|
14
|
+
/** `revision` (a positive integer that increases per save) lets the host refuse an older save. */
|
|
15
|
+
save(character: string, options?: Readonly<{ revision?: number }>): Promise<boolean>
|
|
15
16
|
/** Feed every parsed host message in; unrelated ones are ignored. */
|
|
16
17
|
receive(message: SimHostMessage): void
|
|
17
18
|
/** Fails any open save. Call when the frame is torn down. */
|
|
@@ -48,8 +49,14 @@ export function createCharacterSaveClient(
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
return {
|
|
51
|
-
save(character) {
|
|
52
|
-
|
|
52
|
+
save(character, saveOptions) {
|
|
53
|
+
const revision = saveOptions?.revision
|
|
54
|
+
if (
|
|
55
|
+
disposed ||
|
|
56
|
+
open ||
|
|
57
|
+
parseSimCharacterValue(character) === null ||
|
|
58
|
+
(revision !== undefined && (!Number.isSafeInteger(revision) || revision < 1))
|
|
59
|
+
)
|
|
53
60
|
return Promise.resolve(false)
|
|
54
61
|
const requestId = mint()
|
|
55
62
|
return new Promise<boolean>((resolve) => {
|
|
@@ -65,7 +72,13 @@ export function createCharacterSaveClient(
|
|
|
65
72
|
}
|
|
66
73
|
open = entry
|
|
67
74
|
try {
|
|
68
|
-
options.post({
|
|
75
|
+
options.post({
|
|
76
|
+
type: 'frame.character.save',
|
|
77
|
+
payload:
|
|
78
|
+
revision === undefined
|
|
79
|
+
? { requestId, character }
|
|
80
|
+
: { requestId, character, revision },
|
|
81
|
+
})
|
|
69
82
|
} catch {
|
|
70
83
|
entry.settle(false)
|
|
71
84
|
}
|