@porulle/plugin-channel-connector 0.47.0 → 0.48.1
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/index.js +9 -0
- package/dist/service.d.ts +12 -0
- package/dist/service.js +21 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +2 -2
- package/src/index.ts +23 -0
- package/src/service.ts +54 -0
package/dist/index.js
CHANGED
|
@@ -184,6 +184,15 @@ export function channelConnectorPlugin(options = {}) {
|
|
|
184
184
|
counted: page.value.imported,
|
|
185
185
|
cursor: page.value.cursor ?? null,
|
|
186
186
|
...(page.value.warnings ? { warnings: page.value.warnings } : {}),
|
|
187
|
+
// UNCONDITIONAL, unlike `warnings` and `failures` beside it. The step's return value is
|
|
188
|
+
// the only per-batch seam a host application has — `walkBatches` keeps just `last` — so
|
|
189
|
+
// this is where a page gets its identity. Omitting it when empty would make "this batch
|
|
190
|
+
// committed nothing" and "this plugin build does not report entities" the same
|
|
191
|
+
// `undefined` at the seam, and a caller that collapses those enqueues nothing and
|
|
192
|
+
// reports success. The service's own return declares it unconditional for the same
|
|
193
|
+
// reason; dropping it here would have undone that one line later.
|
|
194
|
+
entityIds: page.value.entityIds,
|
|
195
|
+
...(page.value.failures ? { failures: page.value.failures } : {}),
|
|
187
196
|
};
|
|
188
197
|
});
|
|
189
198
|
const jobs = ctx.services.jobs;
|
package/dist/service.d.ts
CHANGED
|
@@ -291,6 +291,18 @@ export declare class ChannelConnectorService {
|
|
|
291
291
|
conflicts?: CatalogFieldConflict[];
|
|
292
292
|
warnings?: string[];
|
|
293
293
|
failures?: CatalogConvergenceFailure[];
|
|
294
|
+
/**
|
|
295
|
+
* The entities this batch committed — see `CatalogConvergenceStats.entityIds`.
|
|
296
|
+
*
|
|
297
|
+
* Declared on the BOUNDED overload only. This is the one a per-batch step wrapper calls, so it
|
|
298
|
+
* is the one with a page to name. The unbounded overload walks a whole catalogue and would hand
|
|
299
|
+
* back thousands of ids across a durable step boundary, which is the opposite of the point.
|
|
300
|
+
*
|
|
301
|
+
* Required rather than optional here, unlike its siblings, for the reason the implementation
|
|
302
|
+
* states: a caller must be able to tell "this batch committed nothing" from "this build does
|
|
303
|
+
* not report entities", and one of those is `[]` while the other is `undefined`.
|
|
304
|
+
*/
|
|
305
|
+
entityIds: string[];
|
|
294
306
|
}>>;
|
|
295
307
|
importCatalog(orgId: string, storeId: string, actor: Actor, options?: undefined): Promise<PluginResult<{
|
|
296
308
|
imported: number;
|
package/dist/service.js
CHANGED
|
@@ -1733,6 +1733,7 @@ export class ChannelConnectorService {
|
|
|
1733
1733
|
const conflicts = [];
|
|
1734
1734
|
const warnings = [];
|
|
1735
1735
|
const failures = [];
|
|
1736
|
+
const entityIds = [];
|
|
1736
1737
|
while (remaining > 0) {
|
|
1737
1738
|
const page = await connector.importCatalog(store, pageCursor ?? undefined);
|
|
1738
1739
|
if (!page.ok)
|
|
@@ -1759,6 +1760,7 @@ export class ChannelConnectorService {
|
|
|
1759
1760
|
conflicts.push(...result.value.conflicts);
|
|
1760
1761
|
warnings.push(...result.value.warnings);
|
|
1761
1762
|
failures.push(...result.value.failures);
|
|
1763
|
+
entityIds.push(...result.value.entityIds);
|
|
1762
1764
|
offset += result.value.consumed;
|
|
1763
1765
|
if (offset >= pageItems.length) {
|
|
1764
1766
|
if (page.value.nextCursor) {
|
|
@@ -1793,6 +1795,13 @@ export class ChannelConnectorService {
|
|
|
1793
1795
|
// Always surfaced when non-empty. A silently dropped product is worse than the halt this
|
|
1794
1796
|
// replaced: the caller must be able to see which externalIds did not land.
|
|
1795
1797
|
...(failures.length > 0 ? { failures } : {}),
|
|
1798
|
+
// UNCONDITIONAL, unlike every optional field above it, and the asymmetry is deliberate.
|
|
1799
|
+
// The caller turns this into one queue message naming the page it just converged. If the key
|
|
1800
|
+
// were omitted when empty, a caller reading `outcome.entityIds` could not tell "this batch
|
|
1801
|
+
// committed nothing" from "this plugin version does not report entities" — both read as
|
|
1802
|
+
// `undefined`, and the second one silently produces an import that enqueues nothing. An
|
|
1803
|
+
// empty array says the first; a missing key says the second. They deserve different answers.
|
|
1804
|
+
entityIds,
|
|
1796
1805
|
});
|
|
1797
1806
|
}
|
|
1798
1807
|
async promoteLegacyAttributes(orgId, storeId, actor, dryRun) {
|
|
@@ -1958,6 +1967,7 @@ export class ChannelConnectorService {
|
|
|
1958
1967
|
conflicts: [],
|
|
1959
1968
|
warnings: [],
|
|
1960
1969
|
failures: [], // a dry run converges nothing, so it can fail nothing
|
|
1970
|
+
entityIds: [], // ...and commits nothing, so it names nothing
|
|
1961
1971
|
};
|
|
1962
1972
|
const assets = await this.db.select().from(mediaAssets).where(eq(mediaAssets.organizationId, orgId));
|
|
1963
1973
|
for (const item of items) {
|
|
@@ -2090,6 +2100,8 @@ export class ChannelConnectorService {
|
|
|
2090
2100
|
const conflicts = [];
|
|
2091
2101
|
const warnings = [];
|
|
2092
2102
|
const failures = [];
|
|
2103
|
+
const entityIds = [];
|
|
2104
|
+
const committed = new Set();
|
|
2093
2105
|
for (const item of items) {
|
|
2094
2106
|
consumed += 1;
|
|
2095
2107
|
try {
|
|
@@ -2288,6 +2300,14 @@ export class ChannelConnectorService {
|
|
|
2288
2300
|
}).where(eq(channelEntityMap.id, entityMapping.id));
|
|
2289
2301
|
}
|
|
2290
2302
|
await this.db.update(channelEntityMap).set({ lastSyncedAt }).where(and(eq(channelEntityMap.organizationId, orgId), eq(channelEntityMap.storeId, storeId), eq(channelEntityMap.entityId, entityId), eq(channelEntityMap.kind, "variant")));
|
|
2303
|
+
// LAST statement of the try, and that position is the whole guarantee: every failure path
|
|
2304
|
+
// above reaches `continue` before here, so an id is recorded only once the item's writes are
|
|
2305
|
+
// done. De-duplicated because a connector returning one externalId twice in a page would
|
|
2306
|
+
// otherwise have the consumer pay for the same entity twice.
|
|
2307
|
+
if (!committed.has(entityId)) {
|
|
2308
|
+
committed.add(entityId);
|
|
2309
|
+
entityIds.push(entityId);
|
|
2310
|
+
}
|
|
2291
2311
|
}
|
|
2292
2312
|
catch (error) {
|
|
2293
2313
|
// Anything the stages throw rather than returning. Same disposition: record it against the
|
|
@@ -2308,6 +2328,7 @@ export class ChannelConnectorService {
|
|
|
2308
2328
|
conflicts,
|
|
2309
2329
|
warnings,
|
|
2310
2330
|
failures,
|
|
2331
|
+
entityIds,
|
|
2311
2332
|
});
|
|
2312
2333
|
}
|
|
2313
2334
|
async reconcile(orgId, storeId, actor) {
|