Setting the file. One moment. Bulk Results · Rp Target Wix · wix/skills · Skills Docs41.10
Multilingual Restore
lib/bulk-results.js
lib/bulk-results.js
JavaScript·73 lines·4 KB
({
7 contacts: { ...selectors, envelope: r => r, validId: contactId },
8 products: { ...selectors, envelope: r => r?.productResults, validId: opaqueId },
9 inventory: { ...selectors, envelope: r => r, validId: null },
10});
11
12function correlateBulk(response, inputs, adapter) {
13 if (!adapter || !Object.values(adapters).includes(adapter)) throw new Error('An inspected endpoint adapter is required');
14 const envelope = adapter.envelope(response);
15 const defects = [];
16 const raw = Array.isArray(envelope?.results) ? envelope.results : [];
17 if (!Array.isArray(envelope?.results)) defects.push('invalid-envelope');
18 const meta = envelope?.bulkActionMetadata;
19 if (meta != null && (typeof meta !== 'object' || Array.isArray(meta))) defects.push('invalid-metadata');
20 const indexes = new Map(), ids = new Map();
21 for (const r of raw) {
22 const index = adapter.index(r);
23 indexes.set(index, (indexes.get(index) || 0) + 1);
24 if (adapter.success(r) === true && r?.itemMetadata?.id) ids.set(r.itemMetadata.id, (ids.get(r.itemMetadata.id) || 0) + 1);
25 }
26 const reportedSuccesses = raw.filter(r => adapter.success(r) === true).length;
27 const reportedFailures = raw.filter(r => adapter.success(r) === false).length;
28 for (const key of ['totalSuccesses', 'totalFailures', 'undetailedFailures']) {
29 if (meta?.[key] !== undefined && (!Number.isInteger(meta[key]) || meta[key] < 0 || meta[key] > inputs.length)) defects.push(`invalid-${key}`);
30 }
31 const undetailedFailures = Number.isInteger(meta?.undetailedFailures) && meta.undetailedFailures >= 0 ? meta.undetailedFailures : 0;
32 if (meta?.totalSuccesses !== undefined && meta.totalSuccesses !== reportedSuccesses) defects.push('inconsistent-successes');
33 if (meta?.totalFailures !== undefined && meta.totalFailures !== reportedFailures + undetailedFailures) defects.push('inconsistent-failures');
34 if (raw.length + undetailedFailures > inputs.length) defects.push('excess-results');
35 const globalInvalid = defects.length > 0;
36 const results = raw.map(r => {
37 const index = adapter.index(r), metadata = r?.itemMetadata || {};
38 const errors = [];
39 if (!Number.isInteger(index) || index < 0 || index >= inputs.length) errors.push('invalid-index');
40 else if (indexes.get(index) !== 1) errors.push('duplicate-index');
41 if (typeof adapter.success(r) !== 'boolean') errors.push('invalid-success');
42 if (adapter.validId && adapter.success(r) === true) {
43 if (!adapter.validId(metadata.id) || r?.item?._dryRunPlaceholder) errors.push('invalid-id');
44 if (r?.item?.id !== undefined && r.item.id !== metadata.id) errors.push('conflicting-id');
45 if (ids.get(metadata.id) > 1) errors.push('duplicate-target-id');
46 }
47 const correlated = !globalInvalid && errors.length === 0;
48 defects.push(...errors.map(code => `${code}:${String(index)}`));
49 return { index, input: Number.isInteger(index) ? inputs[index] : undefined, raw: r,
50 correlated, success: correlated && adapter.success(r) === true,
51 errorCode: errors[0] || (globalInvalid ? 'invalid-bulk-metadata' : metadata.error?.code) || null,
52 errorDescription: metadata.error?.description || null };
53 });
54 const accounted = new Set(results.filter(r => r.correlated).map(r => r.index));
55 const unresolvedIndexes = inputs.map((_, i) => i).filter(i => !accounted.has(i));
56 return { results, defects, unresolvedIndexes, unaccounted: unresolvedIndexes.length, undetailedFailures,
57 totalSuccesses: reportedSuccesses, totalFailures: reportedFailures + undetailedFailures };
58}
59
60function normalizeBulk(response, inputs, kind) {
61 const out = correlateBulk(response, inputs, adapters[kind]);
62 const contact = kind === 'contacts';
63 out.results = out.results.map(({ raw, input, ...r }) => ({ ...r,
64 [contact ? 'inputContact' : 'inputProduct']: input,
65 [contact ? 'contactId' : 'productId']: raw?.itemMetadata?.id || null,
66 [contact ? 'contact' : 'product']: raw?.item || null,
67 ...(contact ? { action: raw?.action || null } : { revision: raw?.item?.revision || null }),
68 }));
69 out.succeeded = out.results.filter(r => r.success);
70 out.failed = out.results.filter(r => !r.success);
71 return out;
72}
73module.exports = { adapters, correlateBulk, normalizeBulk, opaqueId, contactId };