@mengine/medeo-tool 1.4.1-alpha.4 → 2.0.1-alpha.10
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 -0
- package/dist/{entity-contract-DQ56Ihrh.d.mts → entity-contract-Cf3AiSe7.d.mts} +46 -44
- package/dist/{entity-sandbox-OArq9NSH.mjs → entity-sandbox-BTR2cRl1.mjs} +274 -170
- package/dist/entity-sandbox-BTR2cRl1.mjs.map +1 -0
- package/dist/index.d.mts +27 -10
- package/dist/index.mjs +120 -130
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +43 -45
- package/dist/worker-entry.d.mts +2 -1
- package/dist/worker-entry.mjs +100 -93
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/entity-sandbox-OArq9NSH.mjs.map +0 -1
package/dist/sandbox-api.d.mts
CHANGED
|
@@ -1,24 +1,5 @@
|
|
|
1
1
|
//#region src/sandbox/generated/entity-edit-sandbox-api.d.ts
|
|
2
2
|
/** @generated by gen:sandbox-dts. Entity-native editor contract; DO NOT EDIT. */
|
|
3
|
-
interface BoundedDerivedSequencePayload extends JsonObject {
|
|
4
|
-
extent: {
|
|
5
|
-
kind: 'bounded';
|
|
6
|
-
start: number;
|
|
7
|
-
end: number;
|
|
8
|
-
};
|
|
9
|
-
sampling: 'derived';
|
|
10
|
-
coordinateSpace: JsonValue;
|
|
11
|
-
}
|
|
12
|
-
interface BoundedNativeSequencePayload extends JsonObject {
|
|
13
|
-
/** Factual coordinates from recalled media metadata; never invent an end/duration. */
|
|
14
|
-
extent: {
|
|
15
|
-
kind: 'bounded';
|
|
16
|
-
start: number;
|
|
17
|
-
end: number;
|
|
18
|
-
};
|
|
19
|
-
sampling: 'native';
|
|
20
|
-
coordinateSpace: JsonValue;
|
|
21
|
-
}
|
|
22
3
|
/** Business editing surface. Reads are assembled snapshots; writes preserve native operation intent. */
|
|
23
4
|
interface BusinessEntityFacade {
|
|
24
5
|
list(): SandboxEntity[];
|
|
@@ -59,17 +40,20 @@ interface EntityAssetContent {
|
|
|
59
40
|
content: JsonValue;
|
|
60
41
|
}
|
|
61
42
|
interface EntityPayloadByKind {
|
|
62
|
-
|
|
43
|
+
/** Its Timeline decides how long it runs, so it stores no length. */
|
|
44
|
+
axvideo: JsonObject;
|
|
63
45
|
timeline: JsonObject;
|
|
64
46
|
track: JsonObject & {
|
|
65
47
|
hidden?: boolean;
|
|
66
48
|
role?: string;
|
|
67
49
|
};
|
|
68
50
|
clip: JsonObject;
|
|
69
|
-
video:
|
|
70
|
-
audio
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
video: OwnDurationPayload;
|
|
52
|
+
/** Every playable sound, including video original audio and synthesized voiceovers. */
|
|
53
|
+
audio: OwnDurationPayload;
|
|
54
|
+
/** A timbre identity, never playable content; the rendered take is an `audio` entity. */
|
|
55
|
+
voice: VoiceIdentityPayload;
|
|
56
|
+
image: NoDurationPayload;
|
|
73
57
|
'sequence-marker': JsonObject & {
|
|
74
58
|
sourceRange: {
|
|
75
59
|
start: number;
|
|
@@ -103,9 +87,9 @@ interface EntityPayloadByKind {
|
|
|
103
87
|
phonemeScript?: string;
|
|
104
88
|
prosody?: JsonObject;
|
|
105
89
|
};
|
|
106
|
-
caption:
|
|
90
|
+
caption: OwnDurationPayload & {
|
|
107
91
|
baseEntityIds: string[];
|
|
108
|
-
|
|
92
|
+
selection: CaptionTextSelection;
|
|
109
93
|
style?: JsonObject;
|
|
110
94
|
segmentRanges?: {
|
|
111
95
|
segmentId: string;
|
|
@@ -160,7 +144,7 @@ interface JsonObject {
|
|
|
160
144
|
type JsonPrimitive = string | number | boolean | null;
|
|
161
145
|
type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
162
146
|
type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'video' | 'audio' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
|
|
163
|
-
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
|
|
147
|
+
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'voice-timbre' | 'audio-script-source' | 'audio-script-marker';
|
|
164
148
|
interface LinkRelationBase {
|
|
165
149
|
relation_id?: string;
|
|
166
150
|
endpoint_0_entity_id: string;
|
|
@@ -171,12 +155,18 @@ interface LinkRelationInput extends LinkRelationBase {
|
|
|
171
155
|
relation_kind: KnownRelationKind;
|
|
172
156
|
metadata?: JsonObject;
|
|
173
157
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
158
|
+
/** A still frame runs for as long as its use asks, so it states no length. */
|
|
159
|
+
interface NoDurationPayload extends JsonObject {
|
|
160
|
+
durationMs: null;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Content states how long it runs and nothing else: where it is taken from and
|
|
164
|
+
* where it lands both belong to its Sequence Marker.
|
|
165
|
+
*/
|
|
166
|
+
interface OwnDurationPayload extends JsonObject {
|
|
167
|
+
/** Factual whole milliseconds from recalled media metadata; never invented. */
|
|
168
|
+
durationMs: number;
|
|
169
|
+
}
|
|
180
170
|
interface RelationUpdateInput {
|
|
181
171
|
relation_id: string;
|
|
182
172
|
changes: FieldChange[];
|
|
@@ -199,18 +189,18 @@ type ScriptTextSegment = JsonObject & {
|
|
|
199
189
|
text: string;
|
|
200
190
|
language?: string;
|
|
201
191
|
};
|
|
202
|
-
/**
|
|
203
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Stored own fields; a variant may obtain required content fields from its
|
|
194
|
+
* declared bases.
|
|
195
|
+
*
|
|
196
|
+
* Caption and Audio may also be declared resource-only: the ASR transcript and
|
|
197
|
+
* the synthesized voiceover are attached by the host, which then fills in the
|
|
198
|
+
* remaining factual fields.
|
|
199
|
+
*/
|
|
200
|
+
type StoredEntityPayload<K extends KnownEntityKind> = EntityPayloadByKind[K] // Resource-only: the host fills the factual fields after reading the Asset.
|
|
201
|
+
| (K extends 'caption' | 'audio' ? Record<string, never> : never) | (JsonObject & Partial<EntityPayloadByKind[K]> & {
|
|
204
202
|
baseEntityIds: string[];
|
|
205
203
|
});
|
|
206
|
-
interface UnboundedConstantSequencePayload extends JsonObject {
|
|
207
|
-
extent: {
|
|
208
|
-
kind: 'unbounded';
|
|
209
|
-
start: number;
|
|
210
|
-
};
|
|
211
|
-
sampling: 'constant';
|
|
212
|
-
coordinateSpace: JsonValue;
|
|
213
|
-
}
|
|
214
204
|
interface UnlinkRelationInput {
|
|
215
205
|
relation_id: string;
|
|
216
206
|
}
|
|
@@ -219,9 +209,17 @@ interface UpdateEntityInput {
|
|
|
219
209
|
entity_id: string;
|
|
220
210
|
payload: JsonObject;
|
|
221
211
|
}
|
|
212
|
+
/** The voice-library timbre a synthesized Audio was rendered with. */
|
|
213
|
+
type VoiceIdentityPayload = JsonObject & {
|
|
214
|
+
voice: {
|
|
215
|
+
system: 'voice-library';
|
|
216
|
+
key: string;
|
|
217
|
+
name?: string;
|
|
218
|
+
};
|
|
219
|
+
};
|
|
222
220
|
declare const entities: BusinessEntityFacade;
|
|
223
221
|
declare const relations: BusinessRelationFacade;
|
|
224
|
-
/** Resolve this Entity's attached resource through the host; await before using an uninitialized Caption. */
|
|
222
|
+
/** Resolve this Entity's attached resource through the host; await before using an uninitialized Caption or Voice. */
|
|
225
223
|
declare function rgetAssetFromEntity(entityId: string): Promise<EntityAssetContent>;
|
|
226
224
|
declare function checkpoint(): EntitySandboxCheckpoint;
|
|
227
225
|
declare function rollbackTo(cp: EntitySandboxCheckpoint): void;
|
|
@@ -233,5 +231,5 @@ declare const console: {
|
|
|
233
231
|
error(...values: unknown[]): void;
|
|
234
232
|
};
|
|
235
233
|
//#endregion
|
|
236
|
-
export type {
|
|
234
|
+
export type { BusinessEntityFacade, BusinessRelationFacade, CaptionTextSelection, CreateEntityInput, DeleteEntityInput, EntityAssetContent, EntityPayloadByKind, EntitySandboxCheckpoint, EntityUpdateInput, FieldChange, FieldPath, JsonObject, JsonPrimitive, JsonValue, KnownEntityKind, KnownRelationKind, LinkRelationInput, NoDurationPayload, OwnDurationPayload, RelationUpdateInput, SandboxEntity, SandboxRelation, ScriptTextSegment, StoredEntityPayload, UnlinkRelationInput, UpdateEntityInput, VoiceIdentityPayload, checkpoint, console, entities, inputs, relations, rgetAssetFromEntity, rollbackTo };
|
|
237
235
|
//# sourceMappingURL=sandbox-api.d.mts.map
|
package/dist/worker-entry.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as EntityStoreSnapshot } from "./entity-contract-
|
|
1
|
+
import { l as EntityStoreSnapshot } from "./entity-contract-Cf3AiSe7.mjs";
|
|
2
2
|
import { VideoDocument } from "@mengine/medeo-client";
|
|
3
3
|
|
|
4
4
|
//#region src/sandbox/worker-entry.d.ts
|
|
@@ -10,6 +10,7 @@ import { VideoDocument } from "@mengine/medeo-client";
|
|
|
10
10
|
* host so hard timeout / OOM termination still preserves partial products.
|
|
11
11
|
*/
|
|
12
12
|
interface WorkerData {
|
|
13
|
+
docId: string;
|
|
13
14
|
document: VideoDocument;
|
|
14
15
|
script: string;
|
|
15
16
|
inputs?: Record<string, unknown>;
|
package/dist/worker-entry.mjs
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
import { n as toDslRows, r as businessFacades, t as EntitySandbox } from "./entity-sandbox-
|
|
2
|
-
import { LoroEntityDocument, assertCanonicalEditorResources, assertMediaAssetWritePolicy, base64ToBytes, bytesToBase64, projectEntityTimeline } from "@mengine/medeo-client";
|
|
1
|
+
import { n as toDslRows, r as businessFacades, t as EntitySandbox } from "./entity-sandbox-BTR2cRl1.mjs";
|
|
2
|
+
import { LoroEntityDocument, assertCanonicalEditorResources, assertMediaAssetWritePolicy, audioScriptAssetContent, audioScriptAssetFields, audioScriptAssetOf, base64ToBytes, bytesToBase64, projectEntityTimeline } from "@mengine/medeo-client";
|
|
3
3
|
import { parentPort, workerData } from "node:worker_threads";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import vm from "node:vm";
|
|
6
6
|
//#region src/entity/entity-asset.ts
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Persisted voiceover Audio facts, resolved by the host rather than inferred
|
|
9
|
+
* from transcript timing.
|
|
10
|
+
*
|
|
11
|
+
* A returned voice-library descriptor is validated but never written here: the
|
|
12
|
+
* timbre is its own Voice entity linked by a `voice-timbre` Relation, so the
|
|
13
|
+
* rendered Audio row stays resource-only.
|
|
14
|
+
*/
|
|
15
|
+
function speechAssetFields(content) {
|
|
16
|
+
if (!content || typeof content !== "object" || Array.isArray(content) || typeof content.storageKey !== "string" || !content.storageKey.trim() || !Number.isSafeInteger(content.durationMs) || content.durationMs <= 0) throw new Error("Speech Asset requires factual storageKey and positive millisecond duration");
|
|
17
|
+
const voice = content.voice;
|
|
18
|
+
if (voice !== void 0 && (!voice || typeof voice !== "object" || Array.isArray(voice) || voice.system !== "voice-library" || typeof voice.key !== "string" || !voice.key.trim())) throw new Error("Speech Asset has an invalid voice-library identity");
|
|
19
|
+
return { durationMs: content.durationMs };
|
|
20
|
+
}
|
|
21
|
+
/** The storage path the speech resource reports, destined for its Asset. */
|
|
22
|
+
function speechAssetStorageKey(content) {
|
|
23
|
+
speechAssetFields(content);
|
|
24
|
+
return content.storageKey;
|
|
19
25
|
}
|
|
20
26
|
//#endregion
|
|
21
27
|
//#region src/sandbox/entity-script-session.ts
|
|
@@ -26,22 +32,22 @@ const TRUNCATE_MARK = "[truncated]";
|
|
|
26
32
|
const LOG_TRUNCATED = "[log truncated]";
|
|
27
33
|
/** Entity/relation script session; compilation retains the ordered operation journal. */
|
|
28
34
|
var EntityEditSandboxSession = class {
|
|
29
|
-
|
|
35
|
+
docId;
|
|
30
36
|
entitySandbox;
|
|
31
37
|
baseRows;
|
|
32
38
|
domainIdFactory;
|
|
33
39
|
logs = [];
|
|
34
40
|
onLog;
|
|
35
41
|
logBytes = 0;
|
|
36
|
-
|
|
42
|
+
directScriptWrites = /* @__PURE__ */ new Set();
|
|
37
43
|
logCapped = false;
|
|
38
44
|
entities;
|
|
39
45
|
relations;
|
|
40
46
|
console;
|
|
41
47
|
checkpoint;
|
|
42
48
|
rollbackTo;
|
|
43
|
-
constructor(
|
|
44
|
-
this.
|
|
49
|
+
constructor(options) {
|
|
50
|
+
this.docId = options?.docId ?? "";
|
|
45
51
|
this.baseRows = toDslRows(options?.entityState ?? {
|
|
46
52
|
revision: 0,
|
|
47
53
|
audioScriptEntityId: null,
|
|
@@ -58,20 +64,25 @@ var EntityEditSandboxSession = class {
|
|
|
58
64
|
onCommand: options?.onEntityCommand,
|
|
59
65
|
onTruncate: options?.onEntityTruncate
|
|
60
66
|
});
|
|
61
|
-
const business = businessFacades(this.entitySandbox.entities, this.entitySandbox.relations);
|
|
67
|
+
const business = businessFacades(this.entitySandbox.entities, this.entitySandbox.relations, (id) => this.directScriptWrites.add(id));
|
|
62
68
|
this.entities = business.entities;
|
|
63
69
|
this.relations = business.relations;
|
|
64
70
|
this.console = this.buildConsoleShim();
|
|
65
71
|
const checkpoints = /* @__PURE__ */ new Map();
|
|
66
72
|
this.checkpoint = () => {
|
|
67
73
|
const token = Object.freeze({});
|
|
68
|
-
checkpoints.set(token,
|
|
74
|
+
checkpoints.set(token, {
|
|
75
|
+
index: this.entitySandbox.commandCount,
|
|
76
|
+
scripts: new Set(this.directScriptWrites)
|
|
77
|
+
});
|
|
69
78
|
return token;
|
|
70
79
|
};
|
|
71
80
|
this.rollbackTo = (cp) => {
|
|
72
81
|
const index = checkpoints.get(cp);
|
|
73
82
|
if (index === void 0) throw new Error("Invalid or expired sandbox checkpoint");
|
|
74
|
-
this.entitySandbox.rollbackTo(index);
|
|
83
|
+
this.entitySandbox.rollbackTo(index.index);
|
|
84
|
+
this.directScriptWrites.clear();
|
|
85
|
+
for (const id of index.scripts) this.directScriptWrites.add(id);
|
|
75
86
|
let later = false;
|
|
76
87
|
for (const token of checkpoints.keys()) {
|
|
77
88
|
if (later) checkpoints.delete(token);
|
|
@@ -83,92 +94,70 @@ var EntityEditSandboxSession = class {
|
|
|
83
94
|
async rgetAssetFromEntity(entityId, load) {
|
|
84
95
|
const entity = this.entitySandbox.entities.get(entityId);
|
|
85
96
|
if (!entity || entity.entity_kind === "asset") throw new Error(`Business Entity not found: ${entityId}`);
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
const assetId =
|
|
97
|
+
const locator = this.entitySandbox.assetOf(entityId);
|
|
98
|
+
if (!locator || typeof locator.payload.key !== "string") throw new Error(`Entity ${entityId} has no attached Asset`);
|
|
99
|
+
const assetId = locator.payload.key;
|
|
89
100
|
const result = await load(entity);
|
|
90
|
-
if (result.assetId !==
|
|
101
|
+
if (result.assetId !== assetId) throw new Error("Host returned a different Entity Asset");
|
|
91
102
|
const current = this.entitySandbox.entities.get(entityId);
|
|
92
|
-
if (!current ||
|
|
93
|
-
if (entity.entity_kind === "
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
segmentId: `asset:${assetId}:${index}`,
|
|
97
|
-
text: segment.text
|
|
98
|
-
}));
|
|
99
|
-
const bases = current.payload.baseEntityIds;
|
|
100
|
-
const scriptId = bases?.length ? this.entitySandbox.captionAudioScriptId(entityId) : this.entitySandbox.entities.create({
|
|
101
|
-
entity_kind: "audio-script",
|
|
102
|
-
payload: { segments: [] }
|
|
103
|
-
});
|
|
104
|
-
const existing = this.entitySandbox.entities.get(scriptId).payload.segments;
|
|
105
|
-
const additions = segments.filter((segment) => !existing.some((item) => item.segmentId === segment.segmentId));
|
|
106
|
-
this.entitySandbox.entities.update({
|
|
107
|
-
entity_id: scriptId,
|
|
108
|
-
payload: { segments: [...existing, ...additions] }
|
|
109
|
-
});
|
|
110
|
-
const ranges = timed.map((segment, index) => ({
|
|
111
|
-
segmentId: segments[index].segmentId,
|
|
112
|
-
startMs: segment.start_time_ms,
|
|
113
|
-
endMs: segment.end_time_ms
|
|
114
|
-
}));
|
|
115
|
-
this.entitySandbox.entities.update({
|
|
103
|
+
if (!current || this.entitySandbox.assetOf(entityId)?.entity_id !== locator.entity_id) throw new Error("Entity resource changed during its read");
|
|
104
|
+
if (entity.entity_kind === "audio" && locator.payload.system === "memota-speech") {
|
|
105
|
+
const fields = speechAssetFields(result.content);
|
|
106
|
+
if (Object.entries(fields).some(([key, value]) => JSON.stringify(current.payload[key]) !== JSON.stringify(value))) this.entitySandbox.entities.declareFields({
|
|
116
107
|
entity_id: entityId,
|
|
117
|
-
payload:
|
|
118
|
-
baseEntityIds: bases?.length ? bases : [scriptId],
|
|
119
|
-
selections: segments.map(({ segmentId }) => ({ segmentId })),
|
|
120
|
-
extent: {
|
|
121
|
-
kind: "bounded",
|
|
122
|
-
start: Math.min(...ranges.map((r) => r.startMs)),
|
|
123
|
-
end: Math.max(...ranges.map((r) => r.endMs))
|
|
124
|
-
},
|
|
125
|
-
sampling: "native",
|
|
126
|
-
coordinateSpace: "milliseconds",
|
|
127
|
-
segmentRanges: ranges
|
|
128
|
-
}
|
|
108
|
+
payload: fields
|
|
129
109
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
payload: {
|
|
133
|
-
sourceRange: {
|
|
134
|
-
start: Math.min(...ranges.map((r) => r.startMs)),
|
|
135
|
-
end: Math.max(...ranges.map((r) => r.endMs))
|
|
136
|
-
},
|
|
137
|
-
duration: { mode: "from-source" },
|
|
138
|
-
segmentRanges: ranges
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
this.entitySandbox.relations.link({
|
|
142
|
-
relation_kind: "audio-script-marker",
|
|
143
|
-
endpoint_0_entity_id: scriptId,
|
|
144
|
-
endpoint_1_entity_id: markerId
|
|
110
|
+
this.entitySandbox.entities.declareFields({
|
|
111
|
+
entity_id: locator.entity_id,
|
|
112
|
+
payload: { storageKey: speechAssetStorageKey(result.content) }
|
|
145
113
|
});
|
|
146
114
|
}
|
|
147
|
-
this.resolvedCaptionAssets.add(`${entityId}:${assetId}`);
|
|
148
115
|
return result;
|
|
149
116
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const external = this.baseRows.entities.find((row) => row.entityId === entityId)?.payload.external;
|
|
154
|
-
return !!external && typeof external === "object" && !Array.isArray(external) && "key" in external && external.key === assetId;
|
|
117
|
+
/** A speech resource is hydrated once its Asset names where the bytes live. */
|
|
118
|
+
initializedSpeech(asset) {
|
|
119
|
+
return typeof asset.payload.storageKey === "string" && asset.payload.storageKey.trim() !== "";
|
|
155
120
|
}
|
|
156
|
-
/** Finish
|
|
121
|
+
/** Finish resource initialization before validation; no partial rows are published. */
|
|
157
122
|
async prepareEntityAssets(load) {
|
|
158
123
|
for (const entity of this.entitySandbox.entities.list()) {
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
124
|
+
const locator = this.entitySandbox.assetOf(entity.entity_id);
|
|
125
|
+
if (typeof locator?.payload.key !== "string") continue;
|
|
126
|
+
if (entity.entity_kind === "audio" && locator.payload.system === "memota-speech" && !this.initializedSpeech(locator)) await this.rgetAssetFromEntity(entity.entity_id, load);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Direct script writes save a resource before the entity graph can be committed. */
|
|
130
|
+
async persistAudioScriptAssets(write) {
|
|
131
|
+
for (const entity of this.entitySandbox.entities.list()) {
|
|
132
|
+
if (entity.entity_kind !== "audio-script") continue;
|
|
133
|
+
if (audioScriptAssetOf(this.entitySandbox.rows(), entity.entity_id) !== void 0 || !this.directScriptWrites.has(entity.entity_id)) continue;
|
|
134
|
+
const content = audioScriptAssetContent(entity.payload);
|
|
135
|
+
const saved = await write(entity, content);
|
|
136
|
+
if (JSON.stringify(saved.content) !== JSON.stringify(content)) throw new Error("AudioScript resource writer changed the submitted content");
|
|
137
|
+
const assetEntityId = this.entitySandbox.entities.ensureAsset({
|
|
138
|
+
system: "memota",
|
|
139
|
+
key: saved.assetId
|
|
140
|
+
});
|
|
141
|
+
this.entitySandbox.relations.link({
|
|
142
|
+
relation_kind: "from-asset",
|
|
143
|
+
endpoint_0_entity_id: entity.entity_id,
|
|
144
|
+
endpoint_1_entity_id: assetEntityId
|
|
145
|
+
});
|
|
146
|
+
this.entitySandbox.entities.declareFields({
|
|
147
|
+
entity_id: entity.entity_id,
|
|
148
|
+
payload: audioScriptAssetFields(entity.payload)
|
|
149
|
+
});
|
|
161
150
|
}
|
|
162
151
|
}
|
|
163
152
|
buildPlan(baseVersion) {
|
|
164
153
|
const entityPlan = this.entitySandbox.buildPlan();
|
|
165
154
|
assertCanonicalEditorResources(toDslRows(entityPlan.rows));
|
|
166
155
|
assertMediaAssetWritePolicy(this.baseRows, toDslRows(entityPlan.rows));
|
|
167
|
-
if (entityPlan.rows.loroSnapshot) projectEntityTimeline(toDslRows(entityPlan.rows)
|
|
156
|
+
if (entityPlan.rows.loroSnapshot) projectEntityTimeline(toDslRows(entityPlan.rows));
|
|
168
157
|
return {
|
|
169
158
|
...entityPlan.rows.loroSnapshot ? { loro_update: bytesToBase64(this.compileJournal(entityPlan)) } : {},
|
|
170
159
|
plan_kind: "entities",
|
|
171
|
-
doc_id: this.
|
|
160
|
+
doc_id: this.docId,
|
|
172
161
|
base_version: baseVersion,
|
|
173
162
|
ops: [],
|
|
174
163
|
entity_base_revision: entityPlan.base_revision,
|
|
@@ -183,7 +172,7 @@ var EntityEditSandboxSession = class {
|
|
|
183
172
|
compileJournal(plan) {
|
|
184
173
|
return LoroEntityDocument.fromSnapshot(base64ToBytes(plan.rows.loroSnapshot), (state) => {
|
|
185
174
|
assertCanonicalEditorResources(state.rows);
|
|
186
|
-
projectEntityTimeline(state.rows
|
|
175
|
+
projectEntityTimeline(state.rows);
|
|
187
176
|
}).transact((draft) => {
|
|
188
177
|
for (const command of plan.commands) switch (command.kind) {
|
|
189
178
|
case "create-entity": {
|
|
@@ -289,6 +278,21 @@ function loadEntityAsset(entity) {
|
|
|
289
278
|
});
|
|
290
279
|
});
|
|
291
280
|
}
|
|
281
|
+
function writeEntityAsset(entity, content) {
|
|
282
|
+
return new Promise((resolve, reject) => {
|
|
283
|
+
const id = ++requestId;
|
|
284
|
+
pending.set(id, {
|
|
285
|
+
resolve,
|
|
286
|
+
reject
|
|
287
|
+
});
|
|
288
|
+
port.postMessage({
|
|
289
|
+
t: "write-entity-asset",
|
|
290
|
+
requestId: id,
|
|
291
|
+
entity,
|
|
292
|
+
content
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
292
296
|
function post(message) {
|
|
293
297
|
port.postMessage(message);
|
|
294
298
|
}
|
|
@@ -329,8 +333,10 @@ function positionFromError(error, script, phase) {
|
|
|
329
333
|
};
|
|
330
334
|
}
|
|
331
335
|
async function main() {
|
|
332
|
-
const
|
|
333
|
-
|
|
336
|
+
const idFactory = data.idLabel != null ? countingFactory(data.idLabel) : void 0;
|
|
337
|
+
const session = new EntityEditSandboxSession({
|
|
338
|
+
docId: data.docId,
|
|
339
|
+
idFactory,
|
|
334
340
|
entityState: data.entityState,
|
|
335
341
|
domainIdFactory: domainIdFactory(data.idLabel),
|
|
336
342
|
onEntry: (entry) => post({
|
|
@@ -353,8 +359,7 @@ async function main() {
|
|
|
353
359
|
t: "entity-truncate",
|
|
354
360
|
index
|
|
355
361
|
})
|
|
356
|
-
};
|
|
357
|
-
const session = new EntityEditSandboxSession(data.document, options);
|
|
362
|
+
});
|
|
358
363
|
const wrapped = `(async (entities, relations, checkpoint, rollbackTo, inputs, console, rgetAssetFromEntity) => {${data.script}\n})`;
|
|
359
364
|
const ctx = vm.createContext(Object.create(null));
|
|
360
365
|
let run;
|
|
@@ -379,10 +384,12 @@ async function main() {
|
|
|
379
384
|
try {
|
|
380
385
|
const invoke = run;
|
|
381
386
|
post({ t: "ready" });
|
|
382
|
-
await invoke(session.entities, session.relations, session.checkpoint, session.rollbackTo, data.inputs ?? {}, session.console, (entityId) => {
|
|
387
|
+
await invoke(session.entities, session.relations, session.checkpoint, session.rollbackTo, data.inputs ?? {}, session.console, async (entityId) => {
|
|
388
|
+
await session.persistAudioScriptAssets(writeEntityAsset);
|
|
383
389
|
return session.rgetAssetFromEntity(entityId, loadEntityAsset);
|
|
384
390
|
});
|
|
385
391
|
await session.prepareEntityAssets(loadEntityAsset);
|
|
392
|
+
await session.persistAudioScriptAssets(writeEntityAsset);
|
|
386
393
|
} catch (error) {
|
|
387
394
|
post({
|
|
388
395
|
t: "fail",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-entry.mjs","names":[],"sources":["../src/entity/entity-asset.ts","../src/sandbox/entity-script-session.ts","../src/sandbox/worker-entry.ts"],"sourcesContent":["import type { JsonValue, SandboxEntity } from './entity-contract.ts';\n\n/** Immutable resource content resolved by the host for a document Entity. */\nexport interface EntityAssetContent {\n assetId: string;\n content: JsonValue;\n}\n\n/** Host-only I/O. The sandbox supplies an Entity, never an arbitrary Asset query. */\nexport type EntityAssetLoader = (docId: string, entity: SandboxEntity) => Promise<EntityAssetContent>;\n\nexport interface CaptionAssetSegment {\n text: string;\n start_time_ms: number;\n end_time_ms: number;\n}\n\n/** MCAP's output_caption JSON contract; unknown formats never become invented captions. */\nexport function captionAssetSegments(content: JsonValue): CaptionAssetSegment[] {\n if (!content || typeof content !== 'object' || Array.isArray(content) || !Array.isArray(content.segments))\n throw new Error('Caption Asset must contain an output_caption object with segments');\n if (!content.segments.length) throw new Error('Caption Asset contains no speech segments');\n return content.segments.map((value) => {\n if (\n !value ||\n typeof value !== 'object' ||\n Array.isArray(value) ||\n typeof value.text !== 'string' ||\n !value.text.trim() ||\n !Number.isSafeInteger(value.start_time_ms) ||\n !Number.isSafeInteger(value.end_time_ms) ||\n (value.start_time_ms as number) < 0 ||\n (value.end_time_ms as number) <= (value.start_time_ms as number)\n )\n throw new Error('Caption Asset has invalid text or millisecond timing');\n return { text: value.text, start_time_ms: value.start_time_ms as number, end_time_ms: value.end_time_ms as number };\n });\n}\n","import {\n LoroEntityDocument,\n projectEntityTimeline,\n base64ToBytes,\n bytesToBase64,\n assertCanonicalEditorResources,\n assertMediaAssetWritePolicy,\n type VideoDocument,\n} from '@mengine/medeo-client';\nimport { type EntityRelationRows } from '@mengine/medeo-dsl';\n\nimport { captionAssetSegments, type EntityAssetContent } from '../entity/entity-asset.ts';\nimport type {\n BusinessEntityFacade,\n BusinessRelationFacade,\n EntitySandboxCheckpoint,\n SandboxEntity,\n} from '../entity/entity-contract.ts';\nimport { EntitySandbox, toDslRows, type DomainIdFactory } from '../entity/entity-sandbox.ts';\nimport { businessFacades } from './business-facades.ts';\nimport type { ChangePlan, ConsoleShim, EditSandboxSessionOptions } from './script-session.ts';\n\nconst LOG_LINE_MAX = 2000;\nconst LOG_LINE_CAP = 1000;\nconst LOG_BYTE_CAP = 64 * 1024;\nconst TRUNCATE_MARK = '[truncated]';\nconst LOG_TRUNCATED = '[log truncated]';\n\n/** Entity/relation script session; compilation retains the ordered operation journal. */\nexport class EntityEditSandboxSession {\n private readonly document: VideoDocument;\n private readonly entitySandbox: EntitySandbox;\n private readonly baseRows: EntityRelationRows;\n private readonly domainIdFactory: DomainIdFactory;\n private readonly logs: string[] = [];\n private readonly onLog: ((line: string) => void) | undefined;\n private logBytes = 0;\n private readonly resolvedCaptionAssets = new Set<string>();\n private logCapped = false;\n\n readonly entities: BusinessEntityFacade;\n readonly relations: BusinessRelationFacade;\n readonly console: ConsoleShim;\n readonly checkpoint: () => EntitySandboxCheckpoint;\n readonly rollbackTo: (cp: EntitySandboxCheckpoint) => void;\n\n constructor(document: VideoDocument, options?: EditSandboxSessionOptions) {\n this.document = structuredClone(document);\n this.baseRows = toDslRows(\n options?.entityState ?? { revision: 0, audioScriptEntityId: null, entities: [], relations: [] },\n );\n this.domainIdFactory =\n options?.domainIdFactory ??\n (() => {\n throw new Error('Entity id factory is unavailable in this sandbox host');\n });\n this.onLog = options?.onLog;\n this.entitySandbox = new EntitySandbox({\n state: options?.entityState,\n idFactory: this.domainIdFactory,\n onCommand: options?.onEntityCommand,\n onTruncate: options?.onEntityTruncate,\n });\n\n const business = businessFacades(this.entitySandbox.entities, this.entitySandbox.relations);\n this.entities = business.entities;\n this.relations = business.relations;\n this.console = this.buildConsoleShim();\n const checkpoints = new Map<EntitySandboxCheckpoint, number>();\n this.checkpoint = () => {\n const token = Object.freeze({}) as EntitySandboxCheckpoint;\n checkpoints.set(token, this.entitySandbox.commandCount);\n return token;\n };\n this.rollbackTo = (cp) => {\n const index = checkpoints.get(cp);\n if (index === undefined) throw new Error('Invalid or expired sandbox checkpoint');\n this.entitySandbox.rollbackTo(index);\n let later = false;\n for (const token of checkpoints.keys()) {\n if (later) checkpoints.delete(token);\n if (token === cp) later = true;\n }\n };\n }\n\n /** Resolve only the resource attached to this Entity; I/O remains in the parent host. */\n async rgetAssetFromEntity(\n entityId: string,\n load: (entity: SandboxEntity) => Promise<EntityAssetContent>,\n ): Promise<EntityAssetContent> {\n const entity = this.entitySandbox.entities.get(entityId);\n if (!entity || entity.entity_kind === 'asset') throw new Error(`Business Entity not found: ${entityId}`);\n const external = entity.payload.external;\n if (!external || typeof external !== 'object' || Array.isArray(external) || typeof external.key !== 'string')\n throw new Error(`Entity ${entityId} has no attached Asset`);\n const assetId = external.key;\n const result = await load(entity);\n if (result.assetId !== external.key) throw new Error('Host returned a different Entity Asset');\n const current = this.entitySandbox.entities.get(entityId);\n if (!current || JSON.stringify(current.payload.external) !== JSON.stringify(external))\n throw new Error('Entity resource changed during its read');\n if (entity.entity_kind === 'caption' && !this.initializedAsset(entityId, external.key)) {\n const timed = captionAssetSegments(result.content);\n const segments = timed.map((segment, index) => ({\n segmentId: `asset:${assetId}:${index}`,\n text: segment.text,\n }));\n // An explicit composition determines the owner, never the panel selection.\n // Resource-only captions establish their own independent complete script.\n const bases = current.payload.baseEntityIds as string[] | undefined;\n const scriptId = bases?.length\n ? this.entitySandbox.captionAudioScriptId(entityId)\n : this.entitySandbox.entities.create({ entity_kind: 'audio-script', payload: { segments: [] } });\n const script = this.entitySandbox.entities.get(scriptId)!;\n const existing = script.payload.segments as { segmentId: string; text: string }[];\n const additions = segments.filter((segment) => !existing.some((item) => item.segmentId === segment.segmentId));\n this.entitySandbox.entities.update({ entity_id: scriptId, payload: { segments: [...existing, ...additions] } });\n const ranges = timed.map((segment, index) => ({\n segmentId: segments[index]!.segmentId,\n startMs: segment.start_time_ms,\n endMs: segment.end_time_ms,\n }));\n this.entitySandbox.entities.update({\n entity_id: entityId,\n payload: {\n baseEntityIds: bases?.length ? bases : [scriptId],\n selections: segments.map(({ segmentId }) => ({ segmentId })),\n extent: {\n kind: 'bounded',\n start: Math.min(...ranges.map((r) => r.startMs)),\n end: Math.max(...ranges.map((r) => r.endMs)),\n },\n sampling: 'native',\n coordinateSpace: 'milliseconds',\n segmentRanges: ranges,\n },\n });\n const markerId = this.entitySandbox.entities.create({\n entity_kind: 'sequence-marker',\n payload: {\n sourceRange: {\n start: Math.min(...ranges.map((r) => r.startMs)),\n end: Math.max(...ranges.map((r) => r.endMs)),\n },\n duration: { mode: 'from-source' },\n segmentRanges: ranges,\n },\n });\n this.entitySandbox.relations.link({\n relation_kind: 'audio-script-marker',\n endpoint_0_entity_id: scriptId,\n endpoint_1_entity_id: markerId,\n });\n }\n this.resolvedCaptionAssets.add(`${entityId}:${assetId}`);\n return result;\n }\n\n private initializedAsset(entityId: string, assetId: string): boolean {\n const current = this.entitySandbox.entities.get(entityId);\n if (\n this.resolvedCaptionAssets.has(`${entityId}:${assetId}`) &&\n Array.isArray(current?.payload.selections) &&\n Array.isArray(current?.payload.baseEntityIds)\n )\n return true;\n const baseline = this.baseRows.entities.find((row) => row.entityId === entityId);\n const external = baseline?.payload.external;\n return (\n !!external &&\n typeof external === 'object' &&\n !Array.isArray(external) &&\n 'key' in external &&\n external.key === assetId\n );\n }\n\n /** Finish unawaited Caption initialization before validation; no partial rows are published. */\n async prepareEntityAssets(load: (entity: SandboxEntity) => Promise<EntityAssetContent>): Promise<void> {\n for (const entity of this.entitySandbox.entities.list()) {\n const external = entity.payload.external;\n if (\n entity.entity_kind === 'caption' &&\n external &&\n typeof external === 'object' &&\n !Array.isArray(external) &&\n typeof external.key === 'string' &&\n !this.initializedAsset(entity.entity_id, external.key)\n )\n await this.rgetAssetFromEntity(entity.entity_id, load);\n }\n }\n\n buildPlan(baseVersion: string): ChangePlan {\n const entityPlan = this.entitySandbox.buildPlan();\n assertCanonicalEditorResources(toDslRows(entityPlan.rows));\n assertMediaAssetWritePolicy(this.baseRows, toDslRows(entityPlan.rows));\n if (entityPlan.rows.loroSnapshot) projectEntityTimeline(toDslRows(entityPlan.rows), this.document.meta);\n return {\n ...(entityPlan.rows.loroSnapshot\n ? {\n loro_update: bytesToBase64(this.compileJournal(entityPlan)),\n }\n : {}),\n plan_kind: 'entities',\n doc_id: this.document.meta.draft_id ?? '',\n base_version: baseVersion,\n ops: [],\n entity_base_revision: entityPlan.base_revision,\n entity_commands: entityPlan.commands,\n entity_rows: entityPlan.rows,\n deleted_entity_ids: entityPlan.deleted_entity_ids,\n deleted_relation_ids: entityPlan.deleted_relation_ids,\n preview: this.entitySandbox.renderPreview(),\n logs: this.logs.slice(),\n };\n }\n\n private compileJournal(plan: ReturnType<EntitySandbox['buildPlan']>): Uint8Array {\n const editor = LoroEntityDocument.fromSnapshot(base64ToBytes(plan.rows.loroSnapshot!), (state) => {\n assertCanonicalEditorResources(state.rows);\n projectEntityTimeline(state.rows, this.document.meta);\n });\n return editor.transact((draft) => {\n for (const command of plan.commands) {\n switch (command.kind) {\n case 'create-entity': {\n const rows = toDslRows({\n revision: 0,\n audioScriptEntityId: null,\n entities: [command.entity],\n relations: [],\n });\n draft.create(rows.entities[0]!);\n if (\n command.entity.entity_kind === 'audio-script' &&\n command.entity.entity_id === plan.rows.audioScriptEntityId\n )\n draft.attach('audioScriptEntityId', command.entity.entity_id);\n break;\n }\n case 'update-entity':\n draft.replaceOwned(command.entity_id, command.payload);\n break;\n case 'change-entity':\n draft.change(command.entity_id, command.changes);\n break;\n case 'delete-entity':\n draft.delete(command.entity_id);\n break;\n case 'link-relation': {\n const rows = toDslRows({\n revision: 0,\n audioScriptEntityId: null,\n entities: [],\n relations: [command.relation],\n });\n draft.link(rows.relations[0]!);\n break;\n }\n case 'change-relation':\n draft.changeRelation(command.relation_id, command.changes);\n break;\n case 'unlink-relation':\n draft.unlink(command.relation_id);\n break;\n }\n }\n draft.reconcileOrder(toDslRows(plan.rows));\n });\n }\n\n getLogs(): readonly string[] {\n return this.logs;\n }\n\n private appendLog(line: string): void {\n if (this.logCapped) return;\n if (this.logs.length >= LOG_LINE_CAP || this.logBytes >= LOG_BYTE_CAP) {\n this.logs.push(LOG_TRUNCATED);\n this.logCapped = true;\n this.onLog?.(LOG_TRUNCATED);\n return;\n }\n const out =\n line.length > LOG_LINE_MAX ? `${line.slice(0, LOG_LINE_MAX - TRUNCATE_MARK.length)}${TRUNCATE_MARK}` : line;\n this.logs.push(out);\n this.logBytes += out.length;\n this.onLog?.(out);\n }\n\n private buildConsoleShim(): ConsoleShim {\n const write = (...args: unknown[]) => this.appendLog(args.map(formatLogArg).join(' '));\n return { log: write, info: write, warn: write, error: write };\n }\n}\n\nfunction formatLogArg(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean' || value === null || value === undefined) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unstringifiable]';\n }\n}\n","/// <reference types=\"node\" />\nimport { randomUUID } from 'node:crypto';\nimport vm from 'node:vm';\nimport { parentPort, workerData } from 'node:worker_threads';\n\nimport type { JournalEntry, PartIdFactory, VideoDocument } from '@mengine/medeo-client';\n\nimport type { EntityAssetContent } from '../entity/entity-asset.ts';\nimport type { SandboxEntity } from '../entity/entity-contract.ts';\nimport type { EntityCommand, EntityStoreSnapshot } from '../entity/entity-contract.ts';\nimport type { DomainIdFactory } from '../entity/entity-sandbox.ts';\nimport { EntityEditSandboxSession } from './entity-script-session.ts';\nimport { type EditSandboxSessionOptions } from './script-session.ts';\n\n/**\n * Node worker entry for trusted edit scripts.\n *\n * Spawns the requested sandbox session, runs the agent script in a bare `vm`\n * context (no fetch/process/setTimeout), and streams journals + logs to the\n * host so hard timeout / OOM termination still preserves partial products.\n */\n\nexport interface WorkerData {\n document: VideoDocument;\n script: string;\n inputs?: Record<string, unknown>;\n entityState?: EntityStoreSnapshot;\n idLabel?: string;\n}\n\ntype HostMessage =\n | { t: 'entity-asset'; requestId: number; entity: SandboxEntity }\n | { t: 'ready' }\n | { t: 'entry'; entry: JournalEntry }\n | { t: 'entity-entry'; command: EntityCommand }\n | { t: 'log'; line: string }\n | { t: 'truncate'; index: number }\n | { t: 'entity-truncate'; index: number }\n | {\n t: 'done';\n preview: string;\n opsCount: number;\n entityCommandsCount: number;\n loroUpdate?: string;\n entityBaseRevision: number;\n entityRows?: EntityStoreSnapshot;\n deletedEntityIds: readonly string[];\n deletedRelationIds: readonly string[];\n planKind: 'timeline' | 'entities';\n }\n | {\n t: 'fail';\n phase: 'parse' | 'runtime';\n error: { message: string; line?: number; column?: number; stack?: string };\n };\n\nconst data = workerData as WorkerData;\nif (parentPort == null) {\n throw new Error('worker-entry must run inside a worker_threads Worker');\n}\nconst port = parentPort;\nlet requestId = 0;\nconst pending = new Map<number, { resolve: (result: EntityAssetContent) => void; reject: (error: Error) => void }>();\nport.on('message', (message: { t: string; requestId: number; result: EntityAssetContent; error?: string }) => {\n if (message.t !== 'entity-asset-result') return;\n const waiter = pending.get(message.requestId);\n pending.delete(message.requestId);\n if (message.error) waiter?.reject(new Error(message.error));\n else waiter?.resolve(message.result);\n});\nfunction loadEntityAsset(entity: SandboxEntity): Promise<EntityAssetContent> {\n return new Promise((resolve, reject) => {\n const id = ++requestId;\n pending.set(id, { resolve, reject });\n port.postMessage({ t: 'entity-asset', requestId: id, entity });\n });\n}\n\nfunction post(message: HostMessage): void {\n port.postMessage(message);\n}\n\nfunction countingFactory(label: string): PartIdFactory {\n let n = 0;\n return (prefix) => `${prefix}_${label}${++n}`;\n}\n\nfunction domainIdFactory(label?: string): DomainIdFactory {\n let n = 0;\n return (prefix) => `${prefix}_${label == null ? randomUUID() : `${label}${++n}`}`;\n}\n\n/** Extract script line/column from the first `agent-script.js` stack frame. */\nfunction positionFromError(\n error: unknown,\n script?: string,\n phase?: 'parse' | 'runtime',\n): { line?: number; column?: number; stack?: string; message: string } {\n // Duck-type: vm SyntaxError in a worker may fail `instanceof Error` across realms.\n const obj = error != null && typeof error === 'object' ? (error as Record<string, unknown>) : null;\n const message =\n obj != null && typeof obj.message === 'string'\n ? obj.message\n : error instanceof Error\n ? error.message\n : String(error);\n const stack = obj != null && typeof obj.stack === 'string' ? obj.stack : undefined;\n\n let line = typeof obj?.lineNumber === 'number' ? obj.lineNumber : undefined;\n let column = typeof obj?.columnNumber === 'number' ? obj.columnNumber : undefined;\n\n if (stack != null) {\n // Prefer the header form `agent-script.js:N` (SyntaxError) or `agent-script.js:N:M`.\n const match = /agent-script\\.js:(\\d+)(?::(\\d+))?/.exec(stack);\n if (match != null) {\n line = Number(match[1]);\n if (match[2] != null) column = Number(match[2]);\n }\n }\n\n // Parse-phase refinement: V8 often points at the token after an unclosed\n // `{`/`(`/`[`; walk back one line when the previous line ends that way so\n // the reported line matches the agent-authored incomplete construct.\n if (phase === 'parse' && script != null && line != null && line >= 2) {\n const lines = script.split('\\n');\n const prev = lines[line - 2];\n if (prev != null && /[{([]\\s*$/.test(prev)) {\n line = line - 1;\n column = prev.length;\n }\n }\n\n return { message, line, column, stack };\n}\n\nasync function main(): Promise<void> {\n const idFactory = data.idLabel != null ? countingFactory(data.idLabel) : undefined;\n const options: EditSandboxSessionOptions = {\n idFactory,\n entityState: data.entityState,\n domainIdFactory: domainIdFactory(data.idLabel),\n onEntry: (entry) => post({ t: 'entry', entry }),\n onEntityCommand: (command) => post({ t: 'entity-entry', command }),\n onLog: (line) => post({ t: 'log', line }),\n onTruncate: (index) => post({ t: 'truncate', index }),\n onEntityTruncate: (index) => post({ t: 'entity-truncate', index }),\n };\n const session = new EntityEditSandboxSession(data.document, options);\n\n // Prelude stays on the same physical line as script line 1 so stack line\n // numbers map 1:1 onto the agent script (no leading newline).\n const wrapped = `(async (entities, relations, checkpoint, rollbackTo, inputs, console, rgetAssetFromEntity) => {${data.script}\\n})`;\n\n const ctx = vm.createContext(Object.create(null) as Record<string, unknown>);\n\n let run: unknown;\n try {\n run = vm.runInContext(wrapped, ctx, { filename: 'agent-script.js' });\n } catch (error) {\n const pos = positionFromError(error, data.script, 'parse');\n post({ t: 'fail', phase: 'parse', error: pos });\n return;\n }\n\n if (typeof run !== 'function') {\n post({\n t: 'fail',\n phase: 'runtime',\n error: { message: 'agent script wrapper did not evaluate to a function' },\n });\n return;\n }\n\n try {\n const invoke = run as (\n entities: typeof session.entities,\n relations: typeof session.relations,\n checkpoint: typeof session.checkpoint,\n rollbackTo: typeof session.rollbackTo,\n inputs: Record<string, unknown>,\n console: typeof session.console,\n rgetAssetFromEntity: (entityId: string) => Promise<EntityAssetContent>,\n ) => Promise<unknown>;\n // Signal host that cold start is done; timeout wall-clock starts here.\n post({ t: 'ready' });\n await invoke(\n session.entities,\n session.relations,\n session.checkpoint,\n session.rollbackTo,\n data.inputs ?? {},\n session.console,\n (entityId) => {\n return session.rgetAssetFromEntity(entityId, loadEntityAsset);\n },\n );\n await session.prepareEntityAssets(loadEntityAsset);\n } catch (error) {\n const pos = positionFromError(error, data.script, 'runtime');\n post({ t: 'fail', phase: 'runtime', error: pos });\n return;\n }\n\n const plan = session.buildPlan('');\n post({\n t: 'done',\n ...(plan.loro_update ? { loroUpdate: plan.loro_update } : {}),\n preview: plan.preview,\n opsCount: plan.ops.length,\n entityCommandsCount: plan.entity_commands.length,\n entityBaseRevision: plan.entity_base_revision,\n ...(plan.entity_rows !== undefined ? { entityRows: plan.entity_rows } : {}),\n deletedEntityIds: plan.deleted_entity_ids ?? [],\n deletedRelationIds: plan.deleted_relation_ids ?? [],\n planKind: plan.plan_kind,\n });\n}\n\nmain().catch((error: unknown) => {\n const pos = positionFromError(error);\n post({ t: 'fail', phase: 'runtime', error: pos });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"worker-entry.mjs","names":[],"sources":["../src/entity/entity-asset.ts","../src/sandbox/entity-script-session.ts","../src/sandbox/worker-entry.ts"],"sourcesContent":["import type { JsonObject, JsonValue, SandboxEntity } from './entity-contract.ts';\n\n/** Immutable resource content resolved by the host for a document Entity. */\nexport interface EntityAssetContent {\n assetId: string;\n content: JsonValue;\n}\n\n/** Host-only I/O. The sandbox supplies an Entity, never an arbitrary Asset query. */\nexport type EntityAssetLoader = (docId: string, entity: SandboxEntity) => Promise<EntityAssetContent>;\n\n/** Program-only initial resource creation; never exposed as a sandbox API. */\nexport type EntityAssetWriter = (\n docId: string,\n entity: SandboxEntity,\n content: JsonValue,\n) => Promise<EntityAssetContent>;\n\nexport interface CaptionAssetSegment {\n text: string;\n start_time_ms: number;\n end_time_ms: number;\n}\n\n/** MCAP's output_caption JSON contract; unknown formats never become invented captions. */\nexport function captionAssetSegments(content: JsonValue): CaptionAssetSegment[] {\n if (!content || typeof content !== 'object' || Array.isArray(content) || !Array.isArray(content.segments))\n throw new Error('Caption Asset must contain an output_caption object with segments');\n if (!content.segments.length) throw new Error('Caption Asset contains no speech segments');\n return content.segments.map((value) => {\n if (\n !value ||\n typeof value !== 'object' ||\n Array.isArray(value) ||\n typeof value.text !== 'string' ||\n !value.text.trim() ||\n !Number.isSafeInteger(value.start_time_ms) ||\n !Number.isSafeInteger(value.end_time_ms) ||\n (value.start_time_ms as number) < 0 ||\n (value.end_time_ms as number) <= (value.start_time_ms as number)\n )\n throw new Error('Caption Asset has invalid text or millisecond timing');\n return { text: value.text, start_time_ms: value.start_time_ms as number, end_time_ms: value.end_time_ms as number };\n });\n}\n\n/**\n * Persisted voiceover Audio facts, resolved by the host rather than inferred\n * from transcript timing.\n *\n * A returned voice-library descriptor is validated but never written here: the\n * timbre is its own Voice entity linked by a `voice-timbre` Relation, so the\n * rendered Audio row stays resource-only.\n */\nexport function speechAssetFields(content: JsonValue): JsonObject {\n if (\n !content ||\n typeof content !== 'object' ||\n Array.isArray(content) ||\n typeof content.storageKey !== 'string' ||\n !content.storageKey.trim() ||\n !Number.isSafeInteger(content.durationMs) ||\n (content.durationMs as number) <= 0\n )\n throw new Error('Speech Asset requires factual storageKey and positive millisecond duration');\n const voice = content.voice;\n if (\n voice !== undefined &&\n (!voice ||\n typeof voice !== 'object' ||\n Array.isArray(voice) ||\n voice.system !== 'voice-library' ||\n typeof voice.key !== 'string' ||\n !voice.key.trim())\n )\n throw new Error('Speech Asset has an invalid voice-library identity');\n // Where the bytes live is a fact about the Asset; how long they play is a\n // fact about the Audio made from them.\n return { durationMs: content.durationMs };\n}\n\n/** The storage path the speech resource reports, destined for its Asset. */\nexport function speechAssetStorageKey(content: JsonValue): string {\n speechAssetFields(content);\n return (content as { storageKey: string }).storageKey;\n}\n","import {\n LoroEntityDocument,\n audioScriptAssetContent,\n audioScriptAssetFields,\n audioScriptAssetOf,\n projectEntityTimeline,\n base64ToBytes,\n bytesToBase64,\n assertCanonicalEditorResources,\n assertMediaAssetWritePolicy,\n} from '@mengine/medeo-client';\nimport type { EntityRelationRows } from '@mengine/medeo-dsl';\n\nimport { speechAssetFields, speechAssetStorageKey, type EntityAssetContent } from '../entity/entity-asset.ts';\nimport type {\n BusinessEntityFacade,\n BusinessRelationFacade,\n EntitySandboxCheckpoint,\n SandboxEntity,\n JsonObject,\n} from '../entity/entity-contract.ts';\nimport { EntitySandbox, toDslRows, type DomainIdFactory } from '../entity/entity-sandbox.ts';\nimport { businessFacades } from './business-facades.ts';\nimport type { ChangePlan, ConsoleShim, EditSandboxSessionOptions } from './script-session.ts';\n\nconst LOG_LINE_MAX = 2000;\nconst LOG_LINE_CAP = 1000;\nconst LOG_BYTE_CAP = 64 * 1024;\nconst TRUNCATE_MARK = '[truncated]';\nconst LOG_TRUNCATED = '[log truncated]';\n\n/** Entity/relation script session; compilation retains the ordered operation journal. */\nexport class EntityEditSandboxSession {\n private readonly docId: string;\n private readonly entitySandbox: EntitySandbox;\n private readonly baseRows: EntityRelationRows;\n private readonly domainIdFactory: DomainIdFactory;\n private readonly logs: string[] = [];\n private readonly onLog: ((line: string) => void) | undefined;\n private logBytes = 0;\n private readonly directScriptWrites = new Set<string>();\n private logCapped = false;\n\n readonly entities: BusinessEntityFacade;\n readonly relations: BusinessRelationFacade;\n readonly console: ConsoleShim;\n readonly checkpoint: () => EntitySandboxCheckpoint;\n readonly rollbackTo: (cp: EntitySandboxCheckpoint) => void;\n\n // The Entity sandbox edits Entity rows only; the legacy VideoDocument\n // projection is not an input to it (P7M14 separated content from identity).\n constructor(options?: EditSandboxSessionOptions) {\n this.docId = options?.docId ?? '';\n this.baseRows = toDslRows(\n options?.entityState ?? { revision: 0, audioScriptEntityId: null, entities: [], relations: [] },\n );\n this.domainIdFactory =\n options?.domainIdFactory ??\n (() => {\n throw new Error('Entity id factory is unavailable in this sandbox host');\n });\n this.onLog = options?.onLog;\n this.entitySandbox = new EntitySandbox({\n state: options?.entityState,\n idFactory: this.domainIdFactory,\n onCommand: options?.onEntityCommand,\n onTruncate: options?.onEntityTruncate,\n });\n\n const business = businessFacades(this.entitySandbox.entities, this.entitySandbox.relations, (id) =>\n this.directScriptWrites.add(id),\n );\n this.entities = business.entities;\n this.relations = business.relations;\n this.console = this.buildConsoleShim();\n const checkpoints = new Map<EntitySandboxCheckpoint, { index: number; scripts: Set<string> }>();\n this.checkpoint = () => {\n const token = Object.freeze({}) as EntitySandboxCheckpoint;\n checkpoints.set(token, { index: this.entitySandbox.commandCount, scripts: new Set(this.directScriptWrites) });\n return token;\n };\n this.rollbackTo = (cp) => {\n const index = checkpoints.get(cp);\n if (index === undefined) throw new Error('Invalid or expired sandbox checkpoint');\n this.entitySandbox.rollbackTo(index.index);\n this.directScriptWrites.clear();\n for (const id of index.scripts) this.directScriptWrites.add(id);\n let later = false;\n for (const token of checkpoints.keys()) {\n if (later) checkpoints.delete(token);\n if (token === cp) later = true;\n }\n };\n }\n\n /** Resolve only the resource attached to this Entity; I/O remains in the parent host. */\n async rgetAssetFromEntity(\n entityId: string,\n load: (entity: SandboxEntity) => Promise<EntityAssetContent>,\n ): Promise<EntityAssetContent> {\n const entity = this.entitySandbox.entities.get(entityId);\n if (!entity || entity.entity_kind === 'asset') throw new Error(`Business Entity not found: ${entityId}`);\n const locator = this.entitySandbox.assetOf(entityId);\n if (!locator || typeof locator.payload.key !== 'string')\n throw new Error(`Entity ${entityId} has no attached Asset`);\n const assetId = locator.payload.key;\n const result = await load(entity);\n if (result.assetId !== assetId) throw new Error('Host returned a different Entity Asset');\n const current = this.entitySandbox.entities.get(entityId);\n if (!current || this.entitySandbox.assetOf(entityId)?.entity_id !== locator.entity_id)\n throw new Error('Entity resource changed during its read');\n if (entity.entity_kind === 'audio' && locator.payload.system === 'memota-speech') {\n const fields = speechAssetFields(result.content);\n // Host declarations initialize nested facts; native compilation writes only\n // their changed leaves against this session's original causal baseline.\n if (Object.entries(fields).some(([key, value]) => JSON.stringify(current.payload[key]) !== JSON.stringify(value)))\n this.entitySandbox.entities.declareFields({ entity_id: entityId, payload: fields });\n this.entitySandbox.entities.declareFields({\n entity_id: locator.entity_id,\n payload: { storageKey: speechAssetStorageKey(result.content) },\n });\n }\n return result;\n }\n\n /** A speech resource is hydrated once its Asset names where the bytes live. */\n private initializedSpeech(asset: SandboxEntity): boolean {\n return typeof asset.payload.storageKey === 'string' && asset.payload.storageKey.trim() !== '';\n }\n\n /** Finish resource initialization before validation; no partial rows are published. */\n async prepareEntityAssets(load: (entity: SandboxEntity) => Promise<EntityAssetContent>): Promise<void> {\n for (const entity of this.entitySandbox.entities.list()) {\n const locator = this.entitySandbox.assetOf(entity.entity_id);\n if (typeof locator?.payload.key !== 'string') continue;\n if (\n entity.entity_kind === 'audio' &&\n locator.payload.system === 'memota-speech' &&\n !this.initializedSpeech(locator)\n )\n await this.rgetAssetFromEntity(entity.entity_id, load);\n }\n }\n\n /** Direct script writes save a resource before the entity graph can be committed. */\n async persistAudioScriptAssets(\n write: (\n entity: SandboxEntity,\n content: import('../entity/entity-contract.ts').JsonValue,\n ) => Promise<EntityAssetContent>,\n ): Promise<void> {\n for (const entity of this.entitySandbox.entities.list()) {\n if (entity.entity_kind !== 'audio-script') continue;\n // Existing script resources are versioned by the server after native merge.\n const rows = this.entitySandbox.rows();\n if (audioScriptAssetOf(rows, entity.entity_id) !== undefined || !this.directScriptWrites.has(entity.entity_id))\n continue;\n const content = audioScriptAssetContent(entity.payload) as JsonObject;\n const saved = await write(entity, content);\n if (JSON.stringify(saved.content) !== JSON.stringify(content))\n throw new Error('AudioScript resource writer changed the submitted content');\n // The bytes are named on an Asset entity; the script keeps the fingerprint.\n const assetEntityId = this.entitySandbox.entities.ensureAsset({ system: 'memota', key: saved.assetId });\n this.entitySandbox.relations.link({\n relation_kind: 'from-asset',\n endpoint_0_entity_id: entity.entity_id,\n endpoint_1_entity_id: assetEntityId,\n });\n this.entitySandbox.entities.declareFields({\n entity_id: entity.entity_id,\n payload: audioScriptAssetFields(entity.payload) as JsonObject,\n });\n }\n }\n\n buildPlan(baseVersion: string): ChangePlan {\n const entityPlan = this.entitySandbox.buildPlan();\n assertCanonicalEditorResources(toDslRows(entityPlan.rows));\n assertMediaAssetWritePolicy(this.baseRows, toDslRows(entityPlan.rows));\n if (entityPlan.rows.loroSnapshot) projectEntityTimeline(toDslRows(entityPlan.rows));\n return {\n ...(entityPlan.rows.loroSnapshot\n ? {\n loro_update: bytesToBase64(this.compileJournal(entityPlan)),\n }\n : {}),\n plan_kind: 'entities',\n doc_id: this.docId,\n base_version: baseVersion,\n ops: [],\n entity_base_revision: entityPlan.base_revision,\n entity_commands: entityPlan.commands,\n entity_rows: entityPlan.rows,\n deleted_entity_ids: entityPlan.deleted_entity_ids,\n deleted_relation_ids: entityPlan.deleted_relation_ids,\n preview: this.entitySandbox.renderPreview(),\n logs: this.logs.slice(),\n };\n }\n\n private compileJournal(plan: ReturnType<EntitySandbox['buildPlan']>): Uint8Array {\n const editor = LoroEntityDocument.fromSnapshot(base64ToBytes(plan.rows.loroSnapshot!), (state) => {\n assertCanonicalEditorResources(state.rows);\n projectEntityTimeline(state.rows);\n });\n return editor.transact((draft) => {\n for (const command of plan.commands) {\n switch (command.kind) {\n case 'create-entity': {\n const rows = toDslRows({\n revision: 0,\n audioScriptEntityId: null,\n entities: [command.entity],\n relations: [],\n });\n draft.create(rows.entities[0]!);\n if (\n command.entity.entity_kind === 'audio-script' &&\n command.entity.entity_id === plan.rows.audioScriptEntityId\n )\n draft.attach('audioScriptEntityId', command.entity.entity_id);\n break;\n }\n case 'update-entity':\n draft.replaceOwned(command.entity_id, command.payload);\n break;\n case 'change-entity':\n draft.change(command.entity_id, command.changes);\n break;\n case 'delete-entity':\n draft.delete(command.entity_id);\n break;\n case 'link-relation': {\n const rows = toDslRows({\n revision: 0,\n audioScriptEntityId: null,\n entities: [],\n relations: [command.relation],\n });\n draft.link(rows.relations[0]!);\n break;\n }\n case 'change-relation':\n draft.changeRelation(command.relation_id, command.changes);\n break;\n case 'unlink-relation':\n draft.unlink(command.relation_id);\n break;\n }\n }\n draft.reconcileOrder(toDslRows(plan.rows));\n });\n }\n\n getLogs(): readonly string[] {\n return this.logs;\n }\n\n private appendLog(line: string): void {\n if (this.logCapped) return;\n if (this.logs.length >= LOG_LINE_CAP || this.logBytes >= LOG_BYTE_CAP) {\n this.logs.push(LOG_TRUNCATED);\n this.logCapped = true;\n this.onLog?.(LOG_TRUNCATED);\n return;\n }\n const out =\n line.length > LOG_LINE_MAX ? `${line.slice(0, LOG_LINE_MAX - TRUNCATE_MARK.length)}${TRUNCATE_MARK}` : line;\n this.logs.push(out);\n this.logBytes += out.length;\n this.onLog?.(out);\n }\n\n private buildConsoleShim(): ConsoleShim {\n const write = (...args: unknown[]) => this.appendLog(args.map(formatLogArg).join(' '));\n return { log: write, info: write, warn: write, error: write };\n }\n}\n\nfunction formatLogArg(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean' || value === null || value === undefined) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unstringifiable]';\n }\n}\n","/// <reference types=\"node\" />\nimport { randomUUID } from 'node:crypto';\nimport vm from 'node:vm';\nimport { parentPort, workerData } from 'node:worker_threads';\n\nimport type { JournalEntry, PartIdFactory, VideoDocument } from '@mengine/medeo-client';\n\nimport type { EntityAssetContent } from '../entity/entity-asset.ts';\nimport type { SandboxEntity } from '../entity/entity-contract.ts';\nimport type { EntityCommand, EntityStoreSnapshot } from '../entity/entity-contract.ts';\nimport type { DomainIdFactory } from '../entity/entity-sandbox.ts';\nimport { EntityEditSandboxSession } from './entity-script-session.ts';\nimport { type EditSandboxSessionOptions } from './script-session.ts';\n\n/**\n * Node worker entry for trusted edit scripts.\n *\n * Spawns the requested sandbox session, runs the agent script in a bare `vm`\n * context (no fetch/process/setTimeout), and streams journals + logs to the\n * host so hard timeout / OOM termination still preserves partial products.\n */\n\nexport interface WorkerData {\n docId: string;\n document: VideoDocument;\n script: string;\n inputs?: Record<string, unknown>;\n entityState?: EntityStoreSnapshot;\n idLabel?: string;\n}\n\ntype HostMessage =\n | { t: 'entity-asset'; requestId: number; entity: SandboxEntity }\n | { t: 'write-entity-asset'; requestId: number; entity: SandboxEntity; content: EntityAssetContent['content'] }\n | { t: 'ready' }\n | { t: 'entry'; entry: JournalEntry }\n | { t: 'entity-entry'; command: EntityCommand }\n | { t: 'log'; line: string }\n | { t: 'truncate'; index: number }\n | { t: 'entity-truncate'; index: number }\n | {\n t: 'done';\n preview: string;\n opsCount: number;\n entityCommandsCount: number;\n loroUpdate?: string;\n entityBaseRevision: number;\n entityRows?: EntityStoreSnapshot;\n deletedEntityIds: readonly string[];\n deletedRelationIds: readonly string[];\n planKind: 'timeline' | 'entities';\n }\n | {\n t: 'fail';\n phase: 'parse' | 'runtime';\n error: { message: string; line?: number; column?: number; stack?: string };\n };\n\nconst data = workerData as WorkerData;\nif (parentPort == null) {\n throw new Error('worker-entry must run inside a worker_threads Worker');\n}\nconst port = parentPort;\nlet requestId = 0;\nconst pending = new Map<number, { resolve: (result: EntityAssetContent) => void; reject: (error: Error) => void }>();\nport.on('message', (message: { t: string; requestId: number; result: EntityAssetContent; error?: string }) => {\n if (message.t !== 'entity-asset-result') return;\n const waiter = pending.get(message.requestId);\n pending.delete(message.requestId);\n if (message.error) waiter?.reject(new Error(message.error));\n else waiter?.resolve(message.result);\n});\nfunction loadEntityAsset(entity: SandboxEntity): Promise<EntityAssetContent> {\n return new Promise((resolve, reject) => {\n const id = ++requestId;\n pending.set(id, { resolve, reject });\n port.postMessage({ t: 'entity-asset', requestId: id, entity });\n });\n}\n\nfunction writeEntityAsset(entity: SandboxEntity, content: EntityAssetContent['content']): Promise<EntityAssetContent> {\n return new Promise((resolve, reject) => {\n const id = ++requestId;\n pending.set(id, { resolve, reject });\n port.postMessage({ t: 'write-entity-asset', requestId: id, entity, content });\n });\n}\n\nfunction post(message: HostMessage): void {\n port.postMessage(message);\n}\n\nfunction countingFactory(label: string): PartIdFactory {\n let n = 0;\n return (prefix) => `${prefix}_${label}${++n}`;\n}\n\nfunction domainIdFactory(label?: string): DomainIdFactory {\n let n = 0;\n return (prefix) => `${prefix}_${label == null ? randomUUID() : `${label}${++n}`}`;\n}\n\n/** Extract script line/column from the first `agent-script.js` stack frame. */\nfunction positionFromError(\n error: unknown,\n script?: string,\n phase?: 'parse' | 'runtime',\n): { line?: number; column?: number; stack?: string; message: string } {\n // Duck-type: vm SyntaxError in a worker may fail `instanceof Error` across realms.\n const obj = error != null && typeof error === 'object' ? (error as Record<string, unknown>) : null;\n const message =\n obj != null && typeof obj.message === 'string'\n ? obj.message\n : error instanceof Error\n ? error.message\n : String(error);\n const stack = obj != null && typeof obj.stack === 'string' ? obj.stack : undefined;\n\n let line = typeof obj?.lineNumber === 'number' ? obj.lineNumber : undefined;\n let column = typeof obj?.columnNumber === 'number' ? obj.columnNumber : undefined;\n\n if (stack != null) {\n // Prefer the header form `agent-script.js:N` (SyntaxError) or `agent-script.js:N:M`.\n const match = /agent-script\\.js:(\\d+)(?::(\\d+))?/.exec(stack);\n if (match != null) {\n line = Number(match[1]);\n if (match[2] != null) column = Number(match[2]);\n }\n }\n\n // Parse-phase refinement: V8 often points at the token after an unclosed\n // `{`/`(`/`[`; walk back one line when the previous line ends that way so\n // the reported line matches the agent-authored incomplete construct.\n if (phase === 'parse' && script != null && line != null && line >= 2) {\n const lines = script.split('\\n');\n const prev = lines[line - 2];\n if (prev != null && /[{([]\\s*$/.test(prev)) {\n line = line - 1;\n column = prev.length;\n }\n }\n\n return { message, line, column, stack };\n}\n\nasync function main(): Promise<void> {\n const idFactory = data.idLabel != null ? countingFactory(data.idLabel) : undefined;\n const options: EditSandboxSessionOptions = {\n docId: data.docId,\n idFactory,\n entityState: data.entityState,\n domainIdFactory: domainIdFactory(data.idLabel),\n onEntry: (entry) => post({ t: 'entry', entry }),\n onEntityCommand: (command) => post({ t: 'entity-entry', command }),\n onLog: (line) => post({ t: 'log', line }),\n onTruncate: (index) => post({ t: 'truncate', index }),\n onEntityTruncate: (index) => post({ t: 'entity-truncate', index }),\n };\n const session = new EntityEditSandboxSession(options);\n\n // Prelude stays on the same physical line as script line 1 so stack line\n // numbers map 1:1 onto the agent script (no leading newline).\n const wrapped = `(async (entities, relations, checkpoint, rollbackTo, inputs, console, rgetAssetFromEntity) => {${data.script}\\n})`;\n\n const ctx = vm.createContext(Object.create(null) as Record<string, unknown>);\n\n let run: unknown;\n try {\n run = vm.runInContext(wrapped, ctx, { filename: 'agent-script.js' });\n } catch (error) {\n const pos = positionFromError(error, data.script, 'parse');\n post({ t: 'fail', phase: 'parse', error: pos });\n return;\n }\n\n if (typeof run !== 'function') {\n post({\n t: 'fail',\n phase: 'runtime',\n error: { message: 'agent script wrapper did not evaluate to a function' },\n });\n return;\n }\n\n try {\n const invoke = run as (\n entities: typeof session.entities,\n relations: typeof session.relations,\n checkpoint: typeof session.checkpoint,\n rollbackTo: typeof session.rollbackTo,\n inputs: Record<string, unknown>,\n console: typeof session.console,\n rgetAssetFromEntity: (entityId: string) => Promise<EntityAssetContent>,\n ) => Promise<unknown>;\n // Signal host that cold start is done; timeout wall-clock starts here.\n post({ t: 'ready' });\n await invoke(\n session.entities,\n session.relations,\n session.checkpoint,\n session.rollbackTo,\n data.inputs ?? {},\n session.console,\n async (entityId) => {\n await session.persistAudioScriptAssets(writeEntityAsset);\n return session.rgetAssetFromEntity(entityId, loadEntityAsset);\n },\n );\n await session.prepareEntityAssets(loadEntityAsset);\n await session.persistAudioScriptAssets(writeEntityAsset);\n } catch (error) {\n const pos = positionFromError(error, data.script, 'runtime');\n post({ t: 'fail', phase: 'runtime', error: pos });\n return;\n }\n\n const plan = session.buildPlan('');\n post({\n t: 'done',\n ...(plan.loro_update ? { loroUpdate: plan.loro_update } : {}),\n preview: plan.preview,\n opsCount: plan.ops.length,\n entityCommandsCount: plan.entity_commands.length,\n entityBaseRevision: plan.entity_base_revision,\n ...(plan.entity_rows !== undefined ? { entityRows: plan.entity_rows } : {}),\n deletedEntityIds: plan.deleted_entity_ids ?? [],\n deletedRelationIds: plan.deleted_relation_ids ?? [],\n planKind: plan.plan_kind,\n });\n}\n\nmain().catch((error: unknown) => {\n const pos = positionFromError(error);\n post({ t: 'fail', phase: 'runtime', error: pos });\n});\n"],"mappings":"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"}
|