@rslsp1/fa-app-tools 10.1.3 → 10.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/StageEngine-3MOBM2WX.mjs +590 -0
- package/dist/StageEngine-5VR3KEZB.js +590 -0
- package/dist/chunk-ACB2543O.js +218 -0
- package/dist/chunk-FTLEDU6C.js +157 -0
- package/dist/chunk-HFX6D53W.js +25729 -0
- package/dist/{chunk-5SYVLULG.mjs → chunk-JP7LIWDR.mjs} +17934 -13288
- package/dist/chunk-QERFD7BY.js +1418 -0
- package/dist/{chunk-C5CGSPP3.mjs → chunk-RFTANBQ5.mjs} +80 -0
- package/dist/chunk-TFWIMFNF.mjs +218 -0
- package/dist/{contracts-DdYOMBl9.d.mts → contracts-B3AbzYQ4.d.mts} +1 -1
- package/dist/{contracts-DdYOMBl9.d.ts → contracts-B3AbzYQ4.d.ts} +1 -1
- package/dist/{hfEventTypes-BUztJySs.d.mts → hfEventTypes-DQPjEP4T.d.mts} +12 -1
- package/dist/{hfEventTypes-fAdA-0A9.d.ts → hfEventTypes-DharkVsi.d.ts} +12 -1
- package/dist/index.d.mts +27 -6
- package/dist/index.d.ts +27 -6
- package/dist/index.js +1744 -22342
- package/dist/index.mjs +55 -33
- package/dist/{storeContract-CJi0fpCA.d.mts → storeContract-C-em5E61.d.ts} +140 -14
- package/dist/{storeContract-gc2dxews.d.ts → storeContract-Cc8tFavd.d.mts} +140 -14
- package/dist/szenen-contract.d.mts +2 -2
- package/dist/szenen-contract.d.ts +2 -2
- package/dist/szenen-contract.js +12 -1474
- package/dist/szenen-contract.mjs +1 -1
- package/dist/szenen.d.mts +1060 -706
- package/dist/szenen.d.ts +1060 -706
- package/dist/szenen.js +1357 -23667
- package/dist/szenen.mjs +95 -128
- package/package.json +4 -2
package/dist/szenen-contract.js
CHANGED
|
@@ -1,1481 +1,20 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
__export(szenen_contract_exports, {
|
|
23
|
-
describeElementStoreContract: () => describeElementStoreContract
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(szenen_contract_exports);
|
|
26
|
-
|
|
27
|
-
// src/lib/szenen/storeContractVitest.ts
|
|
28
|
-
var import_vitest = require("vitest");
|
|
29
|
-
|
|
30
|
-
// src/lib/szenen/versionDag.ts
|
|
31
|
-
var VersionDagError = class extends Error {
|
|
32
|
-
};
|
|
33
|
-
function buildVersionDag(versions) {
|
|
34
|
-
if (versions.length === 0) {
|
|
35
|
-
throw new VersionDagError("Versions-DAG ohne Versionen ist nicht aufbaubar.");
|
|
36
|
-
}
|
|
37
|
-
const elementId = versions[0].element_id;
|
|
38
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
39
|
-
const children = /* @__PURE__ */ new Map();
|
|
40
|
-
for (const version of versions) {
|
|
41
|
-
if (!version.version_id) {
|
|
42
|
-
throw new VersionDagError("Version ohne version_id.");
|
|
43
|
-
}
|
|
44
|
-
if (version.element_id !== elementId) {
|
|
45
|
-
throw new VersionDagError(
|
|
46
|
-
`Version ${version.version_id} gehoert zu Element ${version.element_id}, erwartet ${elementId}. Ein DAG umfasst genau ein Element.`
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
if (nodes.has(version.version_id)) {
|
|
50
|
-
throw new VersionDagError(`Version ${version.version_id} kommt doppelt vor.`);
|
|
51
|
-
}
|
|
52
|
-
nodes.set(version.version_id, version);
|
|
53
|
-
if (!children.has(version.version_id)) children.set(version.version_id, []);
|
|
54
|
-
}
|
|
55
|
-
for (const version of versions) {
|
|
56
|
-
const seenParents = /* @__PURE__ */ new Set();
|
|
57
|
-
for (const link of version.parents) {
|
|
58
|
-
if (link.parent_version_id === version.version_id) {
|
|
59
|
-
throw new VersionDagError(`Version ${version.version_id} ist ihr eigener Parent.`);
|
|
60
|
-
}
|
|
61
|
-
if (!nodes.has(link.parent_version_id)) {
|
|
62
|
-
throw new VersionDagError(
|
|
63
|
-
`Version ${version.version_id} verweist auf unbekannten Parent ${link.parent_version_id}. Der Graph waere unvollstaendig.`
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
if (seenParents.has(link.parent_version_id)) {
|
|
67
|
-
throw new VersionDagError(
|
|
68
|
-
`Version ${version.version_id} nennt Parent ${link.parent_version_id} doppelt.`
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
seenParents.add(link.parent_version_id);
|
|
72
|
-
children.get(link.parent_version_id).push(version.version_id);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
assertAcyclic(nodes);
|
|
76
|
-
const versionIds = versions.map((v) => v.version_id);
|
|
77
|
-
const closure = (start, step) => {
|
|
78
|
-
const seen = /* @__PURE__ */ new Set();
|
|
79
|
-
const stack = [...step(start)];
|
|
80
|
-
while (stack.length > 0) {
|
|
81
|
-
const current = stack.pop();
|
|
82
|
-
if (seen.has(current)) continue;
|
|
83
|
-
seen.add(current);
|
|
84
|
-
stack.push(...step(current));
|
|
85
|
-
}
|
|
86
|
-
return seen;
|
|
87
|
-
};
|
|
88
|
-
const parentIdsOf = (id) => (nodes.get(id)?.parents ?? []).map((p) => p.parent_version_id);
|
|
89
|
-
const childIdsOf = (id) => children.get(id) ?? [];
|
|
90
|
-
return {
|
|
91
|
-
elementId,
|
|
92
|
-
versionIds,
|
|
93
|
-
get: (versionId) => nodes.get(versionId),
|
|
94
|
-
parentsOf: (versionId) => nodes.get(versionId)?.parents ?? [],
|
|
95
|
-
childrenOf: (versionId) => childIdsOf(versionId),
|
|
96
|
-
heads: () => versionIds.filter((id) => childIdsOf(id).length === 0),
|
|
97
|
-
roots: () => versionIds.filter((id) => parentIdsOf(id).length === 0),
|
|
98
|
-
hasFork() {
|
|
99
|
-
return this.heads().length > 1;
|
|
100
|
-
},
|
|
101
|
-
ancestorsOf: (versionId) => closure(versionId, parentIdsOf),
|
|
102
|
-
descendantsOf: (versionId) => closure(versionId, childIdsOf),
|
|
103
|
-
isAncestorOf(candidate, versionId) {
|
|
104
|
-
return this.ancestorsOf(versionId).has(candidate);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function assertAcyclic(nodes) {
|
|
109
|
-
const OPEN = 1;
|
|
110
|
-
const DONE = 2;
|
|
111
|
-
const state = /* @__PURE__ */ new Map();
|
|
112
|
-
for (const start of nodes.keys()) {
|
|
113
|
-
if (state.get(start) === DONE) continue;
|
|
114
|
-
const stack = [
|
|
115
|
-
{ id: start, next: 0, path: [start] }
|
|
116
|
-
];
|
|
117
|
-
state.set(start, OPEN);
|
|
118
|
-
while (stack.length > 0) {
|
|
119
|
-
const frame = stack[stack.length - 1];
|
|
120
|
-
const parents = nodes.get(frame.id).parents;
|
|
121
|
-
if (frame.next >= parents.length) {
|
|
122
|
-
state.set(frame.id, DONE);
|
|
123
|
-
stack.pop();
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
const parentId = parents[frame.next++].parent_version_id;
|
|
127
|
-
const parentState = state.get(parentId);
|
|
128
|
-
if (parentState === OPEN) {
|
|
129
|
-
throw new VersionDagError(
|
|
130
|
-
`Zyklus im Versions-DAG: ${[...frame.path, parentId].join(" -> ")}`
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
if (parentState !== DONE) {
|
|
134
|
-
state.set(parentId, OPEN);
|
|
135
|
-
stack.push({ id: parentId, next: 0, path: [...frame.path, parentId] });
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function resolvePreferredHead(options) {
|
|
141
|
-
const { dag, workingContextId, inheritanceChain = [], owningContextId, selections = [] } = options;
|
|
142
|
-
const heads = dag.heads();
|
|
143
|
-
const ignoredSelections = [];
|
|
144
|
-
const byContext = /* @__PURE__ */ new Map();
|
|
145
|
-
for (const selection of selections) {
|
|
146
|
-
if (!dag.get(selection.version_id)) {
|
|
147
|
-
ignoredSelections.push(selection);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
if (!byContext.has(selection.context_id)) byContext.set(selection.context_id, selection);
|
|
151
|
-
}
|
|
152
|
-
const candidates = [
|
|
153
|
-
{ contextId: workingContextId, source: "context" },
|
|
154
|
-
...inheritanceChain.map((contextId) => ({ contextId, source: "inherited" })),
|
|
155
|
-
...owningContextId ? [{ contextId: owningContextId, source: "owning" }] : []
|
|
156
|
-
];
|
|
157
|
-
for (const candidate of candidates) {
|
|
158
|
-
const selection = byContext.get(candidate.contextId);
|
|
159
|
-
if (!selection) continue;
|
|
160
|
-
return {
|
|
161
|
-
resolution: {
|
|
162
|
-
kind: "selected",
|
|
163
|
-
versionId: selection.version_id,
|
|
164
|
-
source: candidate.source,
|
|
165
|
-
contextId: candidate.contextId,
|
|
166
|
-
heads,
|
|
167
|
-
stale: !heads.includes(selection.version_id)
|
|
168
|
-
},
|
|
169
|
-
ignoredSelections
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
if (heads.length === 1) {
|
|
173
|
-
return { resolution: { kind: "single", versionId: heads[0], heads }, ignoredSelections };
|
|
174
|
-
}
|
|
175
|
-
return { resolution: { kind: "fork", heads }, ignoredSelections };
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// src/lib/szenen/storeContract.ts
|
|
179
|
-
var STYLE_PAYLOAD = {
|
|
180
|
-
role: "medium",
|
|
181
|
-
name: "Kohlezeichnung",
|
|
182
|
-
text: "grobe Kohle auf Papier",
|
|
183
|
-
locale: "de"
|
|
184
|
-
};
|
|
185
|
-
var STYLE_PAYLOAD_V2 = {
|
|
186
|
-
role: "medium",
|
|
187
|
-
name: "Kohlezeichnung, weicher",
|
|
188
|
-
text: "weiche Kohle, gewischt",
|
|
189
|
-
locale: "de"
|
|
190
|
-
};
|
|
191
|
-
var ABSENT_ID = "00000000-0000-7000-8000-0000000affff";
|
|
192
|
-
var SCENE_PAYLOAD = {
|
|
193
|
-
nodes: [{ node_id: "tisch", type: "object", semantic: { description: "ein Tisch" } }],
|
|
194
|
-
relations: []
|
|
195
|
-
};
|
|
196
|
-
var CAMERA_PRESET_PAYLOAD = {
|
|
197
|
-
name: "50mm",
|
|
198
|
-
projection: "perspective",
|
|
199
|
-
lens: { focal_length_mm: 50, sensor_width_mm: 36 },
|
|
200
|
-
focus_policy: "autofocus_on_framing_target"
|
|
201
|
-
};
|
|
202
|
-
var ContractViolation = class extends Error {
|
|
203
|
-
};
|
|
204
|
-
var fail = (message) => {
|
|
205
|
-
throw new ContractViolation(message);
|
|
206
|
-
};
|
|
207
|
-
var show = (value) => {
|
|
208
|
-
try {
|
|
209
|
-
return JSON.stringify(value);
|
|
210
|
-
} catch {
|
|
211
|
-
return String(value);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
var isTrue = (condition, message) => {
|
|
215
|
-
if (!condition) fail(message);
|
|
216
|
-
};
|
|
217
|
-
var equal = (actual, expected, what) => {
|
|
218
|
-
if (actual !== expected) fail(`${what}: erwartet ${show(expected)}, war ${show(actual)}`);
|
|
219
|
-
};
|
|
220
|
-
var canonical = (value) => {
|
|
221
|
-
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
222
|
-
if (value && typeof value === "object") {
|
|
223
|
-
const entries = Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`);
|
|
224
|
-
return `{${entries.join(",")}}`;
|
|
225
|
-
}
|
|
226
|
-
return show(value);
|
|
227
|
-
};
|
|
228
|
-
var deepEqual = (actual, expected, what) => {
|
|
229
|
-
if (canonical(actual) !== canonical(expected)) {
|
|
230
|
-
fail(`${what}: erwartet ${show(expected)}, war ${show(actual)}`);
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
var hasLength = (actual, expected, what) => {
|
|
234
|
-
equal(actual?.length ?? -1, expected, `${what} (Anzahl)`);
|
|
235
|
-
};
|
|
236
|
-
function ok(result, what) {
|
|
237
|
-
if (result.kind !== "ok") {
|
|
238
|
-
fail(`${what}: erwartet ok, war "${result.kind}" \u2014 ${show(result)}`);
|
|
239
|
-
}
|
|
240
|
-
return result.value;
|
|
241
|
-
}
|
|
242
|
-
function kindIs(result, expected, what) {
|
|
243
|
-
equal(result.kind, expected, what);
|
|
244
|
-
}
|
|
245
|
-
async function snapshotOf(store, elementId) {
|
|
246
|
-
const read = await store.getElement(elementId);
|
|
247
|
-
if (read.kind !== "ok") {
|
|
248
|
-
throw new ContractViolation(`getElement: erwartet ok, war ${show(read)}`);
|
|
249
|
-
}
|
|
250
|
-
if (!read.value) {
|
|
251
|
-
throw new ContractViolation(`getElement(${elementId}): erwartet einen Stand, war null`);
|
|
252
|
-
}
|
|
253
|
-
return read.value;
|
|
254
|
-
}
|
|
255
|
-
async function seedElement(store, type = "style", title = "Kohle", contextId) {
|
|
256
|
-
const element = ok(await store.createElement({ type, title, contextId }), "createElement");
|
|
257
|
-
return element.element_id;
|
|
258
|
-
}
|
|
259
|
-
async function seedVersion(store, elementId, payload = STYLE_PAYLOAD, parents) {
|
|
260
|
-
return ok(
|
|
261
|
-
await store.publishVersion({
|
|
262
|
-
elementId,
|
|
263
|
-
payload,
|
|
264
|
-
schemaVersion: "1.0.0",
|
|
265
|
-
publishedBy: "vertrag",
|
|
266
|
-
parents
|
|
267
|
-
}),
|
|
268
|
-
"publishVersion"
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
async function seedSceneSetupUmgebung(store) {
|
|
272
|
-
const sceneId = await seedElement(store, "scene", "Szene");
|
|
273
|
-
const scene = await seedVersion(store, sceneId, SCENE_PAYLOAD);
|
|
274
|
-
const presetElement = ok(
|
|
275
|
-
await store.createElement({ type: "camera_preset", title: "50mm" }),
|
|
276
|
-
"createElement(camera_preset)"
|
|
277
|
-
);
|
|
278
|
-
const preset = await seedVersion(store, presetElement.element_id, CAMERA_PRESET_PAYLOAD);
|
|
279
|
-
const setupElement = ok(
|
|
280
|
-
await store.createElement({ type: "scene_setup", title: "Aufbau" }),
|
|
281
|
-
"createElement(scene_setup)"
|
|
282
|
-
);
|
|
283
|
-
return {
|
|
284
|
-
elementId: setupElement.element_id,
|
|
285
|
-
/** Ein Aufbau mit genau diesen Kamerakennungen. */
|
|
286
|
-
payloadMit(cameraIds, size = "wide_shot") {
|
|
287
|
-
return {
|
|
288
|
-
scene_ref: { element_id: sceneId, version_id: scene.version_id },
|
|
289
|
-
camera_rig: {
|
|
290
|
-
cameras: cameraIds.map((camera_id) => ({
|
|
291
|
-
camera_id,
|
|
292
|
-
preset_ref: {
|
|
293
|
-
element_id: presetElement.element_id,
|
|
294
|
-
version_id: preset.version_id
|
|
295
|
-
},
|
|
296
|
-
placement: { mode: "absolute", position: [0, -3, 1.6] },
|
|
297
|
-
orientation: { mode: "look_at", target: { node_ref: "tisch" } },
|
|
298
|
-
framing: { size, target: { node_ref: "tisch" } }
|
|
299
|
-
}))
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
function elementStoreContractChecks() {
|
|
306
|
-
const checks = [];
|
|
307
|
-
const check = (group, name, run, requires) => checks.push({ group, name, run, requires });
|
|
308
|
-
check("Anlegen und Lesen", "gibt ein angelegtes Element unveraendert zurueck", async (store) => {
|
|
309
|
-
const element = ok(
|
|
310
|
-
await store.createElement({ type: "style", title: "Kohle", contextId: "ctx" }),
|
|
311
|
-
"createElement"
|
|
312
|
-
);
|
|
313
|
-
equal(element.type, "style", "type");
|
|
314
|
-
equal(element.context_id, "ctx", "context_id");
|
|
315
|
-
equal(element.retired, false, "retired");
|
|
316
|
-
const snapshot = await snapshotOf(store, element.element_id);
|
|
317
|
-
deepEqual(snapshot.element, element, "gelesenes Element");
|
|
318
|
-
equal(snapshot.metadata?.title, "Kohle", "Titel");
|
|
319
|
-
equal(snapshot.metadata?.revision, 1, "Metadaten-Revision");
|
|
320
|
-
hasLength(snapshot.versions, 0, "Versionen");
|
|
321
|
-
equal(snapshot.draft, null, "Draft");
|
|
322
|
-
equal(snapshot.draftFork, null, "Draft-Fork");
|
|
323
|
-
});
|
|
324
|
-
check("Anlegen und Lesen", "liefert null fuer ein unbekanntes Element, keinen Fehler", async (store) => {
|
|
325
|
-
const read = await store.getElement(ABSENT_ID);
|
|
326
|
-
kindIs(read, "ok", "getElement auf Unbekanntes");
|
|
327
|
-
equal(read.kind === "ok" ? read.value : void 0, null, "Ergebnis");
|
|
328
|
-
});
|
|
329
|
-
check("Anlegen und Lesen", "vergibt fuer jedes Element eine eigene Kennung", async (store) => {
|
|
330
|
-
const a = await seedElement(store, "style", "A");
|
|
331
|
-
const b = await seedElement(store, "style", "B");
|
|
332
|
-
isTrue(a !== b, `Kennungen muessen sich unterscheiden, beide waren ${a}`);
|
|
333
|
-
});
|
|
334
|
-
check("Anlegen und Lesen", "filtert nach Typ und Kontext", async (store) => {
|
|
335
|
-
await seedElement(store, "style", "A", "ctx1");
|
|
336
|
-
await seedElement(store, "scene", "B", "ctx1");
|
|
337
|
-
await seedElement(store, "style", "C", "ctx2");
|
|
338
|
-
const byContext = await store.listElements({ contextId: "ctx1" });
|
|
339
|
-
isTrue(byContext.kind === "ok", "listElements nach Kontext");
|
|
340
|
-
hasLength(byContext.kind === "ok" ? byContext.value : void 0, 2, "Elemente in ctx1");
|
|
341
|
-
if (byContext.kind === "ok") {
|
|
342
|
-
equal(byContext.value.find((element) => element.type === "style")?.title, "A", "Titel in ElementRecord");
|
|
343
|
-
equal(byContext.value.find((element) => element.type === "scene")?.title, "B", "Titel in ElementRecord");
|
|
344
|
-
}
|
|
345
|
-
const byType = await store.listElements({ contextId: "ctx1", type: "style" });
|
|
346
|
-
hasLength(byType.kind === "ok" ? byType.value : void 0, 1, "style-Elemente in ctx1");
|
|
347
|
-
const byTypes = await store.listElements({ contextId: "ctx1", types: ["style", "scene"] });
|
|
348
|
-
hasLength(byTypes.kind === "ok" ? byTypes.value : void 0, 2, "style- und scene-Elemente in ctx1");
|
|
349
|
-
});
|
|
350
|
-
check("Versionszugriff", "liefert eine veroeffentlichte Version mit Typ und Sichtbarkeit", async (store) => {
|
|
351
|
-
const elementId = await seedElement(store, "style", "Kohle", "ctx");
|
|
352
|
-
const version = await seedVersion(store, elementId);
|
|
353
|
-
const read = await store.getVersion(version.version_id);
|
|
354
|
-
kindIs(read, "ok", "getVersion");
|
|
355
|
-
const value = read.kind === "ok" ? read.value : null;
|
|
356
|
-
isTrue(value !== null, `getVersion(${version.version_id}) lieferte null`);
|
|
357
|
-
equal(value.version_id, version.version_id, "version_id");
|
|
358
|
-
equal(value.element_id, elementId, "element_id");
|
|
359
|
-
equal(value.type, "style", "type");
|
|
360
|
-
equal(value.visible, true, "visible");
|
|
361
|
-
});
|
|
362
|
-
check("Versionszugriff", "liefert null fuer eine unbekannte Version, keinen Fehler", async (store) => {
|
|
363
|
-
const read = await store.getVersion(ABSENT_ID);
|
|
364
|
-
kindIs(read, "ok", "getVersion auf Unbekanntes");
|
|
365
|
-
equal(read.kind === "ok" ? read.value : void 0, null, "Ergebnis");
|
|
366
|
-
});
|
|
367
|
-
check("Versionszugriff", "gibt einen Entwurf nicht als Version aus", async (store) => {
|
|
368
|
-
const elementId = await seedElement(store);
|
|
369
|
-
const draft = ok(
|
|
370
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
371
|
-
"writeDraft"
|
|
372
|
-
);
|
|
373
|
-
const read = await store.getVersion(draft.draft_id);
|
|
374
|
-
kindIs(read, "ok", "getVersion auf eine Draft-Kennung");
|
|
375
|
-
equal(read.kind === "ok" ? read.value : void 0, null, "Ergebnis");
|
|
376
|
-
});
|
|
377
|
-
check(
|
|
378
|
-
"Versionszugriff",
|
|
379
|
-
"meldet eine Version stillgelegt statt sie zu verschweigen",
|
|
380
|
-
async (store) => {
|
|
381
|
-
const elementId = await seedElement(store);
|
|
382
|
-
const version = await seedVersion(store, elementId);
|
|
383
|
-
ok(await store.retireElement(elementId), "retireElement");
|
|
384
|
-
const read = await store.getVersion(version.version_id);
|
|
385
|
-
kindIs(read, "ok", "getVersion nach Stilllegung");
|
|
386
|
-
const value = read.kind === "ok" ? read.value : null;
|
|
387
|
-
isTrue(value !== null, "stillgelegte Version wurde verschwiegen statt ausgewiesen");
|
|
388
|
-
equal(value.visible, false, "visible");
|
|
389
|
-
},
|
|
390
|
-
"retireElement"
|
|
391
|
-
);
|
|
392
|
-
const seedTargetModel = async (store, key, contextId, options = {}) => {
|
|
393
|
-
const element = ok(
|
|
394
|
-
await store.createElement({
|
|
395
|
-
type: "target_model",
|
|
396
|
-
title: options.name ?? key,
|
|
397
|
-
contextId
|
|
398
|
-
}),
|
|
399
|
-
"createElement(target_model)"
|
|
400
|
-
);
|
|
401
|
-
const version = await seedVersion(store, element.element_id, {
|
|
402
|
-
key,
|
|
403
|
-
name: options.name ?? key,
|
|
404
|
-
provider: "google",
|
|
405
|
-
prompt_language: "en",
|
|
406
|
-
supports_negative_prompt: false,
|
|
407
|
-
supports_weighting: false,
|
|
408
|
-
supported_control_inputs: []
|
|
409
|
-
});
|
|
410
|
-
if (options.retired) ok(await store.retireElement(element.element_id), "retireElement");
|
|
411
|
-
return { elementId: element.element_id, versionId: version.version_id };
|
|
412
|
-
};
|
|
413
|
-
const seedShot = async (store, contextId) => {
|
|
414
|
-
const element = ok(
|
|
415
|
-
await store.createElement({ type: "shot", title: "Shot", contextId }),
|
|
416
|
-
"createElement(shot)"
|
|
417
|
-
);
|
|
418
|
-
return element.element_id;
|
|
419
|
-
};
|
|
420
|
-
const resolved = async (store, input) => {
|
|
421
|
-
const result = await store.resolveTargetModel(input);
|
|
422
|
-
kindIs(result, "ok", `resolveTargetModel(${input.key})`);
|
|
423
|
-
return result.kind === "ok" ? result.value : fail("unerreichbar");
|
|
424
|
-
};
|
|
425
|
-
check("Zielmodell", "B13b \u2014 findet ein Modell im direkten Kontext", async (store) => {
|
|
426
|
-
const model = await seedTargetModel(store, "imagen_4", "ctx");
|
|
427
|
-
const shot = await seedShot(store, "ctx");
|
|
428
|
-
const value = await resolved(store, {
|
|
429
|
-
key: "imagen_4",
|
|
430
|
-
forElementId: shot,
|
|
431
|
-
contextChain: ["ctx", null]
|
|
432
|
-
});
|
|
433
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
434
|
-
if (value.kind !== "resolved") return;
|
|
435
|
-
equal(value.elementId, model.elementId, "elementId");
|
|
436
|
-
equal(value.versionId, model.versionId, "versionId");
|
|
437
|
-
equal(value.chainIndex, 0, "chainIndex");
|
|
438
|
-
hasLength(value.shadowedRetired, 0, "shadowedRetired");
|
|
439
|
-
});
|
|
440
|
-
check("Zielmodell", "B13c \u2014 wertet einen geerbten Zwischenkontext aus", async (store) => {
|
|
441
|
-
const model = await seedTargetModel(store, "imagen_4", "eltern");
|
|
442
|
-
const shot = await seedShot(store, "kind");
|
|
443
|
-
const value = await resolved(store, {
|
|
444
|
-
key: "imagen_4",
|
|
445
|
-
forElementId: shot,
|
|
446
|
-
contextChain: ["kind", "eltern", null]
|
|
447
|
-
});
|
|
448
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
449
|
-
if (value.kind !== "resolved") return;
|
|
450
|
-
equal(value.elementId, model.elementId, "elementId");
|
|
451
|
-
equal(value.chainIndex, 1, "chainIndex \u2014 der Zwischenkontext");
|
|
452
|
-
});
|
|
453
|
-
check("Zielmodell", "B13d \u2014 faellt auf den globalen Kontext zurueck", async (store) => {
|
|
454
|
-
const model = await seedTargetModel(store, "imagen_4", void 0);
|
|
455
|
-
const shot = await seedShot(store, "ctx");
|
|
456
|
-
const value = await resolved(store, {
|
|
457
|
-
key: "imagen_4",
|
|
458
|
-
forElementId: shot,
|
|
459
|
-
contextChain: ["ctx", null]
|
|
460
|
-
});
|
|
461
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
462
|
-
if (value.kind !== "resolved") return;
|
|
463
|
-
equal(value.elementId, model.elementId, "elementId");
|
|
464
|
-
equal(value.contextId, null, "contextId \u2014 global");
|
|
465
|
-
equal(value.chainIndex, 1, "chainIndex \u2014 das letzte Glied");
|
|
466
|
-
});
|
|
467
|
-
check("Zielmodell", "B13e \u2014 das fruehere Kettenglied gewinnt, ohne Mehrdeutigkeit", async (store) => {
|
|
468
|
-
const nah = await seedTargetModel(store, "imagen_4", "ctx", { name: "lokal" });
|
|
469
|
-
await seedTargetModel(store, "imagen_4", void 0, { name: "global" });
|
|
470
|
-
const shot = await seedShot(store, "ctx");
|
|
471
|
-
const value = await resolved(store, {
|
|
472
|
-
key: "imagen_4",
|
|
473
|
-
forElementId: shot,
|
|
474
|
-
contextChain: ["ctx", null]
|
|
475
|
-
});
|
|
476
|
-
equal(value.kind, "resolved", "Ausgang \u2014 Rangfolge, nicht ambiguous");
|
|
477
|
-
if (value.kind !== "resolved") return;
|
|
478
|
-
equal(value.elementId, nah.elementId, "der naehere Treffer gewinnt");
|
|
479
|
-
equal(value.chainIndex, 0, "chainIndex");
|
|
480
|
-
});
|
|
481
|
-
check("Zielmodell", "B13e \u2014 der Zwischenkontext schlaegt global", async (store) => {
|
|
482
|
-
const mitte = await seedTargetModel(store, "imagen_4", "eltern", { name: "geerbt" });
|
|
483
|
-
await seedTargetModel(store, "imagen_4", void 0, { name: "global" });
|
|
484
|
-
const shot = await seedShot(store, "kind");
|
|
485
|
-
const value = await resolved(store, {
|
|
486
|
-
key: "imagen_4",
|
|
487
|
-
forElementId: shot,
|
|
488
|
-
contextChain: ["kind", "eltern", null]
|
|
489
|
-
});
|
|
490
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
491
|
-
if (value.kind !== "resolved") return;
|
|
492
|
-
equal(value.elementId, mitte.elementId, "der geerbte Treffer gewinnt");
|
|
493
|
-
});
|
|
494
|
-
check("Zielmodell", "B13f \u2014 zwei Treffer auf demselben Glied sind mehrdeutig", async (store) => {
|
|
495
|
-
await seedTargetModel(store, "imagen_4", "ctx", { name: "A" });
|
|
496
|
-
await seedTargetModel(store, "imagen_4", "ctx", { name: "B" });
|
|
497
|
-
const shot = await seedShot(store, "ctx");
|
|
498
|
-
const value = await resolved(store, {
|
|
499
|
-
key: "imagen_4",
|
|
500
|
-
forElementId: shot,
|
|
501
|
-
contextChain: ["ctx", null]
|
|
502
|
-
});
|
|
503
|
-
equal(value.kind, "ambiguous", "Ausgang");
|
|
504
|
-
if (value.kind !== "ambiguous") return;
|
|
505
|
-
equal(value.chainIndex, 0, "chainIndex");
|
|
506
|
-
hasLength(value.candidates, 2, "Kandidaten");
|
|
507
|
-
});
|
|
508
|
-
check(
|
|
509
|
-
"Zielmodell",
|
|
510
|
-
"B13g \u2014 eine Stilllegung sperrt den Fallback nicht, bleibt aber sichtbar",
|
|
511
|
-
async (store) => {
|
|
512
|
-
const lokal = await seedTargetModel(store, "imagen_4", "ctx", { retired: true });
|
|
513
|
-
const global = await seedTargetModel(store, "imagen_4", void 0);
|
|
514
|
-
const shot = await seedShot(store, "ctx");
|
|
515
|
-
const value = await resolved(store, {
|
|
516
|
-
key: "imagen_4",
|
|
517
|
-
forElementId: shot,
|
|
518
|
-
contextChain: ["ctx", null]
|
|
519
|
-
});
|
|
520
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
521
|
-
if (value.kind !== "resolved") return;
|
|
522
|
-
equal(value.elementId, global.elementId, "der globale Treffer greift");
|
|
523
|
-
hasLength(value.shadowedRetired, 1, "shadowedRetired");
|
|
524
|
-
equal(value.shadowedRetired[0]?.elementId, lokal.elementId, "uebergangener Kandidat");
|
|
525
|
-
},
|
|
526
|
-
"retireElement"
|
|
527
|
-
);
|
|
528
|
-
check(
|
|
529
|
-
"Zielmodell",
|
|
530
|
-
'B13h \u2014 sind alle Kandidaten stillgelegt, ist das nicht "nicht gefunden"',
|
|
531
|
-
async (store) => {
|
|
532
|
-
const a = await seedTargetModel(store, "imagen_4", "ctx", { retired: true, name: "A" });
|
|
533
|
-
const b = await seedTargetModel(store, "imagen_4", void 0, { retired: true, name: "B" });
|
|
534
|
-
const shot = await seedShot(store, "ctx");
|
|
535
|
-
const value = await resolved(store, {
|
|
536
|
-
key: "imagen_4",
|
|
537
|
-
forElementId: shot,
|
|
538
|
-
contextChain: ["ctx", null]
|
|
539
|
-
});
|
|
540
|
-
equal(value.kind, "retired", "Ausgang");
|
|
541
|
-
if (value.kind !== "retired") return;
|
|
542
|
-
hasLength(value.candidates, 2, "Kandidaten");
|
|
543
|
-
const ids = value.candidates.map((candidate) => candidate.elementId).sort();
|
|
544
|
-
deepEqual(ids, [a.elementId, b.elementId].sort(), "Kandidatenkennungen");
|
|
545
|
-
},
|
|
546
|
-
"retireElement"
|
|
547
|
-
);
|
|
548
|
-
check("Zielmodell", "B13a \u2014 meldet einen fehlenden Key mit der durchsuchten Kette", async (store) => {
|
|
549
|
-
await seedTargetModel(store, "sdxl", "ctx");
|
|
550
|
-
const shot = await seedShot(store, "ctx");
|
|
551
|
-
const value = await resolved(store, {
|
|
552
|
-
key: "imagen_4",
|
|
553
|
-
forElementId: shot,
|
|
554
|
-
contextChain: ["ctx", null]
|
|
555
|
-
});
|
|
556
|
-
equal(value.kind, "not_found", "Ausgang");
|
|
557
|
-
if (value.kind !== "not_found") return;
|
|
558
|
-
deepEqual(value.chain, ["ctx", null], "durchsuchte Kette");
|
|
559
|
-
});
|
|
560
|
-
check("Zielmodell", "B13a \u2014 ein anderer Elementtyp mit gleichem Key ist kein Treffer", async (store) => {
|
|
561
|
-
const fremd = ok(
|
|
562
|
-
await store.createElement({ type: "style", title: "Falle", contextId: "ctx" }),
|
|
563
|
-
"createElement(style)"
|
|
564
|
-
);
|
|
565
|
-
await seedVersion(store, fremd.element_id, STYLE_PAYLOAD);
|
|
566
|
-
const shot = await seedShot(store, "ctx");
|
|
567
|
-
const value = await resolved(store, {
|
|
568
|
-
key: "imagen_4",
|
|
569
|
-
forElementId: shot,
|
|
570
|
-
contextChain: ["ctx", null]
|
|
571
|
-
});
|
|
572
|
-
equal(value.kind, "not_found", "Ausgang");
|
|
573
|
-
});
|
|
574
|
-
check(
|
|
575
|
-
"Zielmodell",
|
|
576
|
-
"B13i \u2014 mehrere Heads ohne greifende Auswahl blockieren",
|
|
577
|
-
async (store) => {
|
|
578
|
-
const element = ok(
|
|
579
|
-
await store.createElement({ type: "target_model", title: "imagen", contextId: "ctx" }),
|
|
580
|
-
"createElement(target_model)"
|
|
581
|
-
);
|
|
582
|
-
const payload = {
|
|
583
|
-
key: "imagen_4",
|
|
584
|
-
name: "Imagen 4",
|
|
585
|
-
provider: "google",
|
|
586
|
-
prompt_language: "en",
|
|
587
|
-
supports_negative_prompt: false,
|
|
588
|
-
supports_weighting: false,
|
|
589
|
-
supported_control_inputs: []
|
|
590
|
-
};
|
|
591
|
-
const basis = await seedVersion(store, element.element_id, payload);
|
|
592
|
-
await seedVersion(store, element.element_id, { ...payload, name: "A" }, [
|
|
593
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
594
|
-
]);
|
|
595
|
-
await seedVersion(store, element.element_id, { ...payload, name: "B" }, [
|
|
596
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
597
|
-
]);
|
|
598
|
-
const shot = await seedShot(store, "ctx");
|
|
599
|
-
const value = await resolved(store, {
|
|
600
|
-
key: "imagen_4",
|
|
601
|
-
forElementId: shot,
|
|
602
|
-
contextChain: ["ctx", null]
|
|
603
|
-
});
|
|
604
|
-
equal(value.kind, "fork", "Ausgang");
|
|
605
|
-
if (value.kind !== "fork") return;
|
|
606
|
-
hasLength(value.heads, 2, "Heads");
|
|
607
|
-
}
|
|
608
|
-
);
|
|
609
|
-
check(
|
|
610
|
-
"Zielmodell",
|
|
611
|
-
"B13i \u2014 eine greifende Auswahl loest den Fork auf",
|
|
612
|
-
async (store) => {
|
|
613
|
-
const element = ok(
|
|
614
|
-
await store.createElement({ type: "target_model", title: "imagen", contextId: "ctx" }),
|
|
615
|
-
"createElement(target_model)"
|
|
616
|
-
);
|
|
617
|
-
const payload = {
|
|
618
|
-
key: "imagen_4",
|
|
619
|
-
name: "Imagen 4",
|
|
620
|
-
provider: "google",
|
|
621
|
-
prompt_language: "en",
|
|
622
|
-
supports_negative_prompt: false,
|
|
623
|
-
supports_weighting: false,
|
|
624
|
-
supported_control_inputs: []
|
|
625
|
-
};
|
|
626
|
-
const basis = await seedVersion(store, element.element_id, payload);
|
|
627
|
-
const a = await seedVersion(store, element.element_id, { ...payload, name: "A" }, [
|
|
628
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
629
|
-
]);
|
|
630
|
-
await seedVersion(store, element.element_id, { ...payload, name: "B" }, [
|
|
631
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
632
|
-
]);
|
|
633
|
-
ok(
|
|
634
|
-
await store.setPreferredHead({
|
|
635
|
-
elementId: element.element_id,
|
|
636
|
-
contextId: "ctx",
|
|
637
|
-
versionId: a.version_id,
|
|
638
|
-
expectedRevision: 0,
|
|
639
|
-
selectedBy: "vertrag"
|
|
640
|
-
}),
|
|
641
|
-
"setPreferredHead"
|
|
642
|
-
);
|
|
643
|
-
const shot = await seedShot(store, "ctx");
|
|
644
|
-
const value = await resolved(store, {
|
|
645
|
-
key: "imagen_4",
|
|
646
|
-
forElementId: shot,
|
|
647
|
-
contextChain: ["ctx", null]
|
|
648
|
-
});
|
|
649
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
650
|
-
if (value.kind !== "resolved") return;
|
|
651
|
-
equal(value.versionId, a.version_id, "die gewaehlte Version");
|
|
652
|
-
},
|
|
653
|
-
"setPreferredHead"
|
|
654
|
-
);
|
|
655
|
-
check("Zielmodell", "B13j \u2014 Suche und Head-Aufloesung sehen dieselbe Kette", async (store) => {
|
|
656
|
-
const element = ok(
|
|
657
|
-
await store.createElement({ type: "target_model", title: "imagen" }),
|
|
658
|
-
"createElement(target_model)"
|
|
659
|
-
);
|
|
660
|
-
const payload = {
|
|
661
|
-
key: "imagen_4",
|
|
662
|
-
name: "Imagen 4",
|
|
663
|
-
provider: "google",
|
|
664
|
-
prompt_language: "en",
|
|
665
|
-
supports_negative_prompt: false,
|
|
666
|
-
supports_weighting: false,
|
|
667
|
-
supported_control_inputs: []
|
|
668
|
-
};
|
|
669
|
-
const basis = await seedVersion(store, element.element_id, payload);
|
|
670
|
-
const a = await seedVersion(store, element.element_id, { ...payload, name: "A" }, [
|
|
671
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
672
|
-
]);
|
|
673
|
-
await seedVersion(store, element.element_id, { ...payload, name: "B" }, [
|
|
674
|
-
{ parent_version_id: basis.version_id, relation: "derived_from" }
|
|
675
|
-
]);
|
|
676
|
-
ok(
|
|
677
|
-
await store.setPreferredHead({
|
|
678
|
-
elementId: element.element_id,
|
|
679
|
-
contextId: "eltern",
|
|
680
|
-
versionId: a.version_id,
|
|
681
|
-
expectedRevision: 0,
|
|
682
|
-
selectedBy: "vertrag"
|
|
683
|
-
}),
|
|
684
|
-
"setPreferredHead"
|
|
685
|
-
);
|
|
686
|
-
const shot = await seedShot(store, "kind");
|
|
687
|
-
const value = await resolved(store, {
|
|
688
|
-
key: "imagen_4",
|
|
689
|
-
forElementId: shot,
|
|
690
|
-
contextChain: ["kind", "eltern", null]
|
|
691
|
-
});
|
|
692
|
-
equal(value.kind, "resolved", "Ausgang");
|
|
693
|
-
if (value.kind !== "resolved") return;
|
|
694
|
-
equal(value.versionId, a.version_id, "die im Zwischenkontext gewaehlte Version");
|
|
695
|
-
}, "setPreferredHead");
|
|
696
|
-
check("Zielmodell", "B13k \u2014 eine Kette, die nicht zum Element gehoert, wird abgelehnt", async (store) => {
|
|
697
|
-
await seedTargetModel(store, "imagen_4", "ctx");
|
|
698
|
-
const shot = await seedShot(store, "ctx");
|
|
699
|
-
const result = await store.resolveTargetModel({
|
|
700
|
-
key: "imagen_4",
|
|
701
|
-
forElementId: shot,
|
|
702
|
-
contextChain: ["fremd", null]
|
|
703
|
-
});
|
|
704
|
-
kindIs(result, "error", "resolveTargetModel mit fremder Kette");
|
|
705
|
-
});
|
|
706
|
-
check("Zielmodell", "B13k \u2014 eine leere Kette wird abgelehnt, nicht als leere Suche gefahren", async (store) => {
|
|
707
|
-
const shot = await seedShot(store, "ctx");
|
|
708
|
-
const result = await store.resolveTargetModel({
|
|
709
|
-
key: "imagen_4",
|
|
710
|
-
forElementId: shot,
|
|
711
|
-
contextChain: []
|
|
712
|
-
});
|
|
713
|
-
kindIs(result, "error", "resolveTargetModel ohne Kette");
|
|
714
|
-
});
|
|
715
|
-
check("Zielmodell", "B13k \u2014 global mitten in der Kette wird abgelehnt", async (store) => {
|
|
716
|
-
const shot = await seedShot(store, "ctx");
|
|
717
|
-
const result = await store.resolveTargetModel({
|
|
718
|
-
key: "imagen_4",
|
|
719
|
-
forElementId: shot,
|
|
720
|
-
contextChain: ["ctx", null, "eltern"]
|
|
721
|
-
});
|
|
722
|
-
kindIs(result, "error", "resolveTargetModel mit global in der Mitte");
|
|
723
|
-
});
|
|
724
|
-
check("Zielmodell", "B13k \u2014 ein unbekanntes Element wird gemeldet, nicht ignoriert", async (store) => {
|
|
725
|
-
const result = await store.resolveTargetModel({
|
|
726
|
-
key: "imagen_4",
|
|
727
|
-
forElementId: ABSENT_ID,
|
|
728
|
-
contextChain: [null]
|
|
729
|
-
});
|
|
730
|
-
kindIs(result, "error", "resolveTargetModel fuer ein unbekanntes Element");
|
|
731
|
-
});
|
|
732
|
-
check("Zielmodell", "ein Entwurf allein macht ein Zielmodell nicht auffindbar", async (store) => {
|
|
733
|
-
const element = ok(
|
|
734
|
-
await store.createElement({ type: "target_model", title: "imagen", contextId: "ctx" }),
|
|
735
|
-
"createElement(target_model)"
|
|
736
|
-
);
|
|
737
|
-
ok(
|
|
738
|
-
await store.writeDraft({
|
|
739
|
-
elementId: element.element_id,
|
|
740
|
-
payload: {
|
|
741
|
-
key: "imagen_4",
|
|
742
|
-
name: "Imagen 4",
|
|
743
|
-
provider: "google",
|
|
744
|
-
prompt_language: "en",
|
|
745
|
-
supports_negative_prompt: false,
|
|
746
|
-
supports_weighting: false,
|
|
747
|
-
supported_control_inputs: []
|
|
748
|
-
},
|
|
749
|
-
expectedRevision: 0
|
|
750
|
-
}),
|
|
751
|
-
"writeDraft"
|
|
752
|
-
);
|
|
753
|
-
const shot = await seedShot(store, "ctx");
|
|
754
|
-
const value = await resolved(store, {
|
|
755
|
-
key: "imagen_4",
|
|
756
|
-
forElementId: shot,
|
|
757
|
-
contextChain: ["ctx", null]
|
|
758
|
-
});
|
|
759
|
-
equal(value.kind, "not_found", "Ausgang");
|
|
760
|
-
});
|
|
761
|
-
check("Eingaben \xA76", "lehnt einen unbekannten Elementtyp ab", async (store) => {
|
|
762
|
-
const result = await store.createElement({
|
|
763
|
-
type: "weltmodell",
|
|
764
|
-
title: "X"
|
|
765
|
-
});
|
|
766
|
-
kindIs(result, "error", "createElement mit unbekanntem Typ");
|
|
767
|
-
});
|
|
768
|
-
check("Eingaben \xA76", "lehnt einen leeren Titel ab", async (store) => {
|
|
769
|
-
kindIs(
|
|
770
|
-
await store.createElement({ type: "style", title: " " }),
|
|
771
|
-
"error",
|
|
772
|
-
"createElement mit leerem Titel"
|
|
773
|
-
);
|
|
774
|
-
});
|
|
775
|
-
check("Eingaben \xA76", "lehnt eine erwartete Revision ab, die keine Zahl ist", async (store) => {
|
|
776
|
-
const elementId = await seedElement(store);
|
|
777
|
-
const result = await store.writeDraft({
|
|
778
|
-
elementId,
|
|
779
|
-
payload: STYLE_PAYLOAD,
|
|
780
|
-
expectedRevision: Number.NaN
|
|
781
|
-
});
|
|
782
|
-
kindIs(result, "error", "writeDraft mit NaN als erwarteter Revision");
|
|
783
|
-
});
|
|
784
|
-
check("Eingaben \xA76", "lehnt eine negative erwartete Revision ab", async (store) => {
|
|
785
|
-
const elementId = await seedElement(store);
|
|
786
|
-
kindIs(
|
|
787
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: -1 }),
|
|
788
|
-
"error",
|
|
789
|
-
"writeDraft mit negativer Revision"
|
|
790
|
-
);
|
|
791
|
-
});
|
|
792
|
-
check("Eingaben \xA76", "lehnt parents ab, das kein Array ist", async (store) => {
|
|
793
|
-
const elementId = await seedElement(store);
|
|
794
|
-
const result = await store.publishVersion({
|
|
795
|
-
elementId,
|
|
796
|
-
payload: STYLE_PAYLOAD,
|
|
797
|
-
schemaVersion: "1.0.0",
|
|
798
|
-
publishedBy: "vertrag",
|
|
799
|
-
parents: "kaputt"
|
|
800
|
-
});
|
|
801
|
-
kindIs(result, "error", "publishVersion mit parents als String");
|
|
802
|
-
});
|
|
803
|
-
check("Eingaben \xA76", "lehnt einen Parent-Eintrag ohne relation ab", async (store) => {
|
|
804
|
-
const elementId = await seedElement(store);
|
|
805
|
-
const version = await seedVersion(store, elementId);
|
|
806
|
-
const result = await store.publishVersion({
|
|
807
|
-
elementId,
|
|
808
|
-
payload: STYLE_PAYLOAD_V2,
|
|
809
|
-
schemaVersion: "1.0.0",
|
|
810
|
-
publishedBy: "vertrag",
|
|
811
|
-
parents: [{ parent_version_id: version.version_id }]
|
|
812
|
-
});
|
|
813
|
-
kindIs(result, "error", "publishVersion mit unvollstaendigem Parent");
|
|
814
|
-
});
|
|
815
|
-
check("Eingaben \xA76", "meldet Eingabefehler als endgueltig, nicht als wiederholbar", async (store) => {
|
|
816
|
-
const result = await store.createElement({ type: "weltmodell", title: "X" });
|
|
817
|
-
if (result.kind === "error") {
|
|
818
|
-
equal(result.retryable, false, "retryable bei Eingabefehler");
|
|
819
|
-
}
|
|
820
|
-
});
|
|
821
|
-
check("Drafts \xA73.1", "schreibt den ersten Draft auf Revision 1", async (store) => {
|
|
822
|
-
const elementId = await seedElement(store);
|
|
823
|
-
const draft = ok(
|
|
824
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
825
|
-
"writeDraft"
|
|
826
|
-
);
|
|
827
|
-
equal(draft.revision, 1, "Revision des ersten Drafts");
|
|
828
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
829
|
-
deepEqual(snapshot.draft?.payload, STYLE_PAYLOAD, "gelesene Draft-Payload");
|
|
830
|
-
equal(snapshot.draft?.revision, 1, "gelesene Draft-Revision");
|
|
831
|
-
});
|
|
832
|
-
check("Drafts \xA73.1", "zaehlt die Revision bei jedem Schreiben hoch", async (store) => {
|
|
833
|
-
const elementId = await seedElement(store);
|
|
834
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 });
|
|
835
|
-
const second = ok(
|
|
836
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD_V2, expectedRevision: 1 }),
|
|
837
|
-
"zweiter writeDraft"
|
|
838
|
-
);
|
|
839
|
-
equal(second.revision, 2, "Revision nach zweitem Schreiben");
|
|
840
|
-
});
|
|
841
|
-
check("Drafts \xA73.1", "haelt die Draft-Kennung ueber Fortschreibungen stabil", async (store) => {
|
|
842
|
-
const elementId = await seedElement(store);
|
|
843
|
-
const first = ok(
|
|
844
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
845
|
-
"erster writeDraft"
|
|
846
|
-
);
|
|
847
|
-
const second = ok(
|
|
848
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD_V2, expectedRevision: 1 }),
|
|
849
|
-
"zweiter writeDraft"
|
|
850
|
-
);
|
|
851
|
-
equal(second.draft_id, first.draft_id, "draft_id");
|
|
852
|
-
});
|
|
853
|
-
check("Drafts \xA73.1", "haelt die Draft-Kennung auch ueber ein Publish hinweg", async (store) => {
|
|
854
|
-
const elementId = await seedElement(store);
|
|
855
|
-
const entwurf = ok(
|
|
856
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
857
|
-
"erster writeDraft"
|
|
858
|
-
);
|
|
859
|
-
ok(
|
|
860
|
-
await store.publishVersion({
|
|
861
|
-
elementId,
|
|
862
|
-
payload: STYLE_PAYLOAD,
|
|
863
|
-
schemaVersion: "1.0.0",
|
|
864
|
-
publishedBy: "contract"
|
|
865
|
-
}),
|
|
866
|
-
"publishVersion"
|
|
867
|
-
);
|
|
868
|
-
const weiter = ok(
|
|
869
|
-
await store.writeDraft({
|
|
870
|
-
elementId,
|
|
871
|
-
payload: STYLE_PAYLOAD_V2,
|
|
872
|
-
expectedRevision: entwurf.revision
|
|
873
|
-
}),
|
|
874
|
-
"writeDraft nach Publish"
|
|
875
|
-
);
|
|
876
|
-
equal(weiter.draft_id, entwurf.draft_id, "draft_id nach Publish");
|
|
877
|
-
});
|
|
878
|
-
check("Drafts \xA73.1", "nennt im Konflikt den bestehenden Draft mit seiner Kennung", async (store) => {
|
|
879
|
-
const elementId = await seedElement(store);
|
|
880
|
-
const erste = ok(
|
|
881
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
882
|
-
"erster writeDraft"
|
|
883
|
-
);
|
|
884
|
-
const veraltet = await store.writeDraft({
|
|
885
|
-
elementId,
|
|
886
|
-
payload: STYLE_PAYLOAD_V2,
|
|
887
|
-
expectedRevision: 0
|
|
888
|
-
});
|
|
889
|
-
kindIs(veraltet, "conflict", "Schreibversuch auf veralteter Revision");
|
|
890
|
-
if (veraltet.kind === "conflict") {
|
|
891
|
-
equal(veraltet.current?.draft_id, erste.draft_id, "draft_id im Konflikt");
|
|
892
|
-
}
|
|
893
|
-
});
|
|
894
|
-
check("Drafts \xA76.6", "schreibt und liest Kettenmetadaten am Draft", async (store) => {
|
|
895
|
-
const szene = await seedElement(store, "scene", "Kettenszene");
|
|
896
|
-
const geschrieben = ok(
|
|
897
|
-
await store.writeDraft({
|
|
898
|
-
elementId: szene,
|
|
899
|
-
payload: SCENE_PAYLOAD,
|
|
900
|
-
expectedRevision: 0,
|
|
901
|
-
chain: { chain_id: "kette-1", source_run_id: "lauf-1", links: [] }
|
|
902
|
-
}),
|
|
903
|
-
"writeDraft mit Kette"
|
|
904
|
-
);
|
|
905
|
-
equal(geschrieben.chain?.chain_id, "kette-1", "chain_id im Rueckgabewert");
|
|
906
|
-
const gelesen = ok(await store.getElement(szene), "getElement");
|
|
907
|
-
equal(gelesen?.draft?.chain?.chain_id, "kette-1", "chain_id im gelesenen Draft");
|
|
908
|
-
equal(gelesen?.draft?.chain?.source_run_id, "lauf-1", "source_run_id");
|
|
909
|
-
});
|
|
910
|
-
check("Drafts \xA76.6", "laesst einen Draft ohne Kette unveraendert ohne Kette", async (store) => {
|
|
911
|
-
const elementId = await seedElement(store);
|
|
912
|
-
ok(
|
|
913
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 }),
|
|
914
|
-
"writeDraft ohne Kette"
|
|
915
|
-
);
|
|
916
|
-
const gelesen = ok(await store.getElement(elementId), "getElement");
|
|
917
|
-
equal("chain" in (gelesen?.draft ?? {}), false, "chain fehlt am Einzelentwurf");
|
|
918
|
-
});
|
|
919
|
-
check("Drafts \xA76.6", "behaelt die Kette, wenn nur die Payload fortgeschrieben wird", async (store) => {
|
|
920
|
-
const szene = await seedElement(store, "scene", "Kettenszene");
|
|
921
|
-
const erste = ok(
|
|
922
|
-
await store.writeDraft({
|
|
923
|
-
elementId: szene,
|
|
924
|
-
payload: SCENE_PAYLOAD,
|
|
925
|
-
expectedRevision: 0,
|
|
926
|
-
chain: { chain_id: "kette-2", source_run_id: "lauf-2", links: [] }
|
|
927
|
-
}),
|
|
928
|
-
"erster writeDraft"
|
|
929
|
-
);
|
|
930
|
-
ok(
|
|
931
|
-
await store.writeDraft({
|
|
932
|
-
elementId: szene,
|
|
933
|
-
payload: SCENE_PAYLOAD,
|
|
934
|
-
expectedRevision: erste.revision
|
|
935
|
-
}),
|
|
936
|
-
"zweiter writeDraft ohne chain"
|
|
937
|
-
);
|
|
938
|
-
const gelesen = ok(await store.getElement(szene), "getElement");
|
|
939
|
-
equal(gelesen?.draft?.chain?.chain_id, "kette-2", "chain_id nach Fortschreibung");
|
|
940
|
-
});
|
|
941
|
-
check("Drafts \xA76.6", "loest die Kette bei ausdruecklichem null", async (store) => {
|
|
942
|
-
const szene = await seedElement(store, "scene", "Kettenszene");
|
|
943
|
-
const erste = ok(
|
|
944
|
-
await store.writeDraft({
|
|
945
|
-
elementId: szene,
|
|
946
|
-
payload: SCENE_PAYLOAD,
|
|
947
|
-
expectedRevision: 0,
|
|
948
|
-
chain: { chain_id: "kette-3", source_run_id: "lauf-3", links: [] }
|
|
949
|
-
}),
|
|
950
|
-
"erster writeDraft"
|
|
951
|
-
);
|
|
952
|
-
ok(
|
|
953
|
-
await store.writeDraft({
|
|
954
|
-
elementId: szene,
|
|
955
|
-
payload: SCENE_PAYLOAD,
|
|
956
|
-
expectedRevision: erste.revision,
|
|
957
|
-
chain: null
|
|
958
|
-
}),
|
|
959
|
-
"writeDraft mit chain: null"
|
|
960
|
-
);
|
|
961
|
-
const gelesen = ok(await store.getElement(szene), "getElement");
|
|
962
|
-
equal("chain" in (gelesen?.draft ?? {}), false, "chain nach ausdruecklichem null");
|
|
963
|
-
});
|
|
964
|
-
check("Drafts \xA76.6", "lehnt eine Kante am falschen Elementtyp ab", async (store) => {
|
|
965
|
-
const szene = await seedElement(store, "scene", "Kettenszene");
|
|
966
|
-
const abgelehnt = await store.writeDraft({
|
|
967
|
-
elementId: szene,
|
|
968
|
-
payload: SCENE_PAYLOAD,
|
|
969
|
-
expectedRevision: 0,
|
|
970
|
-
chain: {
|
|
971
|
-
chain_id: "kette-4",
|
|
972
|
-
source_run_id: "lauf-4",
|
|
973
|
-
links: [{
|
|
974
|
-
field: "scene_ref",
|
|
975
|
-
target_element_id: ABSENT_ID,
|
|
976
|
-
target_draft_id: ABSENT_ID
|
|
977
|
-
}]
|
|
978
|
-
}
|
|
979
|
-
});
|
|
980
|
-
kindIs(abgelehnt, "error", "writeDraft mit falscher Kante");
|
|
981
|
-
});
|
|
982
|
-
check("Drafts \xA76.6", "lehnt unvollstaendige Kettenmetadaten ab", async (store) => {
|
|
983
|
-
const szene = await seedElement(store, "scene", "Kettenszene");
|
|
984
|
-
const ohneLauf = await store.writeDraft({
|
|
985
|
-
elementId: szene,
|
|
986
|
-
payload: SCENE_PAYLOAD,
|
|
987
|
-
expectedRevision: 0,
|
|
988
|
-
// `source_run_id` fehlt — ohne sie ist die Herkunft nicht rekonstruierbar
|
|
989
|
-
// (B3), und genau das ist die Zusage der Kette.
|
|
990
|
-
chain: { chain_id: "kette-5", links: [] }
|
|
991
|
-
});
|
|
992
|
-
kindIs(ohneLauf, "error", "writeDraft ohne source_run_id");
|
|
993
|
-
});
|
|
994
|
-
check("Drafts \xA73.1", "lehnt eine veraltete Revision ab und liefert den aktuellen Stand", async (store) => {
|
|
995
|
-
const elementId = await seedElement(store);
|
|
996
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 });
|
|
997
|
-
const stale = await store.writeDraft({
|
|
998
|
-
elementId,
|
|
999
|
-
payload: STYLE_PAYLOAD_V2,
|
|
1000
|
-
expectedRevision: 0
|
|
1001
|
-
});
|
|
1002
|
-
kindIs(stale, "conflict", "zweiter Schreibversuch auf veralteter Revision");
|
|
1003
|
-
if (stale.kind === "conflict") {
|
|
1004
|
-
equal(stale.expectedRevision, 0, "gemeldete erwartete Revision");
|
|
1005
|
-
equal(stale.actualRevision, 1, "gemeldete tatsaechliche Revision");
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
|
-
check("Drafts \xA73.1", "schreibt bei einem Konflikt nichts", async (store) => {
|
|
1009
|
-
const elementId = await seedElement(store);
|
|
1010
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD, expectedRevision: 0 });
|
|
1011
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD_V2, expectedRevision: 0 });
|
|
1012
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1013
|
-
deepEqual(snapshot.draft?.payload, STYLE_PAYLOAD, "Payload nach abgelehntem Schreiben");
|
|
1014
|
-
equal(snapshot.draft?.revision, 1, "Revision nach abgelehntem Schreiben");
|
|
1015
|
-
});
|
|
1016
|
-
check("Drafts \xA73.1", "lehnt eine unbekannte base_version_id ab", async (store) => {
|
|
1017
|
-
const elementId = await seedElement(store);
|
|
1018
|
-
const result = await store.writeDraft({
|
|
1019
|
-
elementId,
|
|
1020
|
-
payload: STYLE_PAYLOAD,
|
|
1021
|
-
expectedRevision: 0,
|
|
1022
|
-
baseVersionId: ABSENT_ID
|
|
1023
|
-
});
|
|
1024
|
-
kindIs(result, "error", "writeDraft mit unbekannter base_version_id");
|
|
1025
|
-
});
|
|
1026
|
-
check("Drafts \xA73.1", "lehnt eine base_version_id eines fremden Elements ab", async (store) => {
|
|
1027
|
-
const fremd = await seedElement(store, "style", "Fremd");
|
|
1028
|
-
const fremdeVersion = await seedVersion(store, fremd);
|
|
1029
|
-
const eigenes = await seedElement(store, "scene", "Eigen");
|
|
1030
|
-
const result = await store.writeDraft({
|
|
1031
|
-
elementId: eigenes,
|
|
1032
|
-
payload: { nodes: [] },
|
|
1033
|
-
expectedRevision: 0,
|
|
1034
|
-
baseVersionId: fremdeVersion.version_id
|
|
1035
|
-
});
|
|
1036
|
-
kindIs(result, "error", "writeDraft mit fremder base_version_id");
|
|
1037
|
-
});
|
|
1038
|
-
check("Drafts \xA73.1", "akzeptiert eine eigene base_version_id", async (store) => {
|
|
1039
|
-
const elementId = await seedElement(store);
|
|
1040
|
-
const version = await seedVersion(store, elementId);
|
|
1041
|
-
const draft = ok(
|
|
1042
|
-
await store.writeDraft({
|
|
1043
|
-
elementId,
|
|
1044
|
-
payload: STYLE_PAYLOAD_V2,
|
|
1045
|
-
expectedRevision: 0,
|
|
1046
|
-
baseVersionId: version.version_id
|
|
1047
|
-
}),
|
|
1048
|
-
"writeDraft mit eigener base_version_id"
|
|
1049
|
-
);
|
|
1050
|
-
equal(draft.base_version_id, version.version_id, "base_version_id");
|
|
1051
|
-
});
|
|
1052
|
-
check("Drafts \xA73.1", "meldet einen Draft auf einem unbekannten Element als Fehler", async (store) => {
|
|
1053
|
-
const result = await store.writeDraft({
|
|
1054
|
-
elementId: ABSENT_ID,
|
|
1055
|
-
payload: STYLE_PAYLOAD,
|
|
1056
|
-
expectedRevision: 0
|
|
1057
|
-
});
|
|
1058
|
-
kindIs(result, "error", "writeDraft auf unbekanntes Element");
|
|
1059
|
-
});
|
|
1060
|
-
check("Veroeffentlichen", "veroeffentlicht eine gueltige Payload", async (store) => {
|
|
1061
|
-
const elementId = await seedElement(store);
|
|
1062
|
-
const version = await seedVersion(store, elementId);
|
|
1063
|
-
equal(version.element_id, elementId, "element_id der Version");
|
|
1064
|
-
hasLength(version.parents, 0, "Parents der ersten Version");
|
|
1065
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1066
|
-
hasLength(snapshot.versions, 1, "Versionen nach Veroeffentlichung");
|
|
1067
|
-
deepEqual(snapshot.versions[0].payload, STYLE_PAYLOAD, "gelesene Payload");
|
|
1068
|
-
});
|
|
1069
|
-
check("Veroeffentlichen", "lehnt eine schemawidrige Payload ab \u2014 in JEDEM Port (R-2)", async (store) => {
|
|
1070
|
-
const elementId = await seedElement(store);
|
|
1071
|
-
const result = await store.publishVersion({
|
|
1072
|
-
elementId,
|
|
1073
|
-
payload: { role: "gibt-es-nicht", name: "X", text: "Y", locale: "de" },
|
|
1074
|
-
schemaVersion: "1.0.0",
|
|
1075
|
-
publishedBy: "vertrag"
|
|
1076
|
-
});
|
|
1077
|
-
kindIs(result, "rejected", "Publish mit unzulaessigem role-Wert");
|
|
1078
|
-
if (result.kind === "rejected") {
|
|
1079
|
-
isTrue(result.errors.length > 0, "Ablehnung muss Befunde nennen");
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
check("Veroeffentlichen", "waehlt das Payload-Schema ueber den Typ des Elements", async (store) => {
|
|
1083
|
-
const elementId = await seedElement(store, "scene", "Szene");
|
|
1084
|
-
const result = await store.publishVersion({
|
|
1085
|
-
elementId,
|
|
1086
|
-
payload: STYLE_PAYLOAD,
|
|
1087
|
-
schemaVersion: "1.0.0",
|
|
1088
|
-
publishedBy: "vertrag"
|
|
1089
|
-
});
|
|
1090
|
-
kindIs(result, "rejected", "style-Payload unter scene-Element");
|
|
1091
|
-
});
|
|
1092
|
-
check("Veroeffentlichen", "setzt die Publish-Regeln durch, nicht nur das Schema (D-58)", async (store) => {
|
|
1093
|
-
const element = ok(
|
|
1094
|
-
await store.createElement({ type: "sequence", title: "Sequenz" }),
|
|
1095
|
-
"createElement(sequence)"
|
|
1096
|
-
);
|
|
1097
|
-
const result = await store.publishVersion({
|
|
1098
|
-
elementId: element.element_id,
|
|
1099
|
-
payload: {
|
|
1100
|
-
name: "Testsequenz",
|
|
1101
|
-
// Schemagueltig: zwei Stationen mit item-Zielen. Nur P-09 haelt sie auf.
|
|
1102
|
-
stations: [
|
|
1103
|
-
{ rank: 0, target: { kind: "item", item_id: "item-a" } },
|
|
1104
|
-
{ rank: 1, target: { kind: "item", item_id: "item-b" } }
|
|
1105
|
-
]
|
|
1106
|
-
},
|
|
1107
|
-
schemaVersion: "1.0.0",
|
|
1108
|
-
publishedBy: "vertrag"
|
|
1109
|
-
});
|
|
1110
|
-
kindIs(result, "rejected", "Publish einer sequence");
|
|
1111
|
-
if (result.kind === "rejected") {
|
|
1112
|
-
const mentionsP09 = result.errors.some(
|
|
1113
|
-
(e) => e.keyword === "P-09" || e.message.includes("P-09")
|
|
1114
|
-
);
|
|
1115
|
-
isTrue(mentionsP09, `Ablehnung muss P-09 nennen: ${show(result.errors)}`);
|
|
1116
|
-
}
|
|
1117
|
-
const snapshot = await snapshotOf(store, element.element_id);
|
|
1118
|
-
hasLength(snapshot.versions, 0, "Versionen nach abgelehnter Publish-Regel");
|
|
1119
|
-
});
|
|
1120
|
-
check("Veroeffentlichen", "setzt P-03 ueber die Abstammung durch (D-60)", async (store) => {
|
|
1121
|
-
const setup = await seedSceneSetupUmgebung(store);
|
|
1122
|
-
const v1 = await seedVersion(store, setup.elementId, setup.payloadMit(["cam_a"]));
|
|
1123
|
-
const v2 = ok(
|
|
1124
|
-
await store.publishVersion({
|
|
1125
|
-
elementId: setup.elementId,
|
|
1126
|
-
payload: setup.payloadMit(["cam_b"]),
|
|
1127
|
-
// cam_a entfernt
|
|
1128
|
-
schemaVersion: "1.0.0",
|
|
1129
|
-
publishedBy: "vertrag",
|
|
1130
|
-
parents: [{ parent_version_id: v1.version_id, relation: "derived_from" }]
|
|
1131
|
-
}),
|
|
1132
|
-
"publishVersion(v2 ohne cam_a)"
|
|
1133
|
-
);
|
|
1134
|
-
ok(
|
|
1135
|
-
await store.publishVersion({
|
|
1136
|
-
elementId: setup.elementId,
|
|
1137
|
-
payload: setup.payloadMit(["cam_b"], "medium_close_up"),
|
|
1138
|
-
schemaVersion: "1.0.0",
|
|
1139
|
-
publishedBy: "vertrag",
|
|
1140
|
-
parents: [{ parent_version_id: v2.version_id, relation: "derived_from" }]
|
|
1141
|
-
}),
|
|
1142
|
-
"publishVersion(Eigenschaftswechsel bei stabiler camera_id)"
|
|
1143
|
-
);
|
|
1144
|
-
const recycled = await store.publishVersion({
|
|
1145
|
-
elementId: setup.elementId,
|
|
1146
|
-
payload: setup.payloadMit(["cam_b", "cam_a"]),
|
|
1147
|
-
schemaVersion: "1.0.0",
|
|
1148
|
-
publishedBy: "vertrag",
|
|
1149
|
-
parents: [{ parent_version_id: v2.version_id, relation: "derived_from" }]
|
|
1150
|
-
});
|
|
1151
|
-
kindIs(recycled, "rejected", "Publish mit wiederverwendeter camera_id");
|
|
1152
|
-
if (recycled.kind === "rejected") {
|
|
1153
|
-
const nenntP03 = recycled.errors.some(
|
|
1154
|
-
(e) => e.keyword === "P-03" || e.message.includes("P-03")
|
|
1155
|
-
);
|
|
1156
|
-
isTrue(nenntP03, `Ablehnung muss P-03 nennen: ${show(recycled.errors)}`);
|
|
1157
|
-
}
|
|
1158
|
-
ok(
|
|
1159
|
-
await store.publishVersion({
|
|
1160
|
-
elementId: setup.elementId,
|
|
1161
|
-
payload: setup.payloadMit(["cam_b", "cam_neu"]),
|
|
1162
|
-
schemaVersion: "1.0.0",
|
|
1163
|
-
publishedBy: "vertrag",
|
|
1164
|
-
parents: [{ parent_version_id: v2.version_id, relation: "derived_from" }]
|
|
1165
|
-
}),
|
|
1166
|
-
"publishVersion(Wiedereinfuehrung mit neuer camera_id)"
|
|
1167
|
-
);
|
|
1168
|
-
});
|
|
1169
|
-
check("Veroeffentlichen", "schreibt bei Ablehnung nichts", async (store) => {
|
|
1170
|
-
const elementId = await seedElement(store);
|
|
1171
|
-
await store.publishVersion({
|
|
1172
|
-
elementId,
|
|
1173
|
-
payload: {},
|
|
1174
|
-
schemaVersion: "1.0.0",
|
|
1175
|
-
publishedBy: "vertrag"
|
|
1176
|
-
});
|
|
1177
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1178
|
-
hasLength(snapshot.versions, 0, "Versionen nach abgelehntem Publish");
|
|
1179
|
-
});
|
|
1180
|
-
check("Veroeffentlichen", "verweigert eine Version mit unbekanntem Parent", async (store) => {
|
|
1181
|
-
const elementId = await seedElement(store);
|
|
1182
|
-
const result = await store.publishVersion({
|
|
1183
|
-
elementId,
|
|
1184
|
-
payload: STYLE_PAYLOAD,
|
|
1185
|
-
schemaVersion: "1.0.0",
|
|
1186
|
-
publishedBy: "vertrag",
|
|
1187
|
-
parents: [{ parent_version_id: ABSENT_ID, relation: "derived_from" }]
|
|
1188
|
-
});
|
|
1189
|
-
kindIs(result, "error", "Publish mit unbekanntem Parent");
|
|
1190
|
-
});
|
|
1191
|
-
check("Veroeffentlichen", "ergibt mit derived_from einen linearen DAG", async (store) => {
|
|
1192
|
-
const elementId = await seedElement(store);
|
|
1193
|
-
const v1 = await seedVersion(store, elementId, STYLE_PAYLOAD);
|
|
1194
|
-
const v2 = await seedVersion(store, elementId, STYLE_PAYLOAD_V2, [
|
|
1195
|
-
{ parent_version_id: v1.version_id, relation: "derived_from" }
|
|
1196
|
-
]);
|
|
1197
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1198
|
-
const dag = buildVersionDag(snapshot.versions);
|
|
1199
|
-
deepEqual(dag.roots(), [v1.version_id], "Roots");
|
|
1200
|
-
deepEqual(dag.heads(), [v2.version_id], "Heads");
|
|
1201
|
-
equal(dag.hasFork(), false, "hasFork");
|
|
1202
|
-
});
|
|
1203
|
-
check("Veroeffentlichen", "ergibt ohne Parent zwei Heads \u2014 ein Fork wird nicht linearisiert", async (store) => {
|
|
1204
|
-
const elementId = await seedElement(store);
|
|
1205
|
-
await seedVersion(store, elementId, STYLE_PAYLOAD);
|
|
1206
|
-
await seedVersion(store, elementId, STYLE_PAYLOAD_V2);
|
|
1207
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1208
|
-
const dag = buildVersionDag(snapshot.versions);
|
|
1209
|
-
hasLength(dag.heads(), 2, "Heads");
|
|
1210
|
-
equal(dag.hasFork(), true, "hasFork");
|
|
1211
|
-
equal(
|
|
1212
|
-
resolvePreferredHead({ dag, workingContextId: "ctx" }).resolution.kind,
|
|
1213
|
-
"fork",
|
|
1214
|
-
"Aufloesung ohne Auswahl"
|
|
1215
|
-
);
|
|
1216
|
-
});
|
|
1217
|
-
check("Veroeffentlichen", "laesst eine veroeffentlichte Version unveraendert (D-02)", async (store) => {
|
|
1218
|
-
const elementId = await seedElement(store);
|
|
1219
|
-
const version = await seedVersion(store, elementId, STYLE_PAYLOAD);
|
|
1220
|
-
await store.writeDraft({ elementId, payload: STYLE_PAYLOAD_V2, expectedRevision: 0 });
|
|
1221
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1222
|
-
hasLength(snapshot.versions, 1, "Versionen");
|
|
1223
|
-
equal(snapshot.versions[0].version_id, version.version_id, "version_id");
|
|
1224
|
-
deepEqual(snapshot.versions[0].payload, STYLE_PAYLOAD, "Payload der Version");
|
|
1225
|
-
});
|
|
1226
|
-
check("Veroeffentlichen", "liefert Versionen in Veroeffentlichungsreihenfolge (\xA74)", async (store) => {
|
|
1227
|
-
const elementId = await seedElement(store);
|
|
1228
|
-
const v1 = await seedVersion(store, elementId, STYLE_PAYLOAD);
|
|
1229
|
-
const v2 = await seedVersion(store, elementId, STYLE_PAYLOAD_V2, [
|
|
1230
|
-
{ parent_version_id: v1.version_id, relation: "derived_from" }
|
|
1231
|
-
]);
|
|
1232
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1233
|
-
deepEqual(
|
|
1234
|
-
snapshot.versions.map((v) => v.version_id),
|
|
1235
|
-
[v1.version_id, v2.version_id],
|
|
1236
|
-
"Reihenfolge der Versionen"
|
|
1237
|
-
);
|
|
1238
|
-
});
|
|
1239
|
-
check(
|
|
1240
|
-
"Preferred Head",
|
|
1241
|
-
"setzt eine Auswahl und liefert sie zurueck",
|
|
1242
|
-
async (store) => {
|
|
1243
|
-
const elementId = await seedElement(store, "style", "A", "ctx");
|
|
1244
|
-
const v1 = await seedVersion(store, elementId);
|
|
1245
|
-
ok(
|
|
1246
|
-
await store.setPreferredHead({
|
|
1247
|
-
elementId,
|
|
1248
|
-
contextId: "ctx",
|
|
1249
|
-
versionId: v1.version_id,
|
|
1250
|
-
expectedRevision: 0,
|
|
1251
|
-
selectedBy: "vertrag"
|
|
1252
|
-
}),
|
|
1253
|
-
"setPreferredHead"
|
|
1254
|
-
);
|
|
1255
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1256
|
-
const selection = snapshot.preferredHeads.find(
|
|
1257
|
-
(eintrag) => eintrag.context_id === "ctx" && eintrag.version_id === v1.version_id
|
|
1258
|
-
);
|
|
1259
|
-
isTrue(!!selection, `Auswahl fehlt im gelesenen Stand: ${show(snapshot.preferredHeads)}`);
|
|
1260
|
-
equal(selection.revision, 1, `Revision der Auswahl: ${show(snapshot.preferredHeads)}`);
|
|
1261
|
-
},
|
|
1262
|
-
"setPreferredHead"
|
|
1263
|
-
);
|
|
1264
|
-
check(
|
|
1265
|
-
"Preferred Head",
|
|
1266
|
-
"laesst die Auswahl mit der gelesenen Revision wechseln",
|
|
1267
|
-
async (store) => {
|
|
1268
|
-
const elementId = await seedElement(store, "style", "A", "ctx");
|
|
1269
|
-
const v1 = await seedVersion(store, elementId);
|
|
1270
|
-
const v2 = await seedVersion(store, elementId, STYLE_PAYLOAD_V2, [
|
|
1271
|
-
{ parent_version_id: v1.version_id, relation: "derived_from" }
|
|
1272
|
-
]);
|
|
1273
|
-
ok(
|
|
1274
|
-
await store.setPreferredHead({
|
|
1275
|
-
elementId,
|
|
1276
|
-
contextId: "ctx",
|
|
1277
|
-
versionId: v1.version_id,
|
|
1278
|
-
expectedRevision: 0,
|
|
1279
|
-
selectedBy: "vertrag"
|
|
1280
|
-
}),
|
|
1281
|
-
"erste Auswahl"
|
|
1282
|
-
);
|
|
1283
|
-
const gelesen = await snapshotOf(store, elementId);
|
|
1284
|
-
const aktuell = gelesen.preferredHeads.find((e) => e.context_id === "ctx");
|
|
1285
|
-
ok(
|
|
1286
|
-
await store.setPreferredHead({
|
|
1287
|
-
elementId,
|
|
1288
|
-
contextId: "ctx",
|
|
1289
|
-
versionId: v2.version_id,
|
|
1290
|
-
expectedRevision: aktuell?.revision ?? 0,
|
|
1291
|
-
selectedBy: "vertrag"
|
|
1292
|
-
}),
|
|
1293
|
-
"zweite Auswahl mit gelesener Revision"
|
|
1294
|
-
);
|
|
1295
|
-
const danach = await snapshotOf(store, elementId);
|
|
1296
|
-
const gewechselt = danach.preferredHeads.find((e) => e.context_id === "ctx");
|
|
1297
|
-
equal(gewechselt?.version_id, v2.version_id, "Auswahl nach dem Wechsel");
|
|
1298
|
-
equal(gewechselt?.revision, 2, "Revision nach dem Wechsel");
|
|
1299
|
-
},
|
|
1300
|
-
"setPreferredHead"
|
|
1301
|
-
);
|
|
1302
|
-
check(
|
|
1303
|
-
"Preferred Head",
|
|
1304
|
-
"verweigert eine fremde Version",
|
|
1305
|
-
async (store) => {
|
|
1306
|
-
const elementId = await seedElement(store);
|
|
1307
|
-
const result = await store.setPreferredHead({
|
|
1308
|
-
elementId,
|
|
1309
|
-
contextId: "ctx",
|
|
1310
|
-
versionId: ABSENT_ID,
|
|
1311
|
-
expectedRevision: 0,
|
|
1312
|
-
selectedBy: "vertrag"
|
|
1313
|
-
});
|
|
1314
|
-
kindIs(result, "error", "Auswahl auf fremde Version");
|
|
1315
|
-
},
|
|
1316
|
-
"setPreferredHead"
|
|
1317
|
-
);
|
|
1318
|
-
check(
|
|
1319
|
-
"Preferred Head",
|
|
1320
|
-
"lehnt eine veraltete Revision ab",
|
|
1321
|
-
async (store) => {
|
|
1322
|
-
const elementId = await seedElement(store);
|
|
1323
|
-
const v1 = await seedVersion(store, elementId);
|
|
1324
|
-
const input = {
|
|
1325
|
-
elementId,
|
|
1326
|
-
contextId: "ctx",
|
|
1327
|
-
versionId: v1.version_id,
|
|
1328
|
-
expectedRevision: 0,
|
|
1329
|
-
selectedBy: "vertrag"
|
|
1330
|
-
};
|
|
1331
|
-
await store.setPreferredHead(input);
|
|
1332
|
-
kindIs(await store.setPreferredHead(input), "conflict", "zweite Auswahl mit Revision 0");
|
|
1333
|
-
},
|
|
1334
|
-
"setPreferredHead"
|
|
1335
|
-
);
|
|
1336
|
-
check(
|
|
1337
|
-
"Elementmetadaten D-35",
|
|
1338
|
-
"aendert den Titel ohne neue Version",
|
|
1339
|
-
async (store) => {
|
|
1340
|
-
const elementId = await seedElement(store, "style", "Alt");
|
|
1341
|
-
await seedVersion(store, elementId);
|
|
1342
|
-
const revised = ok(
|
|
1343
|
-
await store.reviseMetadata({ elementId, title: "Neu", expectedRevision: 1 }),
|
|
1344
|
-
"reviseMetadata"
|
|
1345
|
-
);
|
|
1346
|
-
equal(revised.revision, 2, "Revision nach Umbenennung");
|
|
1347
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1348
|
-
equal(snapshot.metadata?.title, "Neu", "Titel");
|
|
1349
|
-
hasLength(snapshot.versions, 1, "Versionen nach Umbenennung");
|
|
1350
|
-
},
|
|
1351
|
-
"reviseMetadata"
|
|
1352
|
-
);
|
|
1353
|
-
check(
|
|
1354
|
-
"Elementmetadaten D-35",
|
|
1355
|
-
"behaelt eine nicht mitgesendete Beschreibung (\xA78)",
|
|
1356
|
-
async (store) => {
|
|
1357
|
-
const element = ok(
|
|
1358
|
-
await store.createElement({
|
|
1359
|
-
type: "style",
|
|
1360
|
-
title: "Alt",
|
|
1361
|
-
description: "wichtige Notiz"
|
|
1362
|
-
}),
|
|
1363
|
-
"createElement mit Beschreibung"
|
|
1364
|
-
);
|
|
1365
|
-
ok(
|
|
1366
|
-
await store.reviseMetadata({
|
|
1367
|
-
elementId: element.element_id,
|
|
1368
|
-
title: "Neu",
|
|
1369
|
-
expectedRevision: 1
|
|
1370
|
-
}),
|
|
1371
|
-
"reviseMetadata ohne description"
|
|
1372
|
-
);
|
|
1373
|
-
const snapshot = await snapshotOf(store, element.element_id);
|
|
1374
|
-
equal(snapshot.metadata?.title, "Neu", "Titel");
|
|
1375
|
-
equal(snapshot.metadata?.description, "wichtige Notiz", "Beschreibung");
|
|
1376
|
-
},
|
|
1377
|
-
"reviseMetadata"
|
|
1378
|
-
);
|
|
1379
|
-
check(
|
|
1380
|
-
"Elementmetadaten D-35",
|
|
1381
|
-
"loescht die Beschreibung bei ausdruecklichem null (\xA78)",
|
|
1382
|
-
async (store) => {
|
|
1383
|
-
const element = ok(
|
|
1384
|
-
await store.createElement({ type: "style", title: "Alt", description: "weg damit" }),
|
|
1385
|
-
"createElement"
|
|
1386
|
-
);
|
|
1387
|
-
ok(
|
|
1388
|
-
await store.reviseMetadata({
|
|
1389
|
-
elementId: element.element_id,
|
|
1390
|
-
title: "Alt",
|
|
1391
|
-
description: null,
|
|
1392
|
-
expectedRevision: 1
|
|
1393
|
-
}),
|
|
1394
|
-
"reviseMetadata mit description null"
|
|
1395
|
-
);
|
|
1396
|
-
const snapshot = await snapshotOf(store, element.element_id);
|
|
1397
|
-
equal(snapshot.metadata?.description, null, "Beschreibung");
|
|
1398
|
-
},
|
|
1399
|
-
"reviseMetadata"
|
|
1400
|
-
);
|
|
1401
|
-
check(
|
|
1402
|
-
"Elementmetadaten D-35",
|
|
1403
|
-
"behaelt eine nicht mitgesendete locale (\xA78)",
|
|
1404
|
-
async (store) => {
|
|
1405
|
-
const element = ok(
|
|
1406
|
-
await store.createElement({ type: "style", title: "A", locale: "en" }),
|
|
1407
|
-
"createElement mit locale en"
|
|
1408
|
-
);
|
|
1409
|
-
ok(
|
|
1410
|
-
await store.reviseMetadata({
|
|
1411
|
-
elementId: element.element_id,
|
|
1412
|
-
title: "B",
|
|
1413
|
-
expectedRevision: 1
|
|
1414
|
-
}),
|
|
1415
|
-
"reviseMetadata ohne locale"
|
|
1416
|
-
);
|
|
1417
|
-
const snapshot = await snapshotOf(store, element.element_id);
|
|
1418
|
-
equal(snapshot.metadata?.locale, "en", "locale");
|
|
1419
|
-
},
|
|
1420
|
-
"reviseMetadata"
|
|
1421
|
-
);
|
|
1422
|
-
check(
|
|
1423
|
-
"Elementmetadaten D-35",
|
|
1424
|
-
"lehnt eine veraltete Revision ab",
|
|
1425
|
-
async (store) => {
|
|
1426
|
-
const elementId = await seedElement(store, "style", "Alt");
|
|
1427
|
-
await store.reviseMetadata({ elementId, title: "Neu", expectedRevision: 1 });
|
|
1428
|
-
const stale = await store.reviseMetadata({
|
|
1429
|
-
elementId,
|
|
1430
|
-
title: "Noch neuer",
|
|
1431
|
-
expectedRevision: 1
|
|
1432
|
-
});
|
|
1433
|
-
kindIs(stale, "conflict", "zweite Umbenennung mit Revision 1");
|
|
1434
|
-
},
|
|
1435
|
-
"reviseMetadata"
|
|
1436
|
-
);
|
|
1437
|
-
check(
|
|
1438
|
-
"Stilllegen",
|
|
1439
|
-
"ist idempotent \u2014 ein zweiter Aufruf aendert nichts (\xA79)",
|
|
1440
|
-
async (store) => {
|
|
1441
|
-
const elementId = await seedElement(store);
|
|
1442
|
-
const erst = ok(await store.retireElement(elementId), "erstes retireElement");
|
|
1443
|
-
const zweit = ok(await store.retireElement(elementId), "zweites retireElement");
|
|
1444
|
-
equal(erst.retired, true, "retired nach dem ersten Aufruf");
|
|
1445
|
-
equal(zweit.retired, true, "retired nach dem zweiten Aufruf");
|
|
1446
|
-
deepEqual(zweit, erst, "Ergebnis des zweiten Aufrufs");
|
|
1447
|
-
},
|
|
1448
|
-
"retireElement"
|
|
1449
|
-
);
|
|
1450
|
-
check(
|
|
1451
|
-
"Stilllegen",
|
|
1452
|
-
"blendet aus, ohne zu loeschen",
|
|
1453
|
-
async (store) => {
|
|
1454
|
-
const elementId = await seedElement(store);
|
|
1455
|
-
ok(await store.retireElement(elementId), "retireElement");
|
|
1456
|
-
const visible = await store.listElements();
|
|
1457
|
-
hasLength(visible.kind === "ok" ? visible.value : void 0, 0, "sichtbare Elemente");
|
|
1458
|
-
const all = await store.listElements({ includeRetired: true });
|
|
1459
|
-
hasLength(all.kind === "ok" ? all.value : void 0, 1, "Elemente inkl. stillgelegter");
|
|
1460
|
-
const snapshot = await snapshotOf(store, elementId);
|
|
1461
|
-
equal(snapshot.element.retired, true, "retired");
|
|
1462
|
-
},
|
|
1463
|
-
"retireElement"
|
|
1464
|
-
);
|
|
1465
|
-
return checks;
|
|
1466
|
-
}
|
|
3
|
+
var _chunkQERFD7BYjs = require('./chunk-QERFD7BY.js');
|
|
4
|
+
require('./chunk-FTLEDU6C.js');
|
|
1467
5
|
|
|
1468
6
|
// src/lib/szenen/storeContractVitest.ts
|
|
7
|
+
var _vitest = require('vitest');
|
|
1469
8
|
function describeElementStoreContract(name, harness) {
|
|
1470
|
-
const missing = new Set(harness.optionalCommandsMissing
|
|
1471
|
-
const checks = elementStoreContractChecks();
|
|
9
|
+
const missing = new Set(_nullishCoalesce(harness.optionalCommandsMissing, () => ( [])));
|
|
10
|
+
const checks = _chunkQERFD7BYjs.elementStoreContractChecks.call(void 0, );
|
|
1472
11
|
const groups = [...new Set(checks.map((check) => check.group))];
|
|
1473
|
-
(0,
|
|
12
|
+
_vitest.describe.call(void 0, `Port-Vertrag: ${name}`, () => {
|
|
1474
13
|
for (const group of groups) {
|
|
1475
|
-
(0,
|
|
14
|
+
_vitest.describe.call(void 0, group, () => {
|
|
1476
15
|
for (const check of checks.filter((candidate) => candidate.group === group)) {
|
|
1477
16
|
const skip = check.requires !== void 0 && missing.has(check.requires);
|
|
1478
|
-
|
|
17
|
+
_vitest.it.skipIf(skip)(check.name, async () => {
|
|
1479
18
|
await check.run(await harness.createStore());
|
|
1480
19
|
});
|
|
1481
20
|
}
|
|
@@ -1483,7 +22,6 @@ function describeElementStoreContract(name, harness) {
|
|
|
1483
22
|
}
|
|
1484
23
|
});
|
|
1485
24
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
});
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
exports.describeElementStoreContract = describeElementStoreContract;
|