@vosjs/shared 0.2.0 → 0.4.0
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 +18 -17
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -26
- package/dist/acquisition.d.ts +0 -59
- package/dist/acquisition.js +0 -92
- package/dist/acquisition.js.map +0 -1
- package/dist/backdrops.d.ts +0 -29
- package/dist/backdrops.js +0 -6
- package/dist/backdrops.js.map +0 -1
- package/dist/chunk-K7EIJSYQ.js +0 -1
- package/dist/chunk-K7EIJSYQ.js.map +0 -1
- package/dist/chunk-RDD5SU6G.js +0 -25
- package/dist/chunk-RDD5SU6G.js.map +0 -1
- package/dist/diff/index.d.ts +0 -65
- package/dist/diff/index.js +0 -568
- package/dist/diff/index.js.map +0 -1
- package/dist/limits.d.ts +0 -76
- package/dist/limits.js +0 -59
- package/dist/limits.js.map +0 -1
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/utils/index.d.ts +0 -23
- package/dist/utils/index.js +0 -13
- package/dist/utils/index.js.map +0 -1
package/dist/diff/index.js
DELETED
|
@@ -1,568 +0,0 @@
|
|
|
1
|
-
// src/diff/internal.ts
|
|
2
|
-
function isRecord(v) {
|
|
3
|
-
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
4
|
-
}
|
|
5
|
-
function deepEqual(a, b) {
|
|
6
|
-
if (Object.is(a, b)) return true;
|
|
7
|
-
if (typeof a !== typeof b) return false;
|
|
8
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
9
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
10
|
-
}
|
|
11
|
-
if (isRecord(a) && isRecord(b)) {
|
|
12
|
-
const ka = Object.keys(a);
|
|
13
|
-
const kb = Object.keys(b);
|
|
14
|
-
if (ka.length !== kb.length) return false;
|
|
15
|
-
return ka.every((k) => deepEqual(a[k], b[k]));
|
|
16
|
-
}
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
function shallowDiff(a, b, ignore = /* @__PURE__ */ new Set()) {
|
|
20
|
-
const props = {};
|
|
21
|
-
const keys = [.../* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])].sort();
|
|
22
|
-
for (const k of keys) {
|
|
23
|
-
if (ignore.has(k)) continue;
|
|
24
|
-
if (!deepEqual(a[k], b[k])) props[k] = [a[k], b[k]];
|
|
25
|
-
}
|
|
26
|
-
return Object.keys(props).length ? props : void 0;
|
|
27
|
-
}
|
|
28
|
-
function diffIdTrack(track, a, b) {
|
|
29
|
-
const ops = [];
|
|
30
|
-
const aById = new Map((a ?? []).map((n) => [String(n.id), n]));
|
|
31
|
-
const bById = new Map((b ?? []).map((n) => [String(n.id), n]));
|
|
32
|
-
for (const [id, node] of aById) {
|
|
33
|
-
if (!bById.has(id)) {
|
|
34
|
-
ops.push({ op: "remove", track, id, props: pickAnchor(node) });
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
for (const [id, node] of bById) {
|
|
38
|
-
const prev = aById.get(id);
|
|
39
|
-
if (!prev) {
|
|
40
|
-
ops.push({ op: "add", track, id, props: pickAnchor(node) });
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const props = shallowDiff(prev, node, ID_KEYS);
|
|
44
|
-
if (props) ops.push({ op: "modify", track, id, props });
|
|
45
|
-
}
|
|
46
|
-
return ops;
|
|
47
|
-
}
|
|
48
|
-
var ID_KEYS = /* @__PURE__ */ new Set(["id"]);
|
|
49
|
-
function pickAnchor(node) {
|
|
50
|
-
const out = {};
|
|
51
|
-
for (const k of ["in", "out", "at", "start", "kind", "key"]) {
|
|
52
|
-
if (node[k] !== void 0) out[k] = [void 0, node[k]];
|
|
53
|
-
}
|
|
54
|
-
return Object.keys(out).length ? out : void 0;
|
|
55
|
-
}
|
|
56
|
-
function lineDelta(a, b) {
|
|
57
|
-
const count = (s) => {
|
|
58
|
-
const m = /* @__PURE__ */ new Map();
|
|
59
|
-
for (const line of s.split("\n")) m.set(line, (m.get(line) ?? 0) + 1);
|
|
60
|
-
return m;
|
|
61
|
-
};
|
|
62
|
-
const ca = count(a);
|
|
63
|
-
const cb = count(b);
|
|
64
|
-
let removed = 0;
|
|
65
|
-
let added = 0;
|
|
66
|
-
for (const [line, n] of ca) removed += Math.max(0, n - (cb.get(line) ?? 0));
|
|
67
|
-
for (const [line, n] of cb) added += Math.max(0, n - (ca.get(line) ?? 0));
|
|
68
|
-
return Math.max(added, removed);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// src/diff/diffConfig.ts
|
|
72
|
-
var FUNCTION_FIELDS = ["setup", "createContent", "createTimeline", "onFrame"];
|
|
73
|
-
var CONFIG_FIELDS = ["duration", "camera", "postprocessing", "elements"];
|
|
74
|
-
function diffConfig(a, b) {
|
|
75
|
-
const ops = [];
|
|
76
|
-
const aParams = paramsByKey(a);
|
|
77
|
-
const bParams = paramsByKey(b);
|
|
78
|
-
const aData = isRecord(a.data) ? a.data : {};
|
|
79
|
-
const bData = isRecord(b.data) ? b.data : {};
|
|
80
|
-
const removedKeys = [];
|
|
81
|
-
const addedKeys = [];
|
|
82
|
-
for (const key of aParams.keys()) if (!bParams.has(key)) removedKeys.push(key);
|
|
83
|
-
for (const key of bParams.keys()) if (!aParams.has(key)) addedKeys.push(key);
|
|
84
|
-
const renamed = /* @__PURE__ */ new Map();
|
|
85
|
-
for (const oldKey of [...removedKeys]) {
|
|
86
|
-
const oldSpec = aParams.get(oldKey);
|
|
87
|
-
const match = addedKeys.find(
|
|
88
|
-
(newKey) => specEqualIgnoringIdentity(oldSpec, bParams.get(newKey))
|
|
89
|
-
);
|
|
90
|
-
if (match) {
|
|
91
|
-
renamed.set(oldKey, match);
|
|
92
|
-
removedKeys.splice(removedKeys.indexOf(oldKey), 1);
|
|
93
|
-
addedKeys.splice(addedKeys.indexOf(match), 1);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
for (const [oldKey, newKey] of renamed) {
|
|
97
|
-
const props = {
|
|
98
|
-
key: [oldKey, newKey]
|
|
99
|
-
};
|
|
100
|
-
const fromVal = valueOf(aData, aParams.get(oldKey), oldKey);
|
|
101
|
-
const toVal = valueOf(bData, bParams.get(newKey), newKey);
|
|
102
|
-
if (!deepEqual(fromVal, toVal)) props.value = [fromVal, toVal];
|
|
103
|
-
ops.push({ op: "modify", track: "knob", id: newKey, props });
|
|
104
|
-
}
|
|
105
|
-
for (const key of removedKeys) {
|
|
106
|
-
ops.push({ op: "remove", track: "knob", id: key });
|
|
107
|
-
}
|
|
108
|
-
for (const key of addedKeys) {
|
|
109
|
-
const spec = bParams.get(key);
|
|
110
|
-
ops.push({
|
|
111
|
-
op: "add",
|
|
112
|
-
track: "knob",
|
|
113
|
-
id: key,
|
|
114
|
-
props: {
|
|
115
|
-
kind: [void 0, spec.kind],
|
|
116
|
-
value: [void 0, valueOf(bData, spec, key)]
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
for (const [key, aSpec] of aParams) {
|
|
121
|
-
const bSpec = bParams.get(key);
|
|
122
|
-
if (!bSpec) continue;
|
|
123
|
-
const props = {};
|
|
124
|
-
const aVal = valueOf(aData, aSpec, key);
|
|
125
|
-
const bVal = valueOf(bData, bSpec, key);
|
|
126
|
-
if (!deepEqual(aVal, bVal)) props.value = [aVal, bVal];
|
|
127
|
-
const specDiff = shallowDiff(aSpec, bSpec, KNOB_IDENTITY);
|
|
128
|
-
if (specDiff) {
|
|
129
|
-
if ("default" in specDiff && "value" in props) delete specDiff.default;
|
|
130
|
-
Object.assign(props, specDiff);
|
|
131
|
-
}
|
|
132
|
-
if (Object.keys(props).length) {
|
|
133
|
-
ops.push({ op: "modify", track: "knob", id: key, props });
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
const declared = /* @__PURE__ */ new Set([...aParams.keys(), ...bParams.keys()]);
|
|
137
|
-
const dataKeys = [
|
|
138
|
-
.../* @__PURE__ */ new Set([...Object.keys(aData), ...Object.keys(bData)])
|
|
139
|
-
].sort();
|
|
140
|
-
for (const key of dataKeys) {
|
|
141
|
-
if (declared.has(key)) continue;
|
|
142
|
-
const from = aData[key];
|
|
143
|
-
const to = bData[key];
|
|
144
|
-
if (deepEqual(from, to)) continue;
|
|
145
|
-
const op = from === void 0 ? "add" : to === void 0 ? "remove" : "modify";
|
|
146
|
-
ops.push({ op, track: "data", id: key, props: { value: [from, to] } });
|
|
147
|
-
}
|
|
148
|
-
ops.push(
|
|
149
|
-
...diffIdTrack("look", looksAsNodes(a.presets), looksAsNodes(b.presets))
|
|
150
|
-
);
|
|
151
|
-
for (const fn of FUNCTION_FIELDS) {
|
|
152
|
-
const va = a[fn];
|
|
153
|
-
const vb = b[fn];
|
|
154
|
-
const fa = typeof va === "string" ? va : "";
|
|
155
|
-
const fb = typeof vb === "string" ? vb : "";
|
|
156
|
-
if (fa === fb) continue;
|
|
157
|
-
ops.push({
|
|
158
|
-
op: "modify",
|
|
159
|
-
track: "code",
|
|
160
|
-
id: fn,
|
|
161
|
-
lines: lineDelta(fa, fb)
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
for (const field of CONFIG_FIELDS) {
|
|
165
|
-
if (deepEqual(a[field], b[field])) continue;
|
|
166
|
-
ops.push({
|
|
167
|
-
op: "modify",
|
|
168
|
-
track: "config",
|
|
169
|
-
id: field,
|
|
170
|
-
props: { value: [a[field], b[field]] }
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
return ops;
|
|
174
|
-
}
|
|
175
|
-
var KNOB_IDENTITY = /* @__PURE__ */ new Set(["key", "label", "order"]);
|
|
176
|
-
function paramsByKey(config) {
|
|
177
|
-
const out = /* @__PURE__ */ new Map();
|
|
178
|
-
if (!Array.isArray(config.params)) return out;
|
|
179
|
-
for (const entry of config.params) {
|
|
180
|
-
if (isRecord(entry) && typeof entry.key === "string" && entry.key) {
|
|
181
|
-
out.set(entry.key, entry);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return out;
|
|
185
|
-
}
|
|
186
|
-
function valueOf(data, spec, key) {
|
|
187
|
-
return data[key] !== void 0 ? data[key] : spec.default;
|
|
188
|
-
}
|
|
189
|
-
function specEqualIgnoringIdentity(a, b) {
|
|
190
|
-
return !shallowDiff(a, b, KNOB_IDENTITY);
|
|
191
|
-
}
|
|
192
|
-
function looksAsNodes(presets) {
|
|
193
|
-
if (!Array.isArray(presets)) return [];
|
|
194
|
-
return presets.filter((p) => isRecord(p) && typeof p.name === "string").map((p) => ({ ...p, id: p.name }));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/diff/diffDoc.ts
|
|
198
|
-
var ID_TRACKS = [
|
|
199
|
-
["zoom", "zoom"],
|
|
200
|
-
["tilt", "tilt"],
|
|
201
|
-
["camMove", "camMotion"],
|
|
202
|
-
["speed", "speed"],
|
|
203
|
-
["rejected", "rejected"],
|
|
204
|
-
["overlay", "overlays"],
|
|
205
|
-
["object", "objects"],
|
|
206
|
-
["audio", "audio"]
|
|
207
|
-
];
|
|
208
|
-
var SCOPED_FIELDS = ["frame", "cursor", "cam", "export"];
|
|
209
|
-
function diffDoc(a, b) {
|
|
210
|
-
const ops = [];
|
|
211
|
-
const pa = isRecord(a.program) ? a.program : void 0;
|
|
212
|
-
const pb = isRecord(b.program) ? b.program : void 0;
|
|
213
|
-
if (pa || pb) {
|
|
214
|
-
ops.push(
|
|
215
|
-
...diffConfig(
|
|
216
|
-
pa && isRecord(pa.config) ? pa.config : {},
|
|
217
|
-
pb && isRecord(pb.config) ? pb.config : {}
|
|
218
|
-
)
|
|
219
|
-
);
|
|
220
|
-
const ea = pa && isRecord(pa.tweenEdits) ? pa.tweenEdits : {};
|
|
221
|
-
const eb = pb && isRecord(pb.tweenEdits) ? pb.tweenEdits : {};
|
|
222
|
-
for (const key of /* @__PURE__ */ new Set([...Object.keys(ea), ...Object.keys(eb)])) {
|
|
223
|
-
const va = isRecord(ea[key]) ? ea[key] : void 0;
|
|
224
|
-
const vb = isRecord(eb[key]) ? eb[key] : void 0;
|
|
225
|
-
if (va && !vb) ops.push({ op: "remove", track: "tween", id: `#${key}` });
|
|
226
|
-
else if (!va && vb) ops.push({ op: "add", track: "tween", id: `#${key}` });
|
|
227
|
-
else if (va && vb) {
|
|
228
|
-
const props = shallowDiff(va, vb);
|
|
229
|
-
if (props)
|
|
230
|
-
ops.push({ op: "modify", track: "tween", id: `#${key}`, props });
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
const da = programLength(pa);
|
|
234
|
-
const db = programLength(pb);
|
|
235
|
-
if (da !== db && (pa?.duration !== void 0 || pb?.duration !== void 0)) {
|
|
236
|
-
ops.push({
|
|
237
|
-
op: "modify",
|
|
238
|
-
track: "config",
|
|
239
|
-
id: "duration",
|
|
240
|
-
props: { value: [da, db] }
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
for (const [track, field] of ID_TRACKS) {
|
|
245
|
-
ops.push(...diffIdTrack(track, asNodeList(a[field]), asNodeList(b[field])));
|
|
246
|
-
}
|
|
247
|
-
const speedOps = ops.filter((o) => o.track === "speed");
|
|
248
|
-
if (speedOps.length) {
|
|
249
|
-
const [oa, ob] = [outputDuration(a), outputDuration(b)];
|
|
250
|
-
if (oa !== null && ob !== null && Math.abs(oa - ob) >= 0.05) {
|
|
251
|
-
speedOps[0].props = { ...speedOps[0].props ?? {}, output: [oa, ob] };
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const aSeg = asNodeList(a.segments) ?? [];
|
|
255
|
-
const bSeg = asNodeList(b.segments) ?? [];
|
|
256
|
-
if (!deepEqual(a.segments, b.segments)) {
|
|
257
|
-
const props = {};
|
|
258
|
-
if (aSeg.length !== bSeg.length) props.count = [aSeg.length, bSeg.length];
|
|
259
|
-
const [da, db] = [keptDuration(aSeg), keptDuration(bSeg)];
|
|
260
|
-
if (da !== db) props.duration = [da, db];
|
|
261
|
-
ops.push({
|
|
262
|
-
op: "modify",
|
|
263
|
-
track: "segments",
|
|
264
|
-
id: "segments",
|
|
265
|
-
props: Object.keys(props).length ? props : { value: ["edited", "edited"] }
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
for (const field of SCOPED_FIELDS) {
|
|
269
|
-
const va = a[field];
|
|
270
|
-
const vb = b[field];
|
|
271
|
-
const fa = isRecord(va) ? va : {};
|
|
272
|
-
const fb = isRecord(vb) ? vb : {};
|
|
273
|
-
const props = shallowDiff(fa, fb);
|
|
274
|
-
if (props) ops.push({ op: "modify", track: field, id: field, props });
|
|
275
|
-
}
|
|
276
|
-
const cameraProps = {};
|
|
277
|
-
for (const k of ["zoomStyle", "tiltStyle", "micGain"]) {
|
|
278
|
-
if (!deepEqual(a[k], b[k])) cameraProps[k] = [a[k], b[k]];
|
|
279
|
-
}
|
|
280
|
-
if (!deepEqual(a.zoomParams, b.zoomParams)) {
|
|
281
|
-
cameraProps.zoomParams = [a.zoomParams, b.zoomParams];
|
|
282
|
-
}
|
|
283
|
-
if (Object.keys(cameraProps).length) {
|
|
284
|
-
ops.push({
|
|
285
|
-
op: "modify",
|
|
286
|
-
track: "camera",
|
|
287
|
-
id: "camera",
|
|
288
|
-
props: cameraProps
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
return ops;
|
|
292
|
-
}
|
|
293
|
-
function asNodeList(v) {
|
|
294
|
-
if (!Array.isArray(v)) return void 0;
|
|
295
|
-
return v.filter(isRecord);
|
|
296
|
-
}
|
|
297
|
-
function programLength(program) {
|
|
298
|
-
if (!program) return null;
|
|
299
|
-
if (typeof program.duration === "number") return program.duration;
|
|
300
|
-
const cfg = isRecord(program.config) ? program.config : void 0;
|
|
301
|
-
return cfg && typeof cfg.duration === "number" ? cfg.duration : null;
|
|
302
|
-
}
|
|
303
|
-
function outputDuration(doc) {
|
|
304
|
-
const source = isRecord(doc.source) ? doc.source : void 0;
|
|
305
|
-
const meta = source && isRecord(source.meta) ? source.meta : void 0;
|
|
306
|
-
const durS = isRecord(doc.program) ? programLength(doc.program) : meta && typeof meta.durationMs === "number" ? meta.durationMs / 1e3 : null;
|
|
307
|
-
const explicit = (asNodeList(doc.segments) ?? []).map((s) => ({
|
|
308
|
-
in: typeof s.in === "number" ? s.in : 0,
|
|
309
|
-
out: typeof s.out === "number" ? s.out : 0
|
|
310
|
-
})).filter((s) => s.out > s.in);
|
|
311
|
-
const segments = explicit.length ? explicit : durS !== null ? [{ in: 0, out: durS }] : null;
|
|
312
|
-
if (!segments) return null;
|
|
313
|
-
const spans = (asNodeList(doc.speed) ?? []).map((s) => ({
|
|
314
|
-
in: typeof s.in === "number" ? s.in : 0,
|
|
315
|
-
out: typeof s.out === "number" ? s.out : 0,
|
|
316
|
-
rate: typeof s.rate === "number" && s.rate > 0 ? s.rate : 1
|
|
317
|
-
})).filter((s) => s.out > s.in);
|
|
318
|
-
let total = 0;
|
|
319
|
-
for (const seg of segments) {
|
|
320
|
-
total += seg.out - seg.in;
|
|
321
|
-
for (const sp of spans) {
|
|
322
|
-
const ov = Math.min(seg.out, sp.out) - Math.max(seg.in, sp.in);
|
|
323
|
-
if (ov > 0) total -= ov - ov / sp.rate;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
return Math.round(total * 1e3) / 1e3;
|
|
327
|
-
}
|
|
328
|
-
function keptDuration(segments) {
|
|
329
|
-
let total = 0;
|
|
330
|
-
for (const s of segments) {
|
|
331
|
-
const start = typeof s.in === "number" ? s.in : 0;
|
|
332
|
-
const end = typeof s.out === "number" ? s.out : start;
|
|
333
|
-
total += Math.max(0, end - start);
|
|
334
|
-
}
|
|
335
|
-
return Math.round(total * 1e3) / 1e3;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// src/diff/types.ts
|
|
339
|
-
function opKey(op) {
|
|
340
|
-
return `${op.track}\0${op.id}`;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// src/diff/coalesce.ts
|
|
344
|
-
function coalesce(opsInOrder) {
|
|
345
|
-
const byNode = /* @__PURE__ */ new Map();
|
|
346
|
-
for (const next of opsInOrder) {
|
|
347
|
-
const key = opKey(next);
|
|
348
|
-
const prev = byNode.get(key);
|
|
349
|
-
if (!prev) {
|
|
350
|
-
byNode.set(key, cloneOp(next));
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
const folded = foldPair(prev, next);
|
|
354
|
-
if (folded) byNode.set(key, folded);
|
|
355
|
-
else byNode.delete(key);
|
|
356
|
-
}
|
|
357
|
-
return [...byNode.values()].sort(compareOps);
|
|
358
|
-
}
|
|
359
|
-
function foldPair(prev, next) {
|
|
360
|
-
if (prev.op === "add" && next.op === "remove") return null;
|
|
361
|
-
if (prev.op === "add" && next.op === "modify") {
|
|
362
|
-
return { ...prev, props: mergeProps(prev.props, next.props) };
|
|
363
|
-
}
|
|
364
|
-
if (next.op === "remove") return { ...next };
|
|
365
|
-
if (prev.op === "remove" && next.op === "add") {
|
|
366
|
-
return { ...next, op: "modify", props: mergeProps(prev.props, next.props) };
|
|
367
|
-
}
|
|
368
|
-
if (prev.op === "modify" && next.op === "modify") {
|
|
369
|
-
const merged = mergeProps(prev.props, next.props, true);
|
|
370
|
-
const lines = prev.lines !== void 0 || next.lines !== void 0 ? (prev.lines ?? 0) + (next.lines ?? 0) : void 0;
|
|
371
|
-
if (!merged && lines === void 0) return null;
|
|
372
|
-
return { ...prev, props: merged, lines };
|
|
373
|
-
}
|
|
374
|
-
return { ...next };
|
|
375
|
-
}
|
|
376
|
-
function mergeProps(a, b, dropNoNet = false) {
|
|
377
|
-
if (!a) return b ? { ...b } : void 0;
|
|
378
|
-
if (!b) return { ...a };
|
|
379
|
-
const out = { ...a };
|
|
380
|
-
for (const [k, [from, to]] of Object.entries(b)) {
|
|
381
|
-
out[k] = k in out ? [out[k][0], to] : [from, to];
|
|
382
|
-
}
|
|
383
|
-
if (dropNoNet) {
|
|
384
|
-
for (const [k, [from, to]] of Object.entries(out)) {
|
|
385
|
-
if (JSON.stringify(from) === JSON.stringify(to)) delete out[k];
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return Object.keys(out).length ? out : void 0;
|
|
389
|
-
}
|
|
390
|
-
function cloneOp(op) {
|
|
391
|
-
return { ...op, props: op.props ? { ...op.props } : void 0 };
|
|
392
|
-
}
|
|
393
|
-
var TRACK_ORDER = [
|
|
394
|
-
"segments",
|
|
395
|
-
"frame",
|
|
396
|
-
"camera",
|
|
397
|
-
"cursor",
|
|
398
|
-
"cam",
|
|
399
|
-
"zoom",
|
|
400
|
-
"tilt",
|
|
401
|
-
"speed",
|
|
402
|
-
"overlay",
|
|
403
|
-
"object",
|
|
404
|
-
"audio",
|
|
405
|
-
"export",
|
|
406
|
-
"knob",
|
|
407
|
-
"look",
|
|
408
|
-
"data",
|
|
409
|
-
"code",
|
|
410
|
-
"config"
|
|
411
|
-
];
|
|
412
|
-
function compareOps(a, b) {
|
|
413
|
-
const ta = TRACK_ORDER.indexOf(a.track);
|
|
414
|
-
const tb = TRACK_ORDER.indexOf(b.track);
|
|
415
|
-
if (ta !== tb) return (ta === -1 ? 99 : ta) - (tb === -1 ? 99 : tb);
|
|
416
|
-
const anchorA = timeAnchor(a);
|
|
417
|
-
const anchorB = timeAnchor(b);
|
|
418
|
-
if (anchorA !== anchorB) return anchorA - anchorB;
|
|
419
|
-
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
420
|
-
}
|
|
421
|
-
function timeAnchor(op) {
|
|
422
|
-
for (const k of ["in", "at", "start"]) {
|
|
423
|
-
const pair = op.props?.[k];
|
|
424
|
-
if (pair) {
|
|
425
|
-
const v = pair[1] ?? pair[0];
|
|
426
|
-
if (typeof v === "number") return v;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return Number.MAX_SAFE_INTEGER;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// src/diff/summarize.ts
|
|
433
|
-
function summarize(ops, options = {}) {
|
|
434
|
-
const max = options.maxItems ?? 12;
|
|
435
|
-
if (ops.length === 0) return "no changes";
|
|
436
|
-
const shown = ops.slice(0, max);
|
|
437
|
-
const parts = shown.map(phrase);
|
|
438
|
-
const hidden = ops.length - shown.length;
|
|
439
|
-
if (hidden > 0)
|
|
440
|
-
parts.push(`and ${hidden} smaller change${hidden === 1 ? "" : "s"}`);
|
|
441
|
-
return parts.join("; ");
|
|
442
|
-
}
|
|
443
|
-
function phrase(op) {
|
|
444
|
-
if (op.track === "code") {
|
|
445
|
-
return `code ${op.id} changed (${op.lines ?? 0} line${op.lines === 1 ? "" : "s"})`;
|
|
446
|
-
}
|
|
447
|
-
if (op.track === "knob") return knobPhrase(op);
|
|
448
|
-
if (op.track === "config") {
|
|
449
|
-
if (op.id === "duration" && op.props?.value) {
|
|
450
|
-
const [from, to] = op.props.value;
|
|
451
|
-
return `duration ${fmt(from, true)}\u2192${fmt(to, true)}`;
|
|
452
|
-
}
|
|
453
|
-
return `${op.id} changed`;
|
|
454
|
-
}
|
|
455
|
-
if (op.track === "data") {
|
|
456
|
-
const pair = op.props?.value;
|
|
457
|
-
if (op.op === "add") return `data ${op.id} set to ${fmt(pair?.[1])}`;
|
|
458
|
-
if (op.op === "remove") return `data ${op.id} removed`;
|
|
459
|
-
return `data ${op.id}: ${fmt(pair?.[0])}\u2192${fmt(pair?.[1])}`;
|
|
460
|
-
}
|
|
461
|
-
if (op.track === "look") {
|
|
462
|
-
if (op.op === "add") return `look "${op.id}" added`;
|
|
463
|
-
if (op.op === "remove") return `look "${op.id}" removed`;
|
|
464
|
-
return `look "${op.id}" changed`;
|
|
465
|
-
}
|
|
466
|
-
if (op.track === "segments") {
|
|
467
|
-
const d = op.props?.duration;
|
|
468
|
-
if (d) return `trim: kept footage ${fmt(d[0], true)}\u2192${fmt(d[1], true)}`;
|
|
469
|
-
return "segments edited";
|
|
470
|
-
}
|
|
471
|
-
if (SCOPED_TRACKS.has(op.track)) {
|
|
472
|
-
return `${op.track} ${propList(op.props)}`;
|
|
473
|
-
}
|
|
474
|
-
const name = `${op.track} ${op.id}`;
|
|
475
|
-
const output = op.props?.output;
|
|
476
|
-
const outputNote = output ? `output ${fmt(output[0], true)}\u2192${fmt(output[1], true)}` : null;
|
|
477
|
-
if (op.op === "add") {
|
|
478
|
-
const range = rangeOf(op);
|
|
479
|
-
const bits = [range, outputNote].filter(Boolean).join(", ");
|
|
480
|
-
return bits ? `${name} added (${bits})` : `${name} added`;
|
|
481
|
-
}
|
|
482
|
-
if (op.op === "remove")
|
|
483
|
-
return outputNote ? `${name} removed (${outputNote})` : `${name} removed`;
|
|
484
|
-
return `${name}: ${propList(op.props)}`;
|
|
485
|
-
}
|
|
486
|
-
function knobPhrase(op) {
|
|
487
|
-
const rename = op.props?.key;
|
|
488
|
-
if (rename) return `replaced knob ${fmt(rename[0])} with ${fmt(rename[1])}`;
|
|
489
|
-
if (op.op === "add") {
|
|
490
|
-
const kind = (op.props?.kind ?? [])[1];
|
|
491
|
-
return typeof kind === "string" ? `knob ${op.id} added (${kind})` : `knob ${op.id} added`;
|
|
492
|
-
}
|
|
493
|
-
if (op.op === "remove") return `knob ${op.id} removed`;
|
|
494
|
-
const value = op.props?.value;
|
|
495
|
-
const parts = [];
|
|
496
|
-
if (value) parts.push(`${fmt(value[0])}\u2192${fmt(value[1])}`);
|
|
497
|
-
for (const [k, [from, to]] of Object.entries(op.props ?? {})) {
|
|
498
|
-
if (k === "value") continue;
|
|
499
|
-
parts.push(`${k} ${fmt(from)}\u2192${fmt(to)}`);
|
|
500
|
-
}
|
|
501
|
-
return `knob ${op.id}: ${parts.join(", ")}`;
|
|
502
|
-
}
|
|
503
|
-
var SCOPED_TRACKS = /* @__PURE__ */ new Set(["frame", "cursor", "cam", "export", "camera"]);
|
|
504
|
-
var PROP_LABELS = {
|
|
505
|
-
in: "start",
|
|
506
|
-
out: "end",
|
|
507
|
-
cx: "focus x",
|
|
508
|
-
cy: "focus y"
|
|
509
|
-
};
|
|
510
|
-
var TIME_PROPS = /* @__PURE__ */ new Set([
|
|
511
|
-
"in",
|
|
512
|
-
"out",
|
|
513
|
-
"at",
|
|
514
|
-
"start",
|
|
515
|
-
"end",
|
|
516
|
-
"duration",
|
|
517
|
-
"output"
|
|
518
|
-
]);
|
|
519
|
-
function propList(props) {
|
|
520
|
-
if (!props) return "changed";
|
|
521
|
-
return Object.entries(props).map(([k, [from, to]]) => {
|
|
522
|
-
const time = TIME_PROPS.has(k);
|
|
523
|
-
return `${PROP_LABELS[k] ?? k} ${fmt(from, time)}\u2192${fmt(to, time)}`;
|
|
524
|
-
}).join(", ");
|
|
525
|
-
}
|
|
526
|
-
function rangeOf(op) {
|
|
527
|
-
const startPair = anchorPair(op, ["in", "at", "start"]);
|
|
528
|
-
const start = startPair ? startPair[1] : void 0;
|
|
529
|
-
if (typeof start !== "number") return null;
|
|
530
|
-
const endPair = anchorPair(op, ["out"]);
|
|
531
|
-
const end = endPair ? endPair[1] : void 0;
|
|
532
|
-
return typeof end === "number" ? `${fmt(start, true)}\u2013${fmt(end, true)}` : `at ${fmt(start, true)}`;
|
|
533
|
-
}
|
|
534
|
-
function anchorPair(op, keys) {
|
|
535
|
-
for (const k of keys) {
|
|
536
|
-
const pair = op.props?.[k];
|
|
537
|
-
if (pair) return pair;
|
|
538
|
-
}
|
|
539
|
-
return void 0;
|
|
540
|
-
}
|
|
541
|
-
var FMT_STRING_MAX = 40;
|
|
542
|
-
function fmt(v, time = false) {
|
|
543
|
-
if (v === void 0) return "\u2205";
|
|
544
|
-
if (v === null) return "null";
|
|
545
|
-
if (typeof v === "number") {
|
|
546
|
-
const rounded = Math.round(v * 100) / 100;
|
|
547
|
-
return time ? `${rounded}s` : String(rounded);
|
|
548
|
-
}
|
|
549
|
-
if (typeof v === "boolean") return v ? "on" : "off";
|
|
550
|
-
if (typeof v === "string") {
|
|
551
|
-
if (v === "") return '""';
|
|
552
|
-
const flat = v.replace(/\s*\n\s*/g, " ");
|
|
553
|
-
const clipped = flat.length > FMT_STRING_MAX ? `${flat.slice(0, FMT_STRING_MAX - 1)}\u2026` : flat;
|
|
554
|
-
return clipped === v ? quoteIfNeeded(clipped) : `"${clipped}"`;
|
|
555
|
-
}
|
|
556
|
-
return "changed";
|
|
557
|
-
}
|
|
558
|
-
function quoteIfNeeded(s) {
|
|
559
|
-
return /^[\w.#-]+$/.test(s) ? s : `"${s}"`;
|
|
560
|
-
}
|
|
561
|
-
export {
|
|
562
|
-
coalesce,
|
|
563
|
-
diffConfig,
|
|
564
|
-
diffDoc,
|
|
565
|
-
opKey,
|
|
566
|
-
summarize
|
|
567
|
-
};
|
|
568
|
-
//# sourceMappingURL=index.js.map
|
package/dist/diff/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/diff/internal.ts","../../src/diff/diffConfig.ts","../../src/diff/diffDoc.ts","../../src/diff/types.ts","../../src/diff/coalesce.ts","../../src/diff/summarize.ts"],"sourcesContent":["import type { Op } from './types'\n\nexport type AnyRecord = Record<string, unknown>\n\nexport function isRecord(v: unknown): v is AnyRecord {\n return !!v && typeof v === 'object' && !Array.isArray(v)\n}\n\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true\n if (typeof a !== typeof b) return false\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]))\n }\n if (isRecord(a) && isRecord(b)) {\n const ka = Object.keys(a)\n const kb = Object.keys(b)\n if (ka.length !== kb.length) return false\n return ka.every((k) => deepEqual(a[k], b[k]))\n }\n return false\n}\n\n/**\n * Shallow property diff of two node objects: changed keys → [from, to].\n * Nested values compare deep but report as whole-value pairs — span/clip\n * props are overwhelmingly scalars, and a whole-value pair stays honest for\n * the rest. `ignore` keys (identity fields) never report.\n */\nexport function shallowDiff(\n a: AnyRecord,\n b: AnyRecord,\n ignore: ReadonlySet<string> = new Set(),\n): Record<string, [unknown, unknown]> | undefined {\n const props: Record<string, [unknown, unknown]> = {}\n const keys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort()\n for (const k of keys) {\n if (ignore.has(k)) continue\n if (!deepEqual(a[k], b[k])) props[k] = [a[k], b[k]]\n }\n return Object.keys(props).length ? props : undefined\n}\n\n/**\n * Diff two id-keyed node lists into add/remove/modify ops. Identity is the\n * id — a moved span with the same id is a modify (the trap case); a\n * remove+add pair is two different nodes by construction.\n */\nexport function diffIdTrack(\n track: string,\n a: readonly AnyRecord[] | undefined,\n b: readonly AnyRecord[] | undefined,\n): Op[] {\n const ops: Op[] = []\n const aById = new Map((a ?? []).map((n) => [String(n.id), n]))\n const bById = new Map((b ?? []).map((n) => [String(n.id), n]))\n for (const [id, node] of aById) {\n if (!bById.has(id)) {\n ops.push({ op: 'remove', track, id, props: pickAnchor(node) })\n }\n }\n for (const [id, node] of bById) {\n const prev = aById.get(id)\n if (!prev) {\n ops.push({ op: 'add', track, id, props: pickAnchor(node) })\n continue\n }\n const props = shallowDiff(prev, node, ID_KEYS)\n if (props) ops.push({ op: 'modify', track, id, props })\n }\n return ops\n}\n\nconst ID_KEYS = new Set(['id'])\n\n/**\n * Anchor props carried on add/remove ops so the summary can place the node\n * in time (\"zoom z5 added (0.8s–2.4s)\") without shipping the whole node.\n */\nfunction pickAnchor(\n node: AnyRecord,\n): Record<string, [unknown, unknown]> | undefined {\n const out: Record<string, [unknown, unknown]> = {}\n for (const k of ['in', 'out', 'at', 'start', 'kind', 'key']) {\n if (node[k] !== undefined) out[k] = [undefined, node[k]]\n }\n return Object.keys(out).length ? out : undefined\n}\n\n/** Magnitude of a function-string change: max(lines added, lines removed). */\nexport function lineDelta(a: string, b: string): number {\n const count = (s: string): Map<string, number> => {\n const m = new Map<string, number>()\n for (const line of s.split('\\n')) m.set(line, (m.get(line) ?? 0) + 1)\n return m\n }\n const ca = count(a)\n const cb = count(b)\n let removed = 0\n let added = 0\n for (const [line, n] of ca) removed += Math.max(0, n - (cb.get(line) ?? 0))\n for (const [line, n] of cb) added += Math.max(0, n - (ca.get(line) ?? 0))\n return Math.max(added, removed)\n}\n","import {\n deepEqual,\n diffIdTrack,\n isRecord,\n lineDelta,\n shallowDiff,\n} from './internal'\nimport type { AnyRecord } from './internal'\nimport type { Op } from './types'\n\n/**\n * Semantic diff over two VosConfigJson states: param keys are\n * program mode's stable ids, so knob values and specs diff fully typed;\n * function-string bodies collapse to a magnitude (\"createContent changed,\n * 12 lines\") — the accepted asymmetry, in the direction nobody reads JSON.\n */\n\nconst FUNCTION_FIELDS = ['setup', 'createContent', 'createTimeline', 'onFrame']\n\n/** Top-level structured fields worth reporting individually. */\nconst CONFIG_FIELDS = ['duration', 'camera', 'postprocessing', 'elements']\n\nexport function diffConfig(a: AnyRecord, b: AnyRecord): Op[] {\n const ops: Op[] = []\n\n const aParams = paramsByKey(a)\n const bParams = paramsByKey(b)\n const aData = isRecord(a.data) ? a.data : {}\n const bData = isRecord(b.data) ? b.data : {}\n\n // --- Knobs: spec + value changes, keyed by param key -------------------\n const removedKeys: string[] = []\n const addedKeys: string[] = []\n for (const key of aParams.keys()) if (!bParams.has(key)) removedKeys.push(key)\n for (const key of bParams.keys()) if (!aParams.has(key)) addedKeys.push(key)\n\n // Rename detection (the \"replaced knob\" trap): a removed and an added key\n // whose specs match ignoring identity/labeling are ONE knob renamed.\n const renamed = new Map<string, string>() // old → new\n for (const oldKey of [...removedKeys]) {\n const oldSpec = aParams.get(oldKey)!\n const match = addedKeys.find((newKey) =>\n specEqualIgnoringIdentity(oldSpec, bParams.get(newKey)!),\n )\n if (match) {\n renamed.set(oldKey, match)\n removedKeys.splice(removedKeys.indexOf(oldKey), 1)\n addedKeys.splice(addedKeys.indexOf(match), 1)\n }\n }\n\n for (const [oldKey, newKey] of renamed) {\n const props: Record<string, [unknown, unknown]> = {\n key: [oldKey, newKey],\n }\n const fromVal = valueOf(aData, aParams.get(oldKey)!, oldKey)\n const toVal = valueOf(bData, bParams.get(newKey)!, newKey)\n if (!deepEqual(fromVal, toVal)) props.value = [fromVal, toVal]\n ops.push({ op: 'modify', track: 'knob', id: newKey, props })\n }\n for (const key of removedKeys) {\n ops.push({ op: 'remove', track: 'knob', id: key })\n }\n for (const key of addedKeys) {\n const spec = bParams.get(key)!\n ops.push({\n op: 'add',\n track: 'knob',\n id: key,\n props: {\n kind: [undefined, spec.kind],\n value: [undefined, valueOf(bData, spec, key)],\n },\n })\n }\n for (const [key, aSpec] of aParams) {\n const bSpec = bParams.get(key)\n if (!bSpec) continue\n const props: Record<string, [unknown, unknown]> = {}\n const aVal = valueOf(aData, aSpec, key)\n const bVal = valueOf(bData, bSpec, key)\n if (!deepEqual(aVal, bVal)) props.value = [aVal, bVal]\n const specDiff = shallowDiff(aSpec, bSpec, KNOB_IDENTITY)\n if (specDiff) {\n // Default changes only matter when they aren't already the value change\n // (applyParamValue bakes default AND data together).\n if ('default' in specDiff && 'value' in props) delete specDiff.default\n Object.assign(props, specDiff)\n }\n if (Object.keys(props).length) {\n ops.push({ op: 'modify', track: 'knob', id: key, props })\n }\n }\n\n // --- Data keys not declared as knobs ------------------------------------\n const declared = new Set([...aParams.keys(), ...bParams.keys()])\n const dataKeys = [\n ...new Set([...Object.keys(aData), ...Object.keys(bData)]),\n ].sort()\n for (const key of dataKeys) {\n if (declared.has(key)) continue\n const from = aData[key]\n const to = bData[key]\n if (deepEqual(from, to)) continue\n const op: Op['op'] =\n from === undefined ? 'add' : to === undefined ? 'remove' : 'modify'\n ops.push({ op, track: 'data', id: key, props: { value: [from, to] } })\n }\n\n // --- Looks (presets), keyed by name -------------------------------------\n ops.push(\n ...diffIdTrack('look', looksAsNodes(a.presets), looksAsNodes(b.presets)),\n )\n\n // --- Function strings collapse to magnitude -----------------------------\n for (const fn of FUNCTION_FIELDS) {\n const va = a[fn]\n const vb = b[fn]\n const fa = typeof va === 'string' ? va : ''\n const fb = typeof vb === 'string' ? vb : ''\n if (fa === fb) continue\n ops.push({\n op: 'modify',\n track: 'code',\n id: fn,\n lines: lineDelta(fa, fb),\n })\n }\n\n // --- Remaining structured top-level fields ------------------------------\n for (const field of CONFIG_FIELDS) {\n if (deepEqual(a[field], b[field])) continue\n ops.push({\n op: 'modify',\n track: 'config',\n id: field,\n props: { value: [a[field], b[field]] },\n })\n }\n\n return ops\n}\n\n/** Spec fields that are identity/labeling, not behavior. */\nconst KNOB_IDENTITY = new Set(['key', 'label', 'order'])\n\ninterface ParamSpecLike extends AnyRecord {\n key: string\n kind?: unknown\n default?: unknown\n}\n\nfunction paramsByKey(config: AnyRecord): Map<string, ParamSpecLike> {\n const out = new Map<string, ParamSpecLike>()\n if (!Array.isArray(config.params)) return out\n for (const entry of config.params) {\n if (isRecord(entry) && typeof entry.key === 'string' && entry.key) {\n out.set(entry.key, entry as ParamSpecLike)\n }\n }\n return out\n}\n\n/** A knob's effective value: data wins (what playback reads), else default. */\nfunction valueOf(data: AnyRecord, spec: ParamSpecLike, key: string): unknown {\n return data[key] !== undefined ? data[key] : spec.default\n}\n\nfunction specEqualIgnoringIdentity(\n a: ParamSpecLike,\n b: ParamSpecLike,\n): boolean {\n return !shallowDiff(a, b, KNOB_IDENTITY)\n}\n\nfunction looksAsNodes(presets: unknown): AnyRecord[] {\n if (!Array.isArray(presets)) return []\n return presets\n .filter((p): p is AnyRecord => isRecord(p) && typeof p.name === 'string')\n .map((p) => ({ ...p, id: p.name }))\n}\n","import { diffConfig } from './diffConfig'\nimport { deepEqual, diffIdTrack, isRecord, shallowDiff } from './internal'\nimport type { AnyRecord } from './internal'\nimport type { Op } from './types'\n\n/**\n * Semantic diff over two ProjectDoc states (wired end-to-end once hosted\n * versions persist take docs). Every editable node has a stable id, so id-keyed\n * tracks diff exactly; singleton surfaces report as scoped modifies. Typed\n * structurally (Record-based) — the differ must not depend on studio-core.\n */\n\n/** Track name → doc field, for the id-keyed span/clip tracks. */\nconst ID_TRACKS: readonly [track: string, field: string][] = [\n ['zoom', 'zoom'],\n ['tilt', 'tilt'],\n ['camMove', 'camMotion'],\n ['speed', 'speed'],\n ['rejected', 'rejected'],\n ['overlay', 'overlays'],\n ['object', 'objects'],\n ['audio', 'audio'],\n]\n\n/** Singleton surfaces that report as one scoped modify each. */\nconst SCOPED_FIELDS = ['frame', 'cursor', 'cam', 'export'] as const\n\nexport function diffDoc(a: AnyRecord, b: AnyRecord): Op[] {\n const ops: Op[] = []\n\n // The program anchor: its config diffs as a program does (code /\n // knob / data / look / config tracks), and its tween-timing overlay as\n // one `tween` track keyed by spec index.\n const pa = isRecord(a.program) ? a.program : undefined\n const pb = isRecord(b.program) ? b.program : undefined\n if (pa || pb) {\n ops.push(\n ...diffConfig(\n pa && isRecord(pa.config) ? pa.config : {},\n pb && isRecord(pb.config) ? pb.config : {},\n ),\n )\n const ea = pa && isRecord(pa.tweenEdits) ? pa.tweenEdits : {}\n const eb = pb && isRecord(pb.tweenEdits) ? pb.tweenEdits : {}\n for (const key of new Set([...Object.keys(ea), ...Object.keys(eb)])) {\n const va = isRecord(ea[key]) ? ea[key] : undefined\n const vb = isRecord(eb[key]) ? eb[key] : undefined\n if (va && !vb) ops.push({ op: 'remove', track: 'tween', id: `#${key}` })\n else if (!va && vb) ops.push({ op: 'add', track: 'tween', id: `#${key}` })\n else if (va && vb) {\n const props = shallowDiff(va, vb)\n if (props)\n ops.push({ op: 'modify', track: 'tween', id: `#${key}`, props })\n }\n }\n // A changed `program.duration` (the anchor's own length) reports as the\n // config's duration would; the config's own duration already did above.\n const da = programLength(pa)\n const db = programLength(pb)\n if (\n da !== db &&\n (pa?.duration !== undefined || pb?.duration !== undefined)\n ) {\n ops.push({\n op: 'modify',\n track: 'config',\n id: 'duration',\n props: { value: [da, db] },\n })\n }\n }\n\n for (const [track, field] of ID_TRACKS) {\n ops.push(...diffIdTrack(track, asNodeList(a[field]), asNodeList(b[field])))\n }\n\n // A speed edit's cost in OUTPUT seconds rides the first\n // speed op, so the history line says what the cut gained or lost\n // (\"speed sp0: rate 2→4, output 25s→22.5s\").\n const speedOps = ops.filter((o) => o.track === 'speed')\n if (speedOps.length) {\n const [oa, ob] = [outputDuration(a), outputDuration(b)]\n if (oa !== null && ob !== null && Math.abs(oa - ob) >= 0.05) {\n speedOps[0].props = { ...(speedOps[0].props ?? {}), output: [oa, ob] }\n }\n }\n\n // Segments: the trim surface. Report count + kept-duration movement, not\n // the raw arrays (payloads stay small; the compare player shows the rest).\n const aSeg = asNodeList(a.segments) ?? []\n const bSeg = asNodeList(b.segments) ?? []\n if (!deepEqual(a.segments, b.segments)) {\n const props: Record<string, [unknown, unknown]> = {}\n if (aSeg.length !== bSeg.length) props.count = [aSeg.length, bSeg.length]\n const [da, db] = [keptDuration(aSeg), keptDuration(bSeg)]\n if (da !== db) props.duration = [da, db]\n ops.push({\n op: 'modify',\n track: 'segments',\n id: 'segments',\n props: Object.keys(props).length\n ? props\n : { value: ['edited', 'edited'] },\n })\n }\n\n for (const field of SCOPED_FIELDS) {\n const va = a[field]\n const vb = b[field]\n const fa = isRecord(va) ? va : {}\n const fb = isRecord(vb) ? vb : {}\n const props = shallowDiff(fa, fb)\n if (props) ops.push({ op: 'modify', track: field, id: field, props })\n }\n\n // Camera personality: style + overrides + wand intensity as ONE surface.\n const cameraProps: Record<string, [unknown, unknown]> = {}\n for (const k of ['zoomStyle', 'tiltStyle', 'micGain'] as const) {\n if (!deepEqual(a[k], b[k])) cameraProps[k] = [a[k], b[k]]\n }\n if (!deepEqual(a.zoomParams, b.zoomParams)) {\n cameraProps.zoomParams = [a.zoomParams, b.zoomParams]\n }\n if (Object.keys(cameraProps).length) {\n ops.push({\n op: 'modify',\n track: 'camera',\n id: 'camera',\n props: cameraProps,\n })\n }\n\n return ops\n}\n\nfunction asNodeList(v: unknown): AnyRecord[] | undefined {\n if (!Array.isArray(v)) return undefined\n return v.filter(isRecord)\n}\n\n/**\n * OUTPUT duration of a doc: kept segments with speed spans applied — the\n * same arithmetic the lowering's rate map performs, kept structural so the\n * differ stays dependency-free. Null when the doc cannot say (no source\n * duration and no explicit segments).\n */\nfunction programLength(program: AnyRecord | undefined): number | null {\n if (!program) return null\n if (typeof program.duration === 'number') return program.duration\n const cfg = isRecord(program.config) ? program.config : undefined\n return cfg && typeof cfg.duration === 'number' ? cfg.duration : null\n}\n\nfunction outputDuration(doc: AnyRecord): number | null {\n // A program document is one source span, its own length: its speed\n // spans rate it the way a recording's rate the footage.\n const source = isRecord(doc.source) ? doc.source : undefined\n const meta = source && isRecord(source.meta) ? source.meta : undefined\n const durS = isRecord(doc.program)\n ? programLength(doc.program)\n : meta && typeof meta.durationMs === 'number'\n ? meta.durationMs / 1000\n : null\n const explicit = (asNodeList(doc.segments) ?? [])\n .map((s) => ({\n in: typeof s.in === 'number' ? s.in : 0,\n out: typeof s.out === 'number' ? s.out : 0,\n }))\n .filter((s) => s.out > s.in)\n const segments = explicit.length\n ? explicit\n : durS !== null\n ? [{ in: 0, out: durS }]\n : null\n if (!segments) return null\n const spans = (asNodeList(doc.speed) ?? [])\n .map((s) => ({\n in: typeof s.in === 'number' ? s.in : 0,\n out: typeof s.out === 'number' ? s.out : 0,\n rate: typeof s.rate === 'number' && s.rate > 0 ? s.rate : 1,\n }))\n .filter((s) => s.out > s.in)\n let total = 0\n for (const seg of segments) {\n total += seg.out - seg.in\n for (const sp of spans) {\n const ov = Math.min(seg.out, sp.out) - Math.max(seg.in, sp.in)\n if (ov > 0) total -= ov - ov / sp.rate\n }\n }\n return Math.round(total * 1000) / 1000\n}\n\nfunction keptDuration(segments: AnyRecord[]): number {\n let total = 0\n for (const s of segments) {\n const start = typeof s.in === 'number' ? s.in : 0\n const end = typeof s.out === 'number' ? s.out : start\n total += Math.max(0, end - start)\n }\n return Math.round(total * 1000) / 1000\n}\n","/**\n * The semantic differ: pure functions over two\n * immutable version states — no I/O, no recorded gesture log (\"derive,\n * don't record\"). Runs identically in Workers, the CLI, and the studio;\n * same two inputs ⇒ byte-identical ops and summary.\n */\n\nexport interface Op {\n op: 'add' | 'remove' | 'modify'\n /**\n * Doc tracks: zoom | tilt | speed | overlay | object | audio, plus scoped\n * singletons (segments | frame | cursor | cam | export | camera).\n * Config tracks: knob (param key space) | look | data | code | config.\n */\n track: string\n /** Span/clip id, param key, function name, or field name. */\n id: string\n /** Changed properties: key → [from, to]. Absent on code ops. */\n props?: Record<string, [unknown, unknown]>\n /** Code-function modifies only: magnitude of the line-level change. */\n lines?: number\n /**\n * True when the change is a cascaded consequence of another gesture\n * (e.g. a trim shifting downstream spans), not a direct edit.\n */\n cascade?: boolean\n}\n\n/** One intervening version's worth of changes, as the pull contract ships it. */\nexport interface VersionChanges {\n versionId: string\n versionNumber: number\n origin: string\n label: string | null\n note: string | null\n ops: Op[]\n summary: string\n}\n\n/** Stable composite key for net-effect folding. */\nexport function opKey(op: Op): string {\n return `${op.track}\u0000${op.id}`\n}\n","import { opKey } from './types'\nimport type { Op } from './types'\n\n/**\n * Net effect per node across a sequence of op sets (the coalescing rules):\n * initial→final only, no intermediate drags. add→modify folds into the add;\n * add→remove vanishes; modify chains keep the first `from` and last `to`\n * (dropping props that net to no change); remove→add of the same id is one\n * modify (the node was replaced in place). Output is deterministically\n * ordered: track declaration order, then output-time anchor, then id.\n */\nexport function coalesce(opsInOrder: readonly Op[]): Op[] {\n const byNode = new Map<string, Op>()\n\n for (const next of opsInOrder) {\n const key = opKey(next)\n const prev = byNode.get(key)\n if (!prev) {\n byNode.set(key, cloneOp(next))\n continue\n }\n const folded = foldPair(prev, next)\n if (folded) byNode.set(key, folded)\n else byNode.delete(key)\n }\n\n return [...byNode.values()].sort(compareOps)\n}\n\nfunction foldPair(prev: Op, next: Op): Op | null {\n // add then remove: the node never existed for the reader.\n if (prev.op === 'add' && next.op === 'remove') return null\n // add then modify: still an add, with the final properties.\n if (prev.op === 'add' && next.op === 'modify') {\n return { ...prev, props: mergeProps(prev.props, next.props) }\n }\n // modify then remove: the removal is the story.\n if (next.op === 'remove') return { ...next }\n // remove then add: replaced in place — one modify.\n if (prev.op === 'remove' && next.op === 'add') {\n return { ...next, op: 'modify', props: mergeProps(prev.props, next.props) }\n }\n // modify then modify: first from, last to; drop props that net out.\n if (prev.op === 'modify' && next.op === 'modify') {\n const merged = mergeProps(prev.props, next.props, true)\n const lines =\n prev.lines !== undefined || next.lines !== undefined\n ? (prev.lines ?? 0) + (next.lines ?? 0)\n : undefined\n if (!merged && lines === undefined) return null\n return { ...prev, props: merged, lines }\n }\n // Remaining combinations (add→add, remove→remove) shouldn't occur between\n // well-formed sets; keep the latest as the honest answer.\n return { ...next }\n}\n\nfunction mergeProps(\n a: Op['props'],\n b: Op['props'],\n dropNoNet = false,\n): Op['props'] {\n if (!a) return b ? { ...b } : undefined\n if (!b) return { ...a }\n const out: NonNullable<Op['props']> = { ...a }\n for (const [k, [from, to]] of Object.entries(b)) {\n out[k] = k in out ? [out[k][0], to] : [from, to]\n }\n if (dropNoNet) {\n for (const [k, [from, to]] of Object.entries(out)) {\n if (JSON.stringify(from) === JSON.stringify(to)) delete out[k]\n }\n }\n return Object.keys(out).length ? out : undefined\n}\n\nfunction cloneOp(op: Op): Op {\n return { ...op, props: op.props ? { ...op.props } : undefined }\n}\n\n/** Track presentation order: content tracks in output order, then meta. */\nconst TRACK_ORDER = [\n 'segments',\n 'frame',\n 'camera',\n 'cursor',\n 'cam',\n 'zoom',\n 'tilt',\n 'speed',\n 'overlay',\n 'object',\n 'audio',\n 'export',\n 'knob',\n 'look',\n 'data',\n 'code',\n 'config',\n]\n\nfunction compareOps(a: Op, b: Op): number {\n const ta = TRACK_ORDER.indexOf(a.track)\n const tb = TRACK_ORDER.indexOf(b.track)\n if (ta !== tb) return (ta === -1 ? 99 : ta) - (tb === -1 ? 99 : tb)\n const anchorA = timeAnchor(a)\n const anchorB = timeAnchor(b)\n if (anchorA !== anchorB) return anchorA - anchorB\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0\n}\n\nfunction timeAnchor(op: Op): number {\n for (const k of ['in', 'at', 'start']) {\n const pair = op.props?.[k]\n if (pair) {\n const v = pair[1] ?? pair[0]\n if (typeof v === 'number') return v\n }\n }\n return Number.MAX_SAFE_INTEGER\n}\n","import type { Op } from './types'\n\n/**\n * Deterministic prose over an op list — the line that lands in the agent's\n * context (\"zoom z3: end 4.2s→4.6s, level 2.2→1.8; tilt t1 removed\").\n * Same ops ⇒ byte-identical string; unit-pinned like the geometry mirrors.\n */\nexport function summarize(\n ops: readonly Op[],\n options: { maxItems?: number } = {},\n): string {\n const max = options.maxItems ?? 12\n if (ops.length === 0) return 'no changes'\n const shown = ops.slice(0, max)\n const parts = shown.map(phrase)\n const hidden = ops.length - shown.length\n if (hidden > 0)\n parts.push(`and ${hidden} smaller change${hidden === 1 ? '' : 's'}`)\n return parts.join('; ')\n}\n\nfunction phrase(op: Op): string {\n if (op.track === 'code') {\n return `code ${op.id} changed (${op.lines ?? 0} line${op.lines === 1 ? '' : 's'})`\n }\n if (op.track === 'knob') return knobPhrase(op)\n if (op.track === 'config') {\n if (op.id === 'duration' && op.props?.value) {\n const [from, to] = op.props.value\n return `duration ${fmt(from, true)}→${fmt(to, true)}`\n }\n return `${op.id} changed`\n }\n if (op.track === 'data') {\n const pair = op.props?.value\n if (op.op === 'add') return `data ${op.id} set to ${fmt(pair?.[1])}`\n if (op.op === 'remove') return `data ${op.id} removed`\n return `data ${op.id}: ${fmt(pair?.[0])}→${fmt(pair?.[1])}`\n }\n if (op.track === 'look') {\n if (op.op === 'add') return `look \"${op.id}\" added`\n if (op.op === 'remove') return `look \"${op.id}\" removed`\n return `look \"${op.id}\" changed`\n }\n if (op.track === 'segments') {\n const d = op.props?.duration\n if (d) return `trim: kept footage ${fmt(d[0], true)}→${fmt(d[1], true)}`\n return 'segments edited'\n }\n if (SCOPED_TRACKS.has(op.track)) {\n return `${op.track} ${propList(op.props)}`\n }\n\n // Id-keyed span/clip tracks.\n const name = `${op.track} ${op.id}`\n // The output-duration pair a speed edit carries (what the cut gained\n // or lost in screen seconds) rides add/remove phrases too — a new 2× span\n // shortens the video without modifying anything.\n const output = op.props?.output\n const outputNote = output\n ? `output ${fmt(output[0], true)}→${fmt(output[1], true)}`\n : null\n if (op.op === 'add') {\n const range = rangeOf(op)\n const bits = [range, outputNote].filter(Boolean).join(', ')\n return bits ? `${name} added (${bits})` : `${name} added`\n }\n if (op.op === 'remove')\n return outputNote ? `${name} removed (${outputNote})` : `${name} removed`\n return `${name}: ${propList(op.props)}`\n}\n\nfunction knobPhrase(op: Op): string {\n const rename = op.props?.key\n if (rename) return `replaced knob ${fmt(rename[0])} with ${fmt(rename[1])}`\n if (op.op === 'add') {\n const kind = (op.props?.kind ?? [])[1]\n return typeof kind === 'string'\n ? `knob ${op.id} added (${kind})`\n : `knob ${op.id} added`\n }\n if (op.op === 'remove') return `knob ${op.id} removed`\n const value = op.props?.value\n const parts: string[] = []\n if (value) parts.push(`${fmt(value[0])}→${fmt(value[1])}`)\n for (const [k, [from, to]] of Object.entries(op.props ?? {})) {\n if (k === 'value') continue\n parts.push(`${k} ${fmt(from)}→${fmt(to)}`)\n }\n return `knob ${op.id}: ${parts.join(', ')}`\n}\n\nconst SCOPED_TRACKS = new Set(['frame', 'cursor', 'cam', 'export', 'camera'])\n\n/** Humanized property names for the take vocabulary. */\nconst PROP_LABELS: Record<string, string> = {\n in: 'start',\n out: 'end',\n cx: 'focus x',\n cy: 'focus y',\n}\n\n/** Properties whose numbers are seconds. */\nconst TIME_PROPS = new Set([\n 'in',\n 'out',\n 'at',\n 'start',\n 'end',\n 'duration',\n 'output',\n])\n\nfunction propList(props: Op['props']): string {\n if (!props) return 'changed'\n return Object.entries(props)\n .map(([k, [from, to]]) => {\n const time = TIME_PROPS.has(k)\n return `${PROP_LABELS[k] ?? k} ${fmt(from, time)}→${fmt(to, time)}`\n })\n .join(', ')\n}\n\nfunction rangeOf(op: Op): string | null {\n const startPair = anchorPair(op, ['in', 'at', 'start'])\n const start = startPair ? startPair[1] : undefined\n if (typeof start !== 'number') return null\n const endPair = anchorPair(op, ['out'])\n const end = endPair ? endPair[1] : undefined\n return typeof end === 'number'\n ? `${fmt(start, true)}–${fmt(end, true)}`\n : `at ${fmt(start, true)}`\n}\n\nfunction anchorPair(\n op: Op,\n keys: readonly string[],\n): [unknown, unknown] | undefined {\n for (const k of keys) {\n const pair = op.props?.[k]\n if (pair) return pair\n }\n return undefined\n}\n\n/**\n * Long strings (content knobs carry whole headlines) collapse to\n * one line and truncate — the summary is a changelog sentence, and it also\n * rides 409 stale_base bodies, so a multiline value must never spill raw.\n */\nconst FMT_STRING_MAX = 40\n\nfunction fmt(v: unknown, time = false): string {\n if (v === undefined) return '∅'\n if (v === null) return 'null'\n if (typeof v === 'number') {\n const rounded = Math.round(v * 100) / 100\n return time ? `${rounded}s` : String(rounded)\n }\n if (typeof v === 'boolean') return v ? 'on' : 'off'\n if (typeof v === 'string') {\n if (v === '') return '\"\"'\n const flat = v.replace(/\\s*\\n\\s*/g, ' ')\n const clipped =\n flat.length > FMT_STRING_MAX\n ? `${flat.slice(0, FMT_STRING_MAX - 1)}…`\n : flat\n return clipped === v ? quoteIfNeeded(clipped) : `\"${clipped}\"`\n }\n return 'changed'\n}\n\nfunction quoteIfNeeded(s: string): string {\n return /^[\\w.#-]+$/.test(s) ? s : `\"${s}\"`\n}\n"],"mappings":"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","names":[]}
|