@fakeware/core 0.0.6 → 0.0.8
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/config/index.d.mts +2 -2
- package/dist/config/index.mjs +2 -2
- package/dist/config-K2mtOgJS.mjs +308 -0
- package/dist/config-K2mtOgJS.mjs.map +1 -0
- package/dist/{index-BZFBgKu8.d.mts → index-Brciwig_.d.mts} +23 -4
- package/dist/{index-Dpb1t7ns.d.mts → index-jYm7NShY.d.mts} +20 -3
- package/dist/index.d.mts +66 -26
- package/dist/index.mjs +249 -179
- package/dist/index.mjs.map +1 -1
- package/dist/shopware/index.d.mts +2 -2
- package/dist/shopware/index.mjs +2 -158
- package/dist/shopware-CIZF8Nuo.mjs +204 -0
- package/dist/shopware-CIZF8Nuo.mjs.map +1 -0
- package/package.json +3 -1
- package/dist/config-CSPA4Itj.mjs +0 -130
- package/dist/config-CSPA4Itj.mjs.map +0 -1
- package/dist/shopware/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,154 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as RefError, _ as buildRefIndex, b as recordHash, d as resolveValue, f as define, g as setActiveRefIndex, h as refs, l as LoadModuleError, m as ref, p as many, s as ConfigError, u as loadModule, v as drain, x as isPlainObject, y as resetRegistry } from "./config-K2mtOgJS.mjs";
|
|
2
|
+
import { r as estimateSyncBytes } from "./shopware-CIZF8Nuo.mjs";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
4
5
|
import { dirname, join } from "node:path";
|
|
5
|
-
//#region src/define/errors.ts
|
|
6
|
-
var RefError = class extends Error {};
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region src/define/is-plain-object.ts
|
|
9
|
-
function isPlainObject(value) {
|
|
10
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region src/define/ids.ts
|
|
14
|
-
const FAKEWARE_NAMESPACE = "b1e0a3f4-6c2d-5a8b-9e7f-0d1c2b3a4e5f";
|
|
15
|
-
function uuidBytes(uuid) {
|
|
16
|
-
const hex = uuid.replace(/-/g, "");
|
|
17
|
-
const bytes = new Uint8Array(16);
|
|
18
|
-
for (let i = 0; i < 16; i++) bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
19
|
-
return bytes;
|
|
20
|
-
}
|
|
21
|
-
const NAMESPACE_BYTES = uuidBytes(FAKEWARE_NAMESPACE);
|
|
22
|
-
function uuidv5(name) {
|
|
23
|
-
const hash = createHash("sha1");
|
|
24
|
-
hash.update(NAMESPACE_BYTES);
|
|
25
|
-
hash.update(name, "utf8");
|
|
26
|
-
const bytes = hash.digest().subarray(0, 16);
|
|
27
|
-
bytes[6] = bytes[6] & 15 | 80;
|
|
28
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
29
|
-
return bytes.toString("hex");
|
|
30
|
-
}
|
|
31
|
-
function deterministicId(entity, key) {
|
|
32
|
-
return uuidv5(`${entity}:${key}`);
|
|
33
|
-
}
|
|
34
|
-
function canonicalize(value) {
|
|
35
|
-
if (Array.isArray(value)) return value.map(canonicalize);
|
|
36
|
-
if (isPlainObject(value)) {
|
|
37
|
-
const sorted = {};
|
|
38
|
-
for (const k of Object.keys(value).sort()) sorted[k] = canonicalize(value[k]);
|
|
39
|
-
return sorted;
|
|
40
|
-
}
|
|
41
|
-
return value;
|
|
42
|
-
}
|
|
43
|
-
function recordHash(payload) {
|
|
44
|
-
return createHash("sha256").update(JSON.stringify(canonicalize(payload))).digest("hex");
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/define/registry.ts
|
|
48
|
-
let entries = [];
|
|
49
|
-
function resetRegistry() {
|
|
50
|
-
entries = [];
|
|
51
|
-
}
|
|
52
|
-
function staticKey(value) {
|
|
53
|
-
if (typeof value !== "function") {
|
|
54
|
-
const k = value.$key;
|
|
55
|
-
if (typeof k === "string") return k;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function defineRecords(entity, recordOrRecords) {
|
|
59
|
-
const list = Array.isArray(recordOrRecords) ? recordOrRecords : [recordOrRecords];
|
|
60
|
-
for (const value of list) entries.push({
|
|
61
|
-
entity,
|
|
62
|
-
key: staticKey(value),
|
|
63
|
-
value
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
function drain() {
|
|
67
|
-
const order = [];
|
|
68
|
-
const byEntity = /* @__PURE__ */ new Map();
|
|
69
|
-
for (const e of entries) {
|
|
70
|
-
let bucket = byEntity.get(e.entity);
|
|
71
|
-
if (!bucket) {
|
|
72
|
-
bucket = [];
|
|
73
|
-
byEntity.set(e.entity, bucket);
|
|
74
|
-
order.push(e.entity);
|
|
75
|
-
}
|
|
76
|
-
bucket.push(e);
|
|
77
|
-
}
|
|
78
|
-
return order.map((entity) => ({
|
|
79
|
-
entity,
|
|
80
|
-
entries: byEntity.get(entity)
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
function buildRefIndex(drained) {
|
|
84
|
-
const refIndex = { byEntity: /* @__PURE__ */ new Map() };
|
|
85
|
-
const ids = /* @__PURE__ */ new Map();
|
|
86
|
-
for (const { entity, entries: bucket } of drained) {
|
|
87
|
-
const slot = {
|
|
88
|
-
byKey: /* @__PURE__ */ new Map(),
|
|
89
|
-
all: []
|
|
90
|
-
};
|
|
91
|
-
refIndex.byEntity.set(entity, slot);
|
|
92
|
-
bucket.forEach((entry, i) => {
|
|
93
|
-
const id = deterministicId(entity, entry.key ?? String(i));
|
|
94
|
-
ids.set(entry, id);
|
|
95
|
-
slot.all.push(id);
|
|
96
|
-
if (entry.key) slot.byKey.set(entry.key, id);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
refIndex,
|
|
101
|
-
ids
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
|
-
//#region src/define/define.ts
|
|
106
|
-
function define(entity, records) {
|
|
107
|
-
defineRecords(entity, records);
|
|
108
|
-
}
|
|
109
|
-
function many(n, fn) {
|
|
110
|
-
return Array.from({ length: n }, () => fn);
|
|
111
|
-
}
|
|
112
|
-
let active;
|
|
113
|
-
function setActiveRefIndex(refIndex) {
|
|
114
|
-
active = refIndex;
|
|
115
|
-
}
|
|
116
|
-
function requireActive() {
|
|
117
|
-
if (!active) throw new RefError("ref()/refs() may only be called while resolving definitions.");
|
|
118
|
-
return active;
|
|
119
|
-
}
|
|
120
|
-
function ref(path) {
|
|
121
|
-
const slash = path.indexOf("/");
|
|
122
|
-
if (slash === -1) throw new RefError(`ref('${path}') must be of the form 'entity/key'.`);
|
|
123
|
-
const entity = path.slice(0, slash);
|
|
124
|
-
const key = path.slice(slash + 1);
|
|
125
|
-
const id = requireActive().byEntity.get(entity)?.byKey.get(key);
|
|
126
|
-
if (!id) throw new RefError(`ref('${path}') does not match any defined record.`);
|
|
127
|
-
return id;
|
|
128
|
-
}
|
|
129
|
-
function refs(entity) {
|
|
130
|
-
const slot = requireActive().byEntity.get(entity);
|
|
131
|
-
if (!slot) throw new RefError(`refs('${entity}') does not match any defined entity.`);
|
|
132
|
-
return [...slot.all];
|
|
133
|
-
}
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region src/define/resolve.ts
|
|
136
|
-
function resolveValue(value, ctx) {
|
|
137
|
-
if (typeof value === "function") return resolveValue(value(ctx), ctx);
|
|
138
|
-
if (Array.isArray(value)) return value.map((item) => resolveValue(item, ctx));
|
|
139
|
-
if (isPlainObject(value)) {
|
|
140
|
-
const out = {};
|
|
141
|
-
for (const [key, v] of Object.entries(value)) {
|
|
142
|
-
if (key === "$key") continue;
|
|
143
|
-
out[key] = resolveValue(v, ctx);
|
|
144
|
-
}
|
|
145
|
-
return out;
|
|
146
|
-
}
|
|
147
|
-
return value;
|
|
148
|
-
}
|
|
149
|
-
//#endregion
|
|
150
6
|
//#region src/engine/errors.ts
|
|
151
7
|
var GraphError = class extends Error {};
|
|
8
|
+
var TransactionError = class extends Error {
|
|
9
|
+
rolledBack;
|
|
10
|
+
failedEntity;
|
|
11
|
+
unrevertableUpdates;
|
|
12
|
+
compensationErrors;
|
|
13
|
+
constructor(message, options) {
|
|
14
|
+
super(message, { cause: options.cause });
|
|
15
|
+
this.name = "TransactionError";
|
|
16
|
+
this.rolledBack = options.rolledBack;
|
|
17
|
+
this.failedEntity = options.failedEntity;
|
|
18
|
+
this.unrevertableUpdates = options.unrevertableUpdates ?? false;
|
|
19
|
+
this.compensationErrors = options.compensationErrors ?? [];
|
|
20
|
+
}
|
|
21
|
+
};
|
|
152
22
|
//#endregion
|
|
153
23
|
//#region src/engine/build-graph.ts
|
|
154
24
|
function ownerByIdOf(refIndex) {
|
|
@@ -309,58 +179,257 @@ function priorHashes(manifest) {
|
|
|
309
179
|
for (const e of manifest?.entities ?? []) map.set(e.entity, new Map(e.records.map((r) => [r.id, r.hash])));
|
|
310
180
|
return map;
|
|
311
181
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const manifestRecords = records.map((record) => {
|
|
182
|
+
function resolveTransaction(opts) {
|
|
183
|
+
return opts.transaction ?? opts.loaded.config.transaction;
|
|
184
|
+
}
|
|
185
|
+
function diffEntity(entity, records, prior) {
|
|
186
|
+
const toWrite = [];
|
|
187
|
+
const createdIds = [];
|
|
188
|
+
let created = 0;
|
|
189
|
+
let updated = 0;
|
|
190
|
+
let unchanged = 0;
|
|
191
|
+
return {
|
|
192
|
+
entity,
|
|
193
|
+
toWrite,
|
|
194
|
+
createdIds,
|
|
195
|
+
manifestRecords: records.map((record) => {
|
|
327
196
|
const hash = recordHash(record);
|
|
328
|
-
const previous =
|
|
329
|
-
if (previous === void 0)
|
|
330
|
-
|
|
197
|
+
const previous = prior.get(record.id);
|
|
198
|
+
if (previous === void 0) {
|
|
199
|
+
created++;
|
|
200
|
+
createdIds.push(record.id);
|
|
201
|
+
} else if (previous === hash) unchanged++;
|
|
331
202
|
else updated++;
|
|
332
203
|
if (previous !== hash) toWrite.push(record);
|
|
333
204
|
return {
|
|
334
205
|
id: record.id,
|
|
335
206
|
hash
|
|
336
207
|
};
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
manifestEntities.push({
|
|
340
|
-
entity,
|
|
341
|
-
records: manifestRecords
|
|
342
|
-
});
|
|
343
|
-
const step = {
|
|
208
|
+
}),
|
|
209
|
+
step: {
|
|
344
210
|
entity,
|
|
345
211
|
created,
|
|
346
212
|
updated,
|
|
347
213
|
unchanged,
|
|
348
214
|
deleted: 0
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function partialWrite(w, committed) {
|
|
219
|
+
if (committed <= 0) return null;
|
|
220
|
+
const createdSet = new Set(w.createdIds);
|
|
221
|
+
const prefix = w.toWrite.slice(0, committed);
|
|
222
|
+
const createdIds = prefix.map((r) => r.id).filter((id) => createdSet.has(id));
|
|
223
|
+
const updated = prefix.length - createdIds.length;
|
|
224
|
+
if (createdIds.length === 0 && updated === 0) return null;
|
|
225
|
+
return {
|
|
226
|
+
entity: w.entity,
|
|
227
|
+
toWrite: [],
|
|
228
|
+
createdIds,
|
|
229
|
+
manifestRecords: [],
|
|
230
|
+
step: {
|
|
231
|
+
entity: w.entity,
|
|
232
|
+
created: 0,
|
|
233
|
+
updated,
|
|
234
|
+
unchanged: 0,
|
|
235
|
+
deleted: 0
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async function runUp(opts) {
|
|
240
|
+
const { loaded, sink, dryRun, reporter } = opts;
|
|
241
|
+
const tx = resolveTransaction(opts);
|
|
242
|
+
const plan = buildWritePlan(await evaluateDataFiles(await discoverDataFiles(loaded.projectRoot)));
|
|
243
|
+
const prior = priorHashes(await readManifest(loaded.projectRoot, loaded.connection.url));
|
|
244
|
+
const writes = plan.order.map((entity) => diffEntity(entity, plan.records.get(entity) ?? [], prior.get(entity) ?? /* @__PURE__ */ new Map()));
|
|
245
|
+
const steps = writes.map((w) => w.step);
|
|
246
|
+
const manifestEntities = writes.map((w) => ({
|
|
247
|
+
entity: w.entity,
|
|
248
|
+
records: w.manifestRecords
|
|
249
|
+
}));
|
|
250
|
+
const committed = steps.reduce((n, s) => n + s.created + s.updated, 0);
|
|
251
|
+
const pending = writes.filter((w) => w.toWrite.length > 0);
|
|
252
|
+
if (dryRun || pending.length === 0) {
|
|
253
|
+
for (const w of writes) {
|
|
254
|
+
reporter?.onStart?.(w.entity);
|
|
255
|
+
reporter?.onStep?.(w.step);
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
steps,
|
|
259
|
+
manifestWritten: false,
|
|
260
|
+
mode: dryRun ? "dry-run" : "noop",
|
|
261
|
+
committed: 0,
|
|
262
|
+
rolledBack: 0
|
|
349
263
|
};
|
|
350
|
-
steps.push(step);
|
|
351
|
-
reporter?.onStep?.(step);
|
|
352
264
|
}
|
|
353
|
-
|
|
265
|
+
const writeManifestNow = (entities) => writeManifest(loaded.projectRoot, buildManifest({
|
|
354
266
|
fakewareVersion: opts.fakewareVersion ?? "0.0.0",
|
|
355
267
|
createdAt: opts.now ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
356
268
|
shopwareUrl: loaded.connection.url,
|
|
357
|
-
entities
|
|
269
|
+
entities
|
|
270
|
+
}));
|
|
271
|
+
const operations = pending.map((w) => ({
|
|
272
|
+
entity: w.entity,
|
|
273
|
+
action: "upsert",
|
|
274
|
+
records: w.toWrite
|
|
358
275
|
}));
|
|
276
|
+
if (tx.atomic && estimateSyncBytes(operations) <= 5242880) {
|
|
277
|
+
reporter?.onTransactionStart?.({ mode: "atomic" });
|
|
278
|
+
try {
|
|
279
|
+
await sink.applyAtomic(operations);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
const message = "Apply failed — Shopware rolled back all changes.";
|
|
282
|
+
reporter?.onStop?.({
|
|
283
|
+
failedEntity: "",
|
|
284
|
+
error,
|
|
285
|
+
message
|
|
286
|
+
});
|
|
287
|
+
throw new TransactionError(message, {
|
|
288
|
+
cause: error,
|
|
289
|
+
rolledBack: [],
|
|
290
|
+
failedEntity: ""
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
await writeManifestNow(manifestEntities);
|
|
294
|
+
reporter?.onCommit?.({ committed });
|
|
295
|
+
return {
|
|
296
|
+
steps,
|
|
297
|
+
manifestWritten: true,
|
|
298
|
+
mode: "atomic",
|
|
299
|
+
committed,
|
|
300
|
+
rolledBack: 0
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
reporter?.onTransactionStart?.({ mode: "saga" });
|
|
304
|
+
const written = [];
|
|
305
|
+
const skipped = [];
|
|
306
|
+
for (const w of pending) {
|
|
307
|
+
reporter?.onStart?.(w.entity, w.toWrite.length);
|
|
308
|
+
let committedRecords = 0;
|
|
309
|
+
try {
|
|
310
|
+
await sink.upsert(w.entity, w.toWrite, (progress) => {
|
|
311
|
+
committedRecords = progress.records;
|
|
312
|
+
reporter?.onBatch?.(progress);
|
|
313
|
+
});
|
|
314
|
+
written.push(w);
|
|
315
|
+
reporter?.onStep?.(w.step);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
if (tx.onError === "stop") {
|
|
318
|
+
const message = `Writing ${w.entity} failed — stopped.`;
|
|
319
|
+
reporter?.onStop?.({
|
|
320
|
+
failedEntity: w.entity,
|
|
321
|
+
error,
|
|
322
|
+
message
|
|
323
|
+
});
|
|
324
|
+
throw new TransactionError(message, {
|
|
325
|
+
cause: error,
|
|
326
|
+
rolledBack: [],
|
|
327
|
+
failedEntity: w.entity
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (tx.onError === "continue") {
|
|
331
|
+
skipped.push({
|
|
332
|
+
entity: w.entity,
|
|
333
|
+
error
|
|
334
|
+
});
|
|
335
|
+
reporter?.onSkip?.({
|
|
336
|
+
entity: w.entity,
|
|
337
|
+
error
|
|
338
|
+
});
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const message = `Could not apply ${w.entity}.`;
|
|
342
|
+
reporter?.onStop?.({
|
|
343
|
+
failedEntity: w.entity,
|
|
344
|
+
error,
|
|
345
|
+
message
|
|
346
|
+
});
|
|
347
|
+
const partial = partialWrite(w, committedRecords);
|
|
348
|
+
const { rolledBack, unrevertableUpdates, compensationErrors } = await compensate(sink, partial ? [...written, partial] : written, reporter);
|
|
349
|
+
throw new TransactionError(message, {
|
|
350
|
+
cause: error,
|
|
351
|
+
rolledBack,
|
|
352
|
+
failedEntity: w.entity,
|
|
353
|
+
unrevertableUpdates,
|
|
354
|
+
compensationErrors
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (const w of writes) if (!written.includes(w) && !skipped.some((s) => s.entity === w.entity)) {
|
|
359
|
+
reporter?.onStart?.(w.entity);
|
|
360
|
+
reporter?.onStep?.(w.step);
|
|
361
|
+
}
|
|
362
|
+
if (skipped.length > 0) {
|
|
363
|
+
await writeManifestNow(restrictManifest(manifestEntities, prior, new Set(written.map((w) => w.entity))));
|
|
364
|
+
const first = skipped[0];
|
|
365
|
+
throw new TransactionError(`Applied with ${skipped.length} skipped entit${skipped.length === 1 ? "y" : "ies"}.`, {
|
|
366
|
+
cause: skipped,
|
|
367
|
+
rolledBack: [],
|
|
368
|
+
failedEntity: first.entity
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
await writeManifestNow(manifestEntities);
|
|
372
|
+
reporter?.onCommit?.({ committed });
|
|
359
373
|
return {
|
|
360
374
|
steps,
|
|
361
|
-
manifestWritten:
|
|
375
|
+
manifestWritten: true,
|
|
376
|
+
mode: "saga",
|
|
377
|
+
committed,
|
|
378
|
+
rolledBack: 0
|
|
362
379
|
};
|
|
363
380
|
}
|
|
381
|
+
async function compensate(sink, written, reporter) {
|
|
382
|
+
const rolledBack = [];
|
|
383
|
+
const compensationErrors = [];
|
|
384
|
+
for (const w of [...written].reverse()) {
|
|
385
|
+
if (w.createdIds.length === 0) continue;
|
|
386
|
+
try {
|
|
387
|
+
await sink.delete(w.entity, w.createdIds);
|
|
388
|
+
rolledBack.push({
|
|
389
|
+
entity: w.entity,
|
|
390
|
+
created: 0,
|
|
391
|
+
updated: 0,
|
|
392
|
+
unchanged: 0,
|
|
393
|
+
deleted: w.createdIds.length
|
|
394
|
+
});
|
|
395
|
+
reporter?.onCompensate?.(w.entity, w.createdIds.length);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
compensationErrors.push(error);
|
|
398
|
+
reporter?.onCompensateFail?.(w.entity);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
rolledBack,
|
|
403
|
+
unrevertableUpdates: written.some((w) => w.step.updated > 0),
|
|
404
|
+
compensationErrors
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
function restrictManifest(desired, prior, writtenEntities) {
|
|
408
|
+
const out = [];
|
|
409
|
+
const seen = /* @__PURE__ */ new Set();
|
|
410
|
+
for (const e of desired) {
|
|
411
|
+
seen.add(e.entity);
|
|
412
|
+
if (writtenEntities.has(e.entity)) out.push(e);
|
|
413
|
+
else {
|
|
414
|
+
const priorRecords = prior.get(e.entity);
|
|
415
|
+
if (priorRecords && priorRecords.size > 0) out.push({
|
|
416
|
+
entity: e.entity,
|
|
417
|
+
records: [...priorRecords].map(([id, hash]) => ({
|
|
418
|
+
id,
|
|
419
|
+
hash
|
|
420
|
+
}))
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
for (const [entity, records] of prior) if (!seen.has(entity) && records.size > 0) out.push({
|
|
425
|
+
entity,
|
|
426
|
+
records: [...records].map(([id, hash]) => ({
|
|
427
|
+
id,
|
|
428
|
+
hash
|
|
429
|
+
}))
|
|
430
|
+
});
|
|
431
|
+
return out;
|
|
432
|
+
}
|
|
364
433
|
async function runDown(opts) {
|
|
365
434
|
const { loaded, sink, dryRun, reporter } = opts;
|
|
366
435
|
const manifest = await readManifest(loaded.projectRoot, loaded.connection.url);
|
|
@@ -368,11 +437,12 @@ async function runDown(opts) {
|
|
|
368
437
|
steps: [],
|
|
369
438
|
reverted: false
|
|
370
439
|
};
|
|
440
|
+
reporter?.onTransactionStart?.({ mode: "saga" });
|
|
371
441
|
const steps = [];
|
|
372
442
|
for (const entity of [...manifest.entities].reverse()) {
|
|
373
|
-
reporter?.onStart?.(entity.entity);
|
|
374
443
|
const ids = entity.records.map((r) => r.id);
|
|
375
|
-
|
|
444
|
+
reporter?.onStart?.(entity.entity, ids.length);
|
|
445
|
+
if (!dryRun && ids.length > 0) await sink.delete(entity.entity, ids, (progress) => reporter?.onBatch?.(progress));
|
|
376
446
|
const step = {
|
|
377
447
|
entity: entity.entity,
|
|
378
448
|
created: 0,
|
|
@@ -390,6 +460,6 @@ async function runDown(opts) {
|
|
|
390
460
|
};
|
|
391
461
|
}
|
|
392
462
|
//#endregion
|
|
393
|
-
export { GraphError, LoadModuleError, RefError, define, many, readManifest, ref, refs, runDown, runUp };
|
|
463
|
+
export { GraphError, LoadModuleError, RefError, TransactionError, define, many, readManifest, ref, refs, runDown, runUp };
|
|
394
464
|
|
|
395
465
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["refById","refsByEntity"],"sources":["../src/define/errors.ts","../src/define/is-plain-object.ts","../src/define/ids.ts","../src/define/registry.ts","../src/define/define.ts","../src/define/resolve.ts","../src/engine/errors.ts","../src/engine/build-graph.ts","../src/engine/discover.ts","../src/engine/evaluate.ts","../src/engine/manifest.ts","../src/engine/run.ts"],"sourcesContent":["export class RefError extends Error {}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)\n )\n}\n","import { createHash } from 'node:crypto'\nimport { isPlainObject } from './is-plain-object'\n\nconst FAKEWARE_NAMESPACE = 'b1e0a3f4-6c2d-5a8b-9e7f-0d1c2b3a4e5f'\n\nfunction uuidBytes(uuid: string): Uint8Array {\n const hex = uuid.replace(/-/g, '')\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) {\n bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\nconst NAMESPACE_BYTES = uuidBytes(FAKEWARE_NAMESPACE)\n\nfunction uuidv5(name: string): string {\n const hash = createHash('sha1')\n hash.update(NAMESPACE_BYTES)\n hash.update(name, 'utf8')\n const digest = hash.digest()\n\n const bytes = digest.subarray(0, 16)\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x50\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80\n\n return bytes.toString('hex')\n}\n\nexport function deterministicId(entity: string, key: string): string {\n return uuidv5(`${entity}:${key}`)\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalize)\n if (isPlainObject(value)) {\n const sorted: Record<string, unknown> = {}\n for (const k of Object.keys(value).sort()) {\n sorted[k] = canonicalize(value[k])\n }\n return sorted\n }\n return value\n}\n\nexport function recordHash(payload: unknown): string {\n return createHash('sha256')\n .update(JSON.stringify(canonicalize(payload)))\n .digest('hex')\n}\n","import type { Ctx } from './ctx'\nimport { deterministicId } from './ids'\n\ntype RecordObject = Record<string, unknown>\nexport type RecordValue = RecordObject | ((ctx: Ctx) => RecordObject)\n\ninterface RawEntry {\n entity: string\n key?: string\n value: RecordValue\n}\n\nexport type DrainedEntries = { entity: string; entries: RawEntry[] }[]\n\nexport interface RefIndex {\n byEntity: Map<string, { byKey: Map<string, string>; all: string[] }>\n}\n\nlet entries: RawEntry[] = []\n\nexport function resetRegistry(): void {\n entries = []\n}\n\nfunction staticKey(value: RecordValue): string | undefined {\n if (typeof value !== 'function') {\n const k = (value as RecordObject).$key\n if (typeof k === 'string') return k\n }\n return undefined\n}\n\nexport function defineRecords(entity: string, recordOrRecords: RecordValue | RecordValue[]): void {\n const list = Array.isArray(recordOrRecords) ? recordOrRecords : [recordOrRecords]\n for (const value of list) {\n entries.push({ entity, key: staticKey(value), value })\n }\n}\n\nexport function drain(): DrainedEntries {\n const order: string[] = []\n const byEntity = new Map<string, RawEntry[]>()\n for (const e of entries) {\n let bucket = byEntity.get(e.entity)\n if (!bucket) {\n bucket = []\n byEntity.set(e.entity, bucket)\n order.push(e.entity)\n }\n bucket.push(e)\n }\n return order.map((entity) => ({ entity, entries: byEntity.get(entity) as RawEntry[] }))\n}\n\nexport function buildRefIndex(drained: DrainedEntries): {\n refIndex: RefIndex\n ids: Map<RawEntry, string>\n} {\n const refIndex: RefIndex = { byEntity: new Map() }\n const ids = new Map<RawEntry, string>()\n\n for (const { entity, entries: bucket } of drained) {\n const slot = { byKey: new Map<string, string>(), all: [] as string[] }\n refIndex.byEntity.set(entity, slot)\n bucket.forEach((entry, i) => {\n const idKey = entry.key ?? String(i)\n const id = deterministicId(entity, idKey)\n ids.set(entry, id)\n slot.all.push(id)\n if (entry.key) slot.byKey.set(entry.key, id)\n })\n }\n\n return { refIndex, ids }\n}\n\nexport type { RawEntry }\n","import type { Ctx } from './ctx'\nimport { RefError } from './errors'\nimport { defineRecords, type RecordValue, type RefIndex } from './registry'\nimport type { DefineRecord, EntityName } from './schema'\n\nexport function define<const E extends EntityName>(\n entity: E,\n records: DefineRecord<E> | readonly DefineRecord<E>[],\n): void {\n defineRecords(entity, records as RecordValue | RecordValue[])\n}\n\nexport function many<R extends Record<string, unknown>>(n: number, fn: (ctx: Ctx) => R): R {\n return Array.from({ length: n }, () => fn) as unknown as R\n}\n\nlet active: RefIndex | undefined\n\nexport function setActiveRefIndex(refIndex: RefIndex | undefined): void {\n active = refIndex\n}\n\nfunction requireActive(): RefIndex {\n if (!active) {\n throw new RefError('ref()/refs() may only be called while resolving definitions.')\n }\n return active\n}\n\nexport function ref(path: string): string {\n const slash = path.indexOf('/')\n if (slash === -1) {\n throw new RefError(`ref('${path}') must be of the form 'entity/key'.`)\n }\n const entity = path.slice(0, slash)\n const key = path.slice(slash + 1)\n const id = requireActive().byEntity.get(entity)?.byKey.get(key)\n if (!id) {\n throw new RefError(`ref('${path}') does not match any defined record.`)\n }\n return id\n}\n\nexport function refs(entity: string): string[] {\n const slot = requireActive().byEntity.get(entity)\n if (!slot) {\n throw new RefError(`refs('${entity}') does not match any defined entity.`)\n }\n return [...slot.all]\n}\n","import type { Ctx } from './ctx'\nimport { isPlainObject } from './is-plain-object'\n\nexport function resolveValue(value: unknown, ctx: Ctx): unknown {\n if (typeof value === 'function') {\n return resolveValue((value as (ctx: Ctx) => unknown)(ctx), ctx)\n }\n if (Array.isArray(value)) {\n return value.map((item) => resolveValue(item, ctx))\n }\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {}\n for (const [key, v] of Object.entries(value)) {\n if (key === '$key') continue\n out[key] = resolveValue(v, ctx)\n }\n return out\n }\n return value\n}\n","export class GraphError extends Error {}\n","import {\n buildRefIndex,\n type Ctx,\n type DrainedEntries,\n isPlainObject,\n type RefIndex,\n ref as refById,\n refs as refsByEntity,\n resolveValue,\n setActiveRefIndex,\n} from '../define'\nimport type { SinkRecord } from '../domain'\nimport { GraphError } from './errors'\n\nexport interface WritePlan {\n order: string[]\n records: Map<string, SinkRecord[]>\n}\n\nfunction ownerByIdOf(refIndex: RefIndex): Map<string, string> {\n const owner = new Map<string, string>()\n for (const [entity, slot] of refIndex.byEntity) {\n for (const id of slot.all) owner.set(id, entity)\n }\n return owner\n}\n\nfunction collectIdRefs(value: unknown, ownerById: Map<string, string>, into: Set<string>): void {\n if (typeof value === 'string') {\n const owner = ownerById.get(value)\n if (owner) into.add(owner)\n return\n }\n if (Array.isArray(value)) {\n for (const item of value) collectIdRefs(item, ownerById, into)\n return\n }\n if (isPlainObject(value)) {\n for (const v of Object.values(value)) collectIdRefs(v, ownerById, into)\n }\n}\n\nfunction topoSort(entities: string[], edges: Map<string, Set<string>>): string[] {\n const indegree = new Map<string, number>(entities.map((e) => [e, 0]))\n const dependents = new Map<string, string[]>(entities.map((e) => [e, []]))\n for (const [entity, deps] of edges) {\n for (const dep of deps) {\n indegree.set(entity, (indegree.get(entity) ?? 0) + 1)\n dependents.get(dep)?.push(entity)\n }\n }\n\n const queue = entities.filter((e) => (indegree.get(e) ?? 0) === 0)\n const ordered: string[] = []\n while (queue.length > 0) {\n const entity = queue.shift() as string\n ordered.push(entity)\n for (const dependent of dependents.get(entity) ?? []) {\n const next = (indegree.get(dependent) ?? 0) - 1\n indegree.set(dependent, next)\n if (next === 0) queue.push(dependent)\n }\n }\n\n if (ordered.length !== entities.length) {\n const cyclic = entities.filter((e) => !ordered.includes(e))\n throw new GraphError(`Reference cycle between entities: ${cyclic.join(', ')}.`)\n }\n return ordered\n}\n\nexport function buildWritePlan(drained: DrainedEntries): WritePlan {\n const { refIndex, ids } = buildRefIndex(drained)\n const ownerById = ownerByIdOf(refIndex)\n const entities = drained.map((d) => d.entity)\n\n const records = new Map<string, SinkRecord[]>()\n const edges = new Map<string, Set<string>>(entities.map((e) => [e, new Set<string>()]))\n\n setActiveRefIndex(refIndex)\n try {\n for (const { entity, entries } of drained) {\n const out: SinkRecord[] = []\n entries.forEach((entry, i) => {\n const ctx: Ctx = {\n index: i,\n count: entries.length,\n ref: refById,\n refs: refsByEntity,\n }\n const payload = resolveValue(entry.value, ctx) as Record<string, unknown>\n const id = ids.get(entry) as string\n\n const referenced = new Set<string>()\n collectIdRefs(payload, ownerById, referenced)\n for (const dep of referenced) {\n if (dep !== entity) edges.get(entity)?.add(dep)\n }\n\n out.push({ ...payload, id })\n })\n records.set(entity, out)\n }\n } finally {\n setActiveRefIndex(undefined)\n }\n\n return { order: topoSort(entities, edges), records }\n}\n","import { readdir } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nconst DATA_DIR = 'data'\n\nfunction isDataFile(name: string): boolean {\n return name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')\n}\n\nexport async function discoverDataFiles(projectRoot: string): Promise<string[]> {\n const root = join(projectRoot, DATA_DIR)\n let names: string[]\n try {\n names = await readdir(root, { recursive: true })\n } catch {\n return []\n }\n return names\n .filter(isDataFile)\n .sort()\n .map((name) => join(root, name))\n}\n","import { type DrainedEntries, drain, resetRegistry } from '../define'\nimport { loadModule } from '../runtime'\n\nexport async function evaluateDataFiles(files: string[]): Promise<DrainedEntries> {\n resetRegistry()\n for (const file of files) {\n await loadModule(file)\n }\n return drain()\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { ConfigError } from '../config'\n\nconst MANIFEST_DIR = '.fakeware'\nconst CURRENT_VERSION = 1 as const\n\nfunction shopKey(shopwareUrl: string): string {\n return createHash('sha256').update(shopwareUrl).digest('hex').slice(0, 16)\n}\n\nexport interface ManifestRecord {\n id: string\n hash: string\n}\n\nexport interface ManifestEntity {\n entity: string\n records: ManifestRecord[]\n}\n\nexport interface Manifest {\n version: 1\n fakewareVersion: string\n createdAt: string\n shopwareUrl: string\n entities: ManifestEntity[]\n checksum: string\n}\n\nexport function manifestPath(projectRoot: string, shopwareUrl: string): string {\n return join(projectRoot, MANIFEST_DIR, `${shopKey(shopwareUrl)}.json`)\n}\n\nfunction checksumOf(entities: ManifestEntity[]): string {\n const canonical = entities\n .map((e) => ({\n entity: e.entity,\n records: [...e.records].sort((a, b) => a.id.localeCompare(b.id)),\n }))\n .sort((a, b) => a.entity.localeCompare(b.entity))\n return createHash('sha256').update(JSON.stringify(canonical)).digest('hex')\n}\n\nexport interface BuildManifestInput {\n fakewareVersion: string\n createdAt: string\n shopwareUrl: string\n entities: ManifestEntity[]\n}\n\nexport function buildManifest(input: BuildManifestInput): Manifest {\n return {\n version: CURRENT_VERSION,\n fakewareVersion: input.fakewareVersion,\n createdAt: input.createdAt,\n shopwareUrl: input.shopwareUrl,\n entities: input.entities,\n checksum: checksumOf(input.entities),\n }\n}\n\nexport async function readManifest(\n projectRoot: string,\n shopwareUrl: string,\n): Promise<Manifest | null> {\n const path = manifestPath(projectRoot, shopwareUrl)\n let contents: string\n try {\n contents = await readFile(path, 'utf8')\n } catch {\n return null\n }\n const parsed = JSON.parse(contents) as { version?: number }\n switch (parsed.version) {\n case CURRENT_VERSION: {\n const manifest = parsed as Manifest\n if (checksumOf(manifest.entities) !== manifest.checksum) {\n throw new ConfigError(\n `Manifest at ${path} is corrupt (checksum mismatch). Re-run \\`fakeware up\\`.`,\n )\n }\n return manifest\n }\n default:\n throw new ConfigError(\n `Unsupported manifest version ${parsed.version} (this CLI understands up to ${CURRENT_VERSION}). Upgrade fakeware.`,\n )\n }\n}\n\nexport async function writeManifest(projectRoot: string, manifest: Manifest): Promise<void> {\n const path = manifestPath(projectRoot, manifest.shopwareUrl)\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, `${JSON.stringify(manifest, null, 2)}\\n`)\n}\n\nexport async function removeManifest(projectRoot: string, shopwareUrl: string): Promise<void> {\n await rm(manifestPath(projectRoot, shopwareUrl), { force: true })\n}\n","import type { LoadedConfig } from '../config'\nimport { recordHash } from '../define'\nimport type { ShopwareSink, SinkRecord } from '../domain'\nimport { buildWritePlan } from './build-graph'\nimport { discoverDataFiles } from './discover'\nimport { evaluateDataFiles } from './evaluate'\nimport {\n buildManifest,\n type Manifest,\n type ManifestEntity,\n readManifest,\n removeManifest,\n writeManifest,\n} from './manifest'\n\nexport interface Reporter {\n onStart?(entity: string): void\n onStep?(step: ReportStep): void\n}\n\nexport interface ReportStep {\n entity: string\n created: number\n updated: number\n unchanged: number\n deleted: number\n}\n\nexport interface RunOptions {\n loaded: LoadedConfig\n sink: ShopwareSink\n dryRun?: boolean\n reporter?: Reporter\n fakewareVersion?: string\n now?: string\n}\n\nexport interface UpResult {\n steps: ReportStep[]\n manifestWritten: boolean\n}\n\nexport interface DownResult {\n steps: ReportStep[]\n reverted: boolean\n}\n\nfunction priorHashes(manifest: Manifest | null): Map<string, Map<string, string>> {\n const map = new Map<string, Map<string, string>>()\n for (const e of manifest?.entities ?? []) {\n map.set(e.entity, new Map(e.records.map((r) => [r.id, r.hash])))\n }\n return map\n}\n\nexport async function runUp(opts: RunOptions): Promise<UpResult> {\n const { loaded, sink, dryRun, reporter } = opts\n const files = await discoverDataFiles(loaded.projectRoot)\n const drained = await evaluateDataFiles(files)\n const plan = buildWritePlan(drained)\n\n const prior = priorHashes(await readManifest(loaded.projectRoot, loaded.connection.url))\n const steps: ReportStep[] = []\n const manifestEntities: ManifestEntity[] = []\n\n for (const entity of plan.order) {\n reporter?.onStart?.(entity)\n const records = plan.records.get(entity) ?? []\n const priorForEntity = prior.get(entity) ?? new Map<string, string>()\n const toWrite: SinkRecord[] = []\n let created = 0\n let updated = 0\n let unchanged = 0\n const manifestRecords = records.map((record) => {\n const hash = recordHash(record)\n const previous = priorForEntity.get(record.id)\n if (previous === undefined) created++\n else if (previous === hash) unchanged++\n else updated++\n if (previous !== hash) toWrite.push(record)\n return { id: record.id, hash }\n })\n\n if (!dryRun && toWrite.length > 0) {\n await sink.upsert(entity, toWrite)\n }\n\n manifestEntities.push({ entity, records: manifestRecords })\n const step: ReportStep = { entity, created, updated, unchanged, deleted: 0 }\n steps.push(step)\n reporter?.onStep?.(step)\n }\n\n if (!dryRun) {\n await writeManifest(\n loaded.projectRoot,\n buildManifest({\n fakewareVersion: opts.fakewareVersion ?? '0.0.0',\n createdAt: opts.now ?? new Date().toISOString(),\n shopwareUrl: loaded.connection.url,\n entities: manifestEntities,\n }),\n )\n }\n\n return { steps, manifestWritten: !dryRun }\n}\n\nexport async function runDown(opts: RunOptions): Promise<DownResult> {\n const { loaded, sink, dryRun, reporter } = opts\n const manifest = await readManifest(loaded.projectRoot, loaded.connection.url)\n if (!manifest) return { steps: [], reverted: false }\n\n const steps: ReportStep[] = []\n for (const entity of [...manifest.entities].reverse()) {\n reporter?.onStart?.(entity.entity)\n const ids = entity.records.map((r) => r.id)\n if (!dryRun && ids.length > 0) {\n await sink.delete(entity.entity, ids)\n }\n const step: ReportStep = {\n entity: entity.entity,\n created: 0,\n updated: 0,\n unchanged: 0,\n deleted: ids.length,\n }\n steps.push(step)\n reporter?.onStep?.(step)\n }\n\n if (!dryRun) await removeManifest(loaded.projectRoot, loaded.connection.url)\n return { steps, reverted: !dryRun }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["refById","refsByEntity"],"sources":["../src/engine/errors.ts","../src/engine/build-graph.ts","../src/engine/discover.ts","../src/engine/evaluate.ts","../src/engine/manifest.ts","../src/engine/run.ts"],"sourcesContent":["import type { ReportStep } from './run'\n\nexport class GraphError extends Error {}\n\nexport class TransactionError extends Error {\n readonly rolledBack: ReportStep[]\n readonly failedEntity: string\n readonly unrevertableUpdates: boolean\n readonly compensationErrors: unknown[]\n\n constructor(\n message: string,\n options: {\n cause: unknown\n rolledBack: ReportStep[]\n failedEntity: string\n unrevertableUpdates?: boolean\n compensationErrors?: unknown[]\n },\n ) {\n super(message, { cause: options.cause })\n this.name = 'TransactionError'\n this.rolledBack = options.rolledBack\n this.failedEntity = options.failedEntity\n this.unrevertableUpdates = options.unrevertableUpdates ?? false\n this.compensationErrors = options.compensationErrors ?? []\n }\n}\n","import {\n buildRefIndex,\n type Ctx,\n type DrainedEntries,\n isPlainObject,\n type RefIndex,\n ref as refById,\n refs as refsByEntity,\n resolveValue,\n setActiveRefIndex,\n} from '../define'\nimport type { SinkRecord } from '../domain'\nimport { GraphError } from './errors'\n\nexport interface WritePlan {\n order: string[]\n records: Map<string, SinkRecord[]>\n}\n\nfunction ownerByIdOf(refIndex: RefIndex): Map<string, string> {\n const owner = new Map<string, string>()\n for (const [entity, slot] of refIndex.byEntity) {\n for (const id of slot.all) owner.set(id, entity)\n }\n return owner\n}\n\nfunction collectIdRefs(value: unknown, ownerById: Map<string, string>, into: Set<string>): void {\n if (typeof value === 'string') {\n const owner = ownerById.get(value)\n if (owner) into.add(owner)\n return\n }\n if (Array.isArray(value)) {\n for (const item of value) collectIdRefs(item, ownerById, into)\n return\n }\n if (isPlainObject(value)) {\n for (const v of Object.values(value)) collectIdRefs(v, ownerById, into)\n }\n}\n\nfunction topoSort(entities: string[], edges: Map<string, Set<string>>): string[] {\n const indegree = new Map<string, number>(entities.map((e) => [e, 0]))\n const dependents = new Map<string, string[]>(entities.map((e) => [e, []]))\n for (const [entity, deps] of edges) {\n for (const dep of deps) {\n indegree.set(entity, (indegree.get(entity) ?? 0) + 1)\n dependents.get(dep)?.push(entity)\n }\n }\n\n const queue = entities.filter((e) => (indegree.get(e) ?? 0) === 0)\n const ordered: string[] = []\n while (queue.length > 0) {\n const entity = queue.shift() as string\n ordered.push(entity)\n for (const dependent of dependents.get(entity) ?? []) {\n const next = (indegree.get(dependent) ?? 0) - 1\n indegree.set(dependent, next)\n if (next === 0) queue.push(dependent)\n }\n }\n\n if (ordered.length !== entities.length) {\n const cyclic = entities.filter((e) => !ordered.includes(e))\n throw new GraphError(`Reference cycle between entities: ${cyclic.join(', ')}.`)\n }\n return ordered\n}\n\nexport function buildWritePlan(drained: DrainedEntries): WritePlan {\n const { refIndex, ids } = buildRefIndex(drained)\n const ownerById = ownerByIdOf(refIndex)\n const entities = drained.map((d) => d.entity)\n\n const records = new Map<string, SinkRecord[]>()\n const edges = new Map<string, Set<string>>(entities.map((e) => [e, new Set<string>()]))\n\n setActiveRefIndex(refIndex)\n try {\n for (const { entity, entries } of drained) {\n const out: SinkRecord[] = []\n entries.forEach((entry, i) => {\n const ctx: Ctx = {\n index: i,\n count: entries.length,\n ref: refById,\n refs: refsByEntity,\n }\n const payload = resolveValue(entry.value, ctx) as Record<string, unknown>\n const id = ids.get(entry) as string\n\n const referenced = new Set<string>()\n collectIdRefs(payload, ownerById, referenced)\n for (const dep of referenced) {\n if (dep !== entity) edges.get(entity)?.add(dep)\n }\n\n out.push({ ...payload, id })\n })\n records.set(entity, out)\n }\n } finally {\n setActiveRefIndex(undefined)\n }\n\n return { order: topoSort(entities, edges), records }\n}\n","import { readdir } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nconst DATA_DIR = 'data'\n\nfunction isDataFile(name: string): boolean {\n return name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')\n}\n\nexport async function discoverDataFiles(projectRoot: string): Promise<string[]> {\n const root = join(projectRoot, DATA_DIR)\n let names: string[]\n try {\n names = await readdir(root, { recursive: true })\n } catch {\n return []\n }\n return names\n .filter(isDataFile)\n .sort()\n .map((name) => join(root, name))\n}\n","import { type DrainedEntries, drain, resetRegistry } from '../define'\nimport { loadModule } from '../runtime'\n\nexport async function evaluateDataFiles(files: string[]): Promise<DrainedEntries> {\n resetRegistry()\n for (const file of files) {\n await loadModule(file)\n }\n return drain()\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { ConfigError } from '../config'\n\nconst MANIFEST_DIR = '.fakeware'\nconst CURRENT_VERSION = 1 as const\n\nfunction shopKey(shopwareUrl: string): string {\n return createHash('sha256').update(shopwareUrl).digest('hex').slice(0, 16)\n}\n\nexport interface ManifestRecord {\n id: string\n hash: string\n}\n\nexport interface ManifestEntity {\n entity: string\n records: ManifestRecord[]\n}\n\nexport interface Manifest {\n version: 1\n fakewareVersion: string\n createdAt: string\n shopwareUrl: string\n entities: ManifestEntity[]\n checksum: string\n}\n\nexport function manifestPath(projectRoot: string, shopwareUrl: string): string {\n return join(projectRoot, MANIFEST_DIR, `${shopKey(shopwareUrl)}.json`)\n}\n\nfunction checksumOf(entities: ManifestEntity[]): string {\n const canonical = entities\n .map((e) => ({\n entity: e.entity,\n records: [...e.records].sort((a, b) => a.id.localeCompare(b.id)),\n }))\n .sort((a, b) => a.entity.localeCompare(b.entity))\n return createHash('sha256').update(JSON.stringify(canonical)).digest('hex')\n}\n\nexport interface BuildManifestInput {\n fakewareVersion: string\n createdAt: string\n shopwareUrl: string\n entities: ManifestEntity[]\n}\n\nexport function buildManifest(input: BuildManifestInput): Manifest {\n return {\n version: CURRENT_VERSION,\n fakewareVersion: input.fakewareVersion,\n createdAt: input.createdAt,\n shopwareUrl: input.shopwareUrl,\n entities: input.entities,\n checksum: checksumOf(input.entities),\n }\n}\n\nexport async function readManifest(\n projectRoot: string,\n shopwareUrl: string,\n): Promise<Manifest | null> {\n const path = manifestPath(projectRoot, shopwareUrl)\n let contents: string\n try {\n contents = await readFile(path, 'utf8')\n } catch {\n return null\n }\n const parsed = JSON.parse(contents) as { version?: number }\n switch (parsed.version) {\n case CURRENT_VERSION: {\n const manifest = parsed as Manifest\n if (checksumOf(manifest.entities) !== manifest.checksum) {\n throw new ConfigError(\n `Manifest at ${path} is corrupt (checksum mismatch). Re-run \\`fakeware up\\`.`,\n )\n }\n return manifest\n }\n default:\n throw new ConfigError(\n `Unsupported manifest version ${parsed.version} (this CLI understands up to ${CURRENT_VERSION}). Upgrade fakeware.`,\n )\n }\n}\n\nexport async function writeManifest(projectRoot: string, manifest: Manifest): Promise<void> {\n const path = manifestPath(projectRoot, manifest.shopwareUrl)\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, `${JSON.stringify(manifest, null, 2)}\\n`)\n}\n\nexport async function removeManifest(projectRoot: string, shopwareUrl: string): Promise<void> {\n await rm(manifestPath(projectRoot, shopwareUrl), { force: true })\n}\n","import type { LoadedConfig } from '../config'\nimport { recordHash } from '../define'\nimport type { BatchProgress, ShopwareSink, SinkRecord, SyncOperation } from '../domain'\nimport { ATOMIC_REQUEST_BYTE_LIMIT, estimateSyncBytes } from '../shopware'\nimport { buildWritePlan } from './build-graph'\nimport { discoverDataFiles } from './discover'\nimport { TransactionError } from './errors'\nimport { evaluateDataFiles } from './evaluate'\nimport {\n buildManifest,\n type Manifest,\n type ManifestEntity,\n type ManifestRecord,\n readManifest,\n removeManifest,\n writeManifest,\n} from './manifest'\n\nexport interface Reporter {\n onStart?(entity: string, records?: number): void\n onBatch?(progress: BatchProgress): void\n onStep?(step: ReportStep): void\n onTransactionStart?(info: { mode: 'atomic' | 'saga' }): void\n onCommit?(info: { committed: number }): void\n onCompensate?(entity: string, count: number): void\n onCompensateFail?(entity: string): void\n onSkip?(info: { entity: string; error: unknown }): void\n onStop?(info: { failedEntity: string; error: unknown; message: string }): void\n}\n\nexport interface ReportStep {\n entity: string\n created: number\n updated: number\n unchanged: number\n deleted: number\n}\n\nexport type OnError = 'rollback' | 'continue' | 'stop'\n\nexport interface TransactionOptions {\n onError: OnError\n atomic: boolean\n}\n\nexport interface RunOptions {\n loaded: LoadedConfig\n sink: ShopwareSink\n dryRun?: boolean\n reporter?: Reporter\n fakewareVersion?: string\n now?: string\n transaction?: TransactionOptions\n}\n\nexport interface UpResult {\n steps: ReportStep[]\n manifestWritten: boolean\n mode: 'atomic' | 'saga' | 'dry-run' | 'noop'\n committed: number\n rolledBack: number\n}\n\nexport interface DownResult {\n steps: ReportStep[]\n reverted: boolean\n}\n\ninterface EntityWrite {\n entity: string\n toWrite: SinkRecord[]\n createdIds: string[]\n manifestRecords: ManifestRecord[]\n step: ReportStep\n}\n\nfunction priorHashes(manifest: Manifest | null): Map<string, Map<string, string>> {\n const map = new Map<string, Map<string, string>>()\n for (const e of manifest?.entities ?? []) {\n map.set(e.entity, new Map(e.records.map((r) => [r.id, r.hash])))\n }\n return map\n}\n\nfunction resolveTransaction(opts: RunOptions): TransactionOptions {\n return opts.transaction ?? opts.loaded.config.transaction\n}\n\nfunction diffEntity(\n entity: string,\n records: SinkRecord[],\n prior: Map<string, string>,\n): EntityWrite {\n const toWrite: SinkRecord[] = []\n const createdIds: string[] = []\n let created = 0\n let updated = 0\n let unchanged = 0\n const manifestRecords = records.map((record) => {\n const hash = recordHash(record)\n const previous = prior.get(record.id)\n if (previous === undefined) {\n created++\n createdIds.push(record.id)\n } else if (previous === hash) {\n unchanged++\n } else {\n updated++\n }\n if (previous !== hash) toWrite.push(record)\n return { id: record.id, hash }\n })\n return {\n entity,\n toWrite,\n createdIds,\n manifestRecords,\n step: { entity, created, updated, unchanged, deleted: 0 },\n }\n}\n\nfunction partialWrite(w: EntityWrite, committed: number): EntityWrite | null {\n if (committed <= 0) return null\n const createdSet = new Set(w.createdIds)\n const prefix = w.toWrite.slice(0, committed)\n const createdIds = prefix.map((r) => r.id).filter((id) => createdSet.has(id))\n const updated = prefix.length - createdIds.length\n if (createdIds.length === 0 && updated === 0) return null\n return {\n entity: w.entity,\n toWrite: [],\n createdIds,\n manifestRecords: [],\n step: { entity: w.entity, created: 0, updated, unchanged: 0, deleted: 0 },\n }\n}\n\nexport async function runUp(opts: RunOptions): Promise<UpResult> {\n const { loaded, sink, dryRun, reporter } = opts\n const tx = resolveTransaction(opts)\n const files = await discoverDataFiles(loaded.projectRoot)\n const drained = await evaluateDataFiles(files)\n const plan = buildWritePlan(drained)\n\n const prior = priorHashes(await readManifest(loaded.projectRoot, loaded.connection.url))\n\n const writes: EntityWrite[] = plan.order.map((entity) =>\n diffEntity(\n entity,\n plan.records.get(entity) ?? [],\n prior.get(entity) ?? new Map<string, string>(),\n ),\n )\n\n const steps = writes.map((w) => w.step)\n const manifestEntities: ManifestEntity[] = writes.map((w) => ({\n entity: w.entity,\n records: w.manifestRecords,\n }))\n const committed = steps.reduce((n, s) => n + s.created + s.updated, 0)\n const pending = writes.filter((w) => w.toWrite.length > 0)\n\n if (dryRun || pending.length === 0) {\n for (const w of writes) {\n reporter?.onStart?.(w.entity)\n reporter?.onStep?.(w.step)\n }\n return {\n steps,\n manifestWritten: false,\n mode: dryRun ? 'dry-run' : 'noop',\n committed: 0,\n rolledBack: 0,\n }\n }\n\n const writeManifestNow = (entities: ManifestEntity[]): Promise<void> =>\n writeManifest(\n loaded.projectRoot,\n buildManifest({\n fakewareVersion: opts.fakewareVersion ?? '0.0.0',\n createdAt: opts.now ?? new Date().toISOString(),\n shopwareUrl: loaded.connection.url,\n entities,\n }),\n )\n\n const operations: SyncOperation[] = pending.map((w) => ({\n entity: w.entity,\n action: 'upsert',\n records: w.toWrite,\n }))\n\n if (tx.atomic && estimateSyncBytes(operations) <= ATOMIC_REQUEST_BYTE_LIMIT) {\n reporter?.onTransactionStart?.({ mode: 'atomic' })\n try {\n await sink.applyAtomic(operations)\n } catch (error) {\n const message = 'Apply failed — Shopware rolled back all changes.'\n reporter?.onStop?.({ failedEntity: '', error, message })\n throw new TransactionError(message, {\n cause: error,\n rolledBack: [],\n failedEntity: '',\n })\n }\n await writeManifestNow(manifestEntities)\n reporter?.onCommit?.({ committed })\n return { steps, manifestWritten: true, mode: 'atomic', committed, rolledBack: 0 }\n }\n\n reporter?.onTransactionStart?.({ mode: 'saga' })\n const written: EntityWrite[] = []\n const skipped: { entity: string; error: unknown }[] = []\n\n for (const w of pending) {\n reporter?.onStart?.(w.entity, w.toWrite.length)\n let committedRecords = 0\n try {\n await sink.upsert(w.entity, w.toWrite, (progress) => {\n committedRecords = progress.records\n reporter?.onBatch?.(progress)\n })\n written.push(w)\n reporter?.onStep?.(w.step)\n } catch (error) {\n if (tx.onError === 'stop') {\n const message = `Writing ${w.entity} failed — stopped.`\n reporter?.onStop?.({ failedEntity: w.entity, error, message })\n throw new TransactionError(message, {\n cause: error,\n rolledBack: [],\n failedEntity: w.entity,\n })\n }\n if (tx.onError === 'continue') {\n skipped.push({ entity: w.entity, error })\n reporter?.onSkip?.({ entity: w.entity, error })\n continue\n }\n const message = `Could not apply ${w.entity}.`\n reporter?.onStop?.({ failedEntity: w.entity, error, message })\n const partial = partialWrite(w, committedRecords)\n const toCompensate = partial ? [...written, partial] : written\n const { rolledBack, unrevertableUpdates, compensationErrors } = await compensate(\n sink,\n toCompensate,\n reporter,\n )\n throw new TransactionError(message, {\n cause: error,\n rolledBack,\n failedEntity: w.entity,\n unrevertableUpdates,\n compensationErrors,\n })\n }\n }\n\n for (const w of writes) {\n if (!written.includes(w) && !skipped.some((s) => s.entity === w.entity)) {\n reporter?.onStart?.(w.entity)\n reporter?.onStep?.(w.step)\n }\n }\n\n if (skipped.length > 0) {\n const writtenEntities = new Set(written.map((w) => w.entity))\n await writeManifestNow(restrictManifest(manifestEntities, prior, writtenEntities))\n const first = skipped[0] as { entity: string; error: unknown }\n throw new TransactionError(\n `Applied with ${skipped.length} skipped entit${skipped.length === 1 ? 'y' : 'ies'}.`,\n { cause: skipped, rolledBack: [], failedEntity: first.entity },\n )\n }\n\n await writeManifestNow(manifestEntities)\n reporter?.onCommit?.({ committed })\n return { steps, manifestWritten: true, mode: 'saga', committed, rolledBack: 0 }\n}\n\nasync function compensate(\n sink: ShopwareSink,\n written: EntityWrite[],\n reporter?: Reporter,\n): Promise<{\n rolledBack: ReportStep[]\n unrevertableUpdates: boolean\n compensationErrors: unknown[]\n}> {\n const rolledBack: ReportStep[] = []\n const compensationErrors: unknown[] = []\n for (const w of [...written].reverse()) {\n if (w.createdIds.length === 0) continue\n try {\n await sink.delete(w.entity, w.createdIds)\n rolledBack.push({\n entity: w.entity,\n created: 0,\n updated: 0,\n unchanged: 0,\n deleted: w.createdIds.length,\n })\n reporter?.onCompensate?.(w.entity, w.createdIds.length)\n } catch (error) {\n compensationErrors.push(error)\n reporter?.onCompensateFail?.(w.entity)\n }\n }\n const unrevertableUpdates = written.some((w) => w.step.updated > 0)\n return { rolledBack, unrevertableUpdates, compensationErrors }\n}\n\nfunction restrictManifest(\n desired: ManifestEntity[],\n prior: Map<string, Map<string, string>>,\n writtenEntities: Set<string>,\n): ManifestEntity[] {\n const out: ManifestEntity[] = []\n const seen = new Set<string>()\n for (const e of desired) {\n seen.add(e.entity)\n if (writtenEntities.has(e.entity)) {\n out.push(e)\n } else {\n const priorRecords = prior.get(e.entity)\n if (priorRecords && priorRecords.size > 0) {\n out.push({\n entity: e.entity,\n records: [...priorRecords].map(([id, hash]) => ({ id, hash })),\n })\n }\n }\n }\n for (const [entity, records] of prior) {\n if (!seen.has(entity) && records.size > 0) {\n out.push({ entity, records: [...records].map(([id, hash]) => ({ id, hash })) })\n }\n }\n return out\n}\n\nexport async function runDown(opts: RunOptions): Promise<DownResult> {\n const { loaded, sink, dryRun, reporter } = opts\n const manifest = await readManifest(loaded.projectRoot, loaded.connection.url)\n if (!manifest) return { steps: [], reverted: false }\n\n reporter?.onTransactionStart?.({ mode: 'saga' })\n\n const steps: ReportStep[] = []\n for (const entity of [...manifest.entities].reverse()) {\n const ids = entity.records.map((r) => r.id)\n reporter?.onStart?.(entity.entity, ids.length)\n if (!dryRun && ids.length > 0) {\n await sink.delete(entity.entity, ids, (progress) => reporter?.onBatch?.(progress))\n }\n const step: ReportStep = {\n entity: entity.entity,\n created: 0,\n updated: 0,\n unchanged: 0,\n deleted: ids.length,\n }\n steps.push(step)\n reporter?.onStep?.(step)\n }\n\n if (!dryRun) await removeManifest(loaded.projectRoot, loaded.connection.url)\n return { steps, reverted: !dryRun }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { type ShopInfo, type ShopwareClient, type ShopwareConnection, ShopwareConnectionError, createShopwareClient, createSyncSink, fetchShopInfo, toConnectionError, validateConnection };
|
|
1
|
+
import { c as fetchShopInfo, d as ShopwareConnectionError, f as ShopwareClient, h as ShopwareConnection, l as toConnectionError, m as ShopInfo, n as createSyncSink, p as createShopwareClient, r as estimateSyncBytes, t as ATOMIC_REQUEST_BYTE_LIMIT, u as validateConnection } from "../index-Brciwig_.mjs";
|
|
2
|
+
export { ATOMIC_REQUEST_BYTE_LIMIT, type ShopInfo, type ShopwareClient, type ShopwareConnection, ShopwareConnectionError, createShopwareClient, createSyncSink, estimateSyncBytes, fetchShopInfo, toConnectionError, validateConnection };
|