@legenki/print2medusa 0.8.1 → 0.9.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.
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const design_1 = require("../../../../utils/design");
6
+ const prompt_1 = require("../../../../utils/prompt");
7
+ /**
8
+ * Mockup prompts per product.
9
+ *
10
+ * A pure read of the database plus string assembly — no Printful call, and no
11
+ * image generation. The plugin writes prompts; generation happens wherever you
12
+ * paste them, which is what keeps API keys, rate-limit queues and file storage
13
+ * out of this repo.
14
+ */
15
+ async function GET(req, res) {
16
+ const productModule = req.scope.resolve(utils_1.Modules.PRODUCT);
17
+ const query = req.query;
18
+ // An unrecognized style falls back to the first preset rather than
19
+ // erroring: a mistyped query parameter should still produce prompts.
20
+ const requested = typeof query.style === "string" ? query.style : undefined;
21
+ const style = prompt_1.PROMPT_STYLES.some((s) => s.id === requested)
22
+ ? requested
23
+ : undefined;
24
+ const artwork = typeof query.artwork === "string" && query.artwork.trim()
25
+ ? query.artwork.trim()
26
+ : undefined;
27
+ const products = await productModule.listProducts({}, { relations: ["variants"], take: 100 });
28
+ const items = products
29
+ .map((product) => {
30
+ const summary = (0, design_1.summarizeProductDesign)(product.variants ?? []);
31
+ if (!summary) {
32
+ // Never enriched by a sync. Omitted rather than listed with no
33
+ // prompts, which would read as "this product cannot be prompted for".
34
+ return null;
35
+ }
36
+ const prompts = (0, prompt_1.buildProductPrompts)({ design: summary, style, artwork });
37
+ if (prompts.length === 0) {
38
+ return null;
39
+ }
40
+ return {
41
+ product_id: product.id,
42
+ title: product.title,
43
+ product_class: summary.product_class,
44
+ prompts,
45
+ };
46
+ })
47
+ .filter((p) => p !== null);
48
+ res.status(200).json({
49
+ products: items,
50
+ styles: prompt_1.PROMPT_STYLES.map((s) => ({ id: s.id, label: s.label })),
51
+ style: style ?? prompt_1.PROMPT_STYLES[0].id,
52
+ artwork,
53
+ });
54
+ }
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3ByaW50ZnVsL3Byb21wdHMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpQkEsa0JBa0RDO0FBbEVELHFEQUFtRDtBQUNuRCxxREFBaUU7QUFDakUscURBSWlDO0FBRWpDOzs7Ozs7O0dBT0c7QUFDSSxLQUFLLFVBQVUsR0FBRyxDQUFDLEdBQWtCLEVBQUUsR0FBbUI7SUFDL0QsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3hELE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFnQyxDQUFBO0lBRWxELG1FQUFtRTtJQUNuRSxxRUFBcUU7SUFDckUsTUFBTSxTQUFTLEdBQUcsT0FBTyxLQUFLLENBQUMsS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0lBQzNFLE1BQU0sS0FBSyxHQUFHLHNCQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsQ0FBQztRQUN6RCxDQUFDLENBQUUsU0FBeUI7UUFDNUIsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtJQUViLE1BQU0sT0FBTyxHQUNYLE9BQU8sS0FBSyxDQUFDLE9BQU8sS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUU7UUFDdkQsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO1FBQ3RCLENBQUMsQ0FBQyxTQUFTLENBQUE7SUFFZixNQUFNLFFBQVEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxZQUFZLENBQy9DLEVBQUUsRUFDRixFQUFFLFNBQVMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDdkMsQ0FBQTtJQUVELE1BQU0sS0FBSyxHQUFHLFFBQVE7U0FDbkIsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDZixNQUFNLE9BQU8sR0FBRyxJQUFBLCtCQUFzQixFQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUE7UUFDOUQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsK0RBQStEO1lBQy9ELHNFQUFzRTtZQUN0RSxPQUFPLElBQUksQ0FBQTtRQUNiLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFBLDRCQUFtQixFQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUN4RSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDekIsT0FBTyxJQUFJLENBQUE7UUFDYixDQUFDO1FBRUQsT0FBTztZQUNMLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRTtZQUN0QixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7WUFDcEIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1lBQ3BDLE9BQU87U0FDUixDQUFBO0lBQ0gsQ0FBQyxDQUFDO1NBQ0QsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUE4QixFQUFFLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFBO0lBRXhELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ25CLFFBQVEsRUFBRSxLQUFLO1FBQ2YsTUFBTSxFQUFFLHNCQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2hFLEtBQUssRUFBRSxLQUFLLElBQUksc0JBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ25DLE9BQU87S0FDUixDQUFDLENBQUE7QUFDSixDQUFDIn0=
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const printful_1 = require("../../../../modules/printful");
6
+ /** Days of history when the caller does not ask for a range. */
7
+ const DEFAULT_DAYS = 30;
8
+ /**
9
+ * Reports the admin page renders. Asking for only these keeps the response
10
+ * small; Printful also offers per-product and per-variant breakdowns, which
11
+ * nothing displays yet and which would be paid for on every page load.
12
+ */
13
+ const REPORT_TYPES = "profit,total_paid_orders,average_fulfillment_time";
14
+ const isoDate = (d) => d.toISOString().slice(0, 10);
15
+ /**
16
+ * Sales statistics for the admin page.
17
+ *
18
+ * Unlike `/health`, this one genuinely has to call Printful — the figures do
19
+ * not exist locally. So the failure is handled rather than propagated: an
20
+ * outage answers `200` with an empty list and a `reason`, not a `500`. The
21
+ * page fetches three panels independently and a thrown error here would take
22
+ * out the one screen an owner opens *because* something is wrong.
23
+ */
24
+ async function GET(req, res) {
25
+ const printful = req.scope.resolve(printful_1.PRINTFUL_MODULE);
26
+ const logger = req.scope.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
27
+ const query = req.query;
28
+ const now = new Date();
29
+ const from = new Date(now.getTime() - DEFAULT_DAYS * 24 * 60 * 60 * 1000);
30
+ const dateFrom = typeof query.date_from === "string" && query.date_from
31
+ ? query.date_from
32
+ : isoDate(from);
33
+ const dateTo = typeof query.date_to === "string" && query.date_to
34
+ ? query.date_to
35
+ : isoDate(now);
36
+ try {
37
+ const client = await printful.getClient();
38
+ const statistics = await client.getStatistics({
39
+ dateFrom,
40
+ dateTo,
41
+ reportTypes: REPORT_TYPES,
42
+ });
43
+ res.status(200).json({ statistics, date_from: dateFrom, date_to: dateTo });
44
+ }
45
+ catch (err) {
46
+ const message = err instanceof Error ? err.message : String(err);
47
+ logger.error(`Printful statistics unavailable: ${message}`);
48
+ // 200 with an empty list, not an error status: the page treats this as
49
+ // "nothing to show" and keeps rendering sync history and webhook health,
50
+ // which are exactly what an operator needs during a Printful outage.
51
+ res.status(200).json({
52
+ statistics: [],
53
+ date_from: dateFrom,
54
+ date_to: dateTo,
55
+ reason: "printful_unreachable",
56
+ });
57
+ }
58
+ }
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3ByaW50ZnVsL3N0YXRpc3RpY3Mvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEwQkEsa0JBd0NDO0FBakVELHFEQUFxRTtBQUNyRSwyREFBOEQ7QUFHOUQsZ0VBQWdFO0FBQ2hFLE1BQU0sWUFBWSxHQUFHLEVBQUUsQ0FBQTtBQUV2Qjs7OztHQUlHO0FBQ0gsTUFBTSxZQUFZLEdBQUcsbURBQW1ELENBQUE7QUFFeEUsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFPLEVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0FBRWpFOzs7Ozs7OztHQVFHO0FBQ0ksS0FBSyxVQUFVLEdBQUcsQ0FBQyxHQUFrQixFQUFFLEdBQW1CO0lBQy9ELE1BQU0sUUFBUSxHQUEwQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQywwQkFBZSxDQUFDLENBQUE7SUFDMUUsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsTUFBTSxDQUFDLENBQUE7SUFFbEUsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQWdDLENBQUE7SUFDbEQsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtJQUN0QixNQUFNLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEdBQUcsWUFBWSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFBO0lBRXpFLE1BQU0sUUFBUSxHQUNaLE9BQU8sS0FBSyxDQUFDLFNBQVMsS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLFNBQVM7UUFDcEQsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTO1FBQ2pCLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDbkIsTUFBTSxNQUFNLEdBQ1YsT0FBTyxLQUFLLENBQUMsT0FBTyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTztRQUNoRCxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU87UUFDZixDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBRWxCLElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFBO1FBQ3pDLE1BQU0sVUFBVSxHQUFHLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQztZQUM1QyxRQUFRO1lBQ1IsTUFBTTtZQUNOLFdBQVcsRUFBRSxZQUFZO1NBQzFCLENBQUMsQ0FBQTtRQUVGLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7SUFDNUUsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLE9BQU8sR0FBRyxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDaEUsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUUzRCx1RUFBdUU7UUFDdkUseUVBQXlFO1FBQ3pFLHFFQUFxRTtRQUNyRSxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNuQixVQUFVLEVBQUUsRUFBRTtZQUNkLFNBQVMsRUFBRSxRQUFRO1lBQ25CLE9BQU8sRUFBRSxNQUFNO1lBQ2YsTUFBTSxFQUFFLHNCQUFzQjtTQUMvQixDQUFDLENBQUE7SUFDSixDQUFDO0FBQ0gsQ0FBQyJ9
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.POST = POST;
4
+ const printful_1 = require("../../../../../modules/printful");
5
+ const clear_sync_1 = require("../../../../../utils/clear-sync");
6
+ /**
7
+ * Clear a sync that is stuck in `running`.
8
+ *
9
+ * Nested under `sync/` rather than living at its own top-level path because it
10
+ * acts on exactly the resource `POST /admin/printful/sync` claims — the two
11
+ * belong together, and the 409 body from that route is what sends an operator
12
+ * here. POST, not DELETE: this does not remove the row, it transitions it to a
13
+ * terminal state and writes an audit marker.
14
+ *
15
+ * This closes the limit recorded in 0.4.0: after a crash the log stays
16
+ * `running` and nothing reclaims it until the next sync attempt, so with the
17
+ * default `syncStaleMinutes: 60` the catalog is blocked for up to an hour with
18
+ * no way to intervene.
19
+ *
20
+ * It deliberately does not just call `reapStaleSyncLogs(0)`. That would clear
21
+ * any running sync unconditionally, including a healthy one mid-catalog, and
22
+ * would stamp the row with the same `stale_running` marker the timeout reaper
23
+ * uses — making a human intervention indistinguishable from an automatic
24
+ * recovery in the audit trail. `planSyncClear` owns both decisions.
25
+ */
26
+ async function POST(req, res) {
27
+ const printful = req.scope.resolve(printful_1.PRINTFUL_MODULE);
28
+ const options = await printful.getOptions();
29
+ const body = (req.body ?? {});
30
+ const confirmation = typeof body.confirm === "string" ? body.confirm : null;
31
+ const running = await printful.getRunningSyncLog();
32
+ const decision = (0, clear_sync_1.planSyncClear)({
33
+ log: running,
34
+ confirmation,
35
+ staleMinutes: options.syncStaleMinutes ?? 60,
36
+ });
37
+ if (!decision.allowed) {
38
+ if (decision.reason === "nothing_running") {
39
+ // Not an error. The page asked to clear a stuck sync and there is no
40
+ // sync to clear, which is the state the operator wanted.
41
+ res.status(200).json({
42
+ cleared: false,
43
+ reason: "nothing_running",
44
+ message: "No Printful sync is running",
45
+ });
46
+ return;
47
+ }
48
+ if (decision.reason === "unconfirmed") {
49
+ res.status(400).json({
50
+ cleared: false,
51
+ reason: "unconfirmed",
52
+ message: `Clearing a sync is destructive. Send { "confirm": "${clear_sync_1.CLEAR_SYNC_CONFIRMATION}" } to proceed.`,
53
+ sync_id: decision.sync_id,
54
+ });
55
+ return;
56
+ }
57
+ // `alive`: the heartbeat says this sync is still running. 409 matches the
58
+ // 409 that POST /admin/printful/sync returns for the same condition — a
59
+ // sync is holding the claim and the caller cannot have it.
60
+ res.status(409).json({
61
+ cleared: false,
62
+ reason: "alive",
63
+ message: "This sync is still sending heartbeats. Clearing it would mark a live sync as failed while it keeps writing.",
64
+ sync_id: decision.sync_id,
65
+ silent_minutes: decision.silent_minutes,
66
+ });
67
+ return;
68
+ }
69
+ // Conditional on the heartbeat we just read. If the sync emitted one more
70
+ // between that read and this write, it was never dead and the update matches
71
+ // nothing — see clearStuckSyncLog.
72
+ const cleared = await printful.clearStuckSyncLog({
73
+ id: decision.sync_id,
74
+ observedHeartbeatAt: running?.heartbeat_at ?? null,
75
+ errorMessage: decision.error_message,
76
+ });
77
+ if (!cleared) {
78
+ res.status(409).json({
79
+ cleared: false,
80
+ reason: "alive",
81
+ message: "This sync sent a heartbeat while the request was being handled, so it is still alive and was left running.",
82
+ sync_id: decision.sync_id,
83
+ });
84
+ return;
85
+ }
86
+ res.status(200).json({
87
+ cleared: true,
88
+ sync_id: decision.sync_id,
89
+ error_message: decision.error_message,
90
+ silent_minutes: decision.silent_minutes,
91
+ });
92
+ }
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3ByaW50ZnVsL3N5bmMvY2xlYXIvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE0QkEsb0JBNkVDO0FBeEdELDhEQUFpRTtBQUVqRSxnRUFHd0M7QUFFeEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFDSSxLQUFLLFVBQVUsSUFBSSxDQUFDLEdBQWtCLEVBQUUsR0FBbUI7SUFDaEUsTUFBTSxRQUFRLEdBQTBCLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLDBCQUFlLENBQUMsQ0FBQTtJQUMxRSxNQUFNLE9BQU8sR0FBRyxNQUFNLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQTtJQUUzQyxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUEwQixDQUFBO0lBQ3RELE1BQU0sWUFBWSxHQUFHLE9BQU8sSUFBSSxDQUFDLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQTtJQUUzRSxNQUFNLE9BQU8sR0FBRyxNQUFNLFFBQVEsQ0FBQyxpQkFBaUIsRUFBRSxDQUFBO0lBRWxELE1BQU0sUUFBUSxHQUFHLElBQUEsMEJBQWEsRUFBQztRQUM3QixHQUFHLEVBQUUsT0FBTztRQUNaLFlBQVk7UUFDWixZQUFZLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixJQUFJLEVBQUU7S0FDN0MsQ0FBQyxDQUFBO0lBRUYsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN0QixJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssaUJBQWlCLEVBQUUsQ0FBQztZQUMxQyxxRUFBcUU7WUFDckUseURBQXlEO1lBQ3pELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO2dCQUNuQixPQUFPLEVBQUUsS0FBSztnQkFDZCxNQUFNLEVBQUUsaUJBQWlCO2dCQUN6QixPQUFPLEVBQUUsNkJBQTZCO2FBQ3ZDLENBQUMsQ0FBQTtZQUNGLE9BQU07UUFDUixDQUFDO1FBRUQsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLGFBQWEsRUFBRSxDQUFDO1lBQ3RDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO2dCQUNuQixPQUFPLEVBQUUsS0FBSztnQkFDZCxNQUFNLEVBQUUsYUFBYTtnQkFDckIsT0FBTyxFQUFFLHNEQUFzRCxvQ0FBdUIsaUJBQWlCO2dCQUN2RyxPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87YUFDMUIsQ0FBQyxDQUFBO1lBQ0YsT0FBTTtRQUNSLENBQUM7UUFFRCwwRUFBMEU7UUFDMUUsd0VBQXdFO1FBQ3hFLDJEQUEyRDtRQUMzRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNuQixPQUFPLEVBQUUsS0FBSztZQUNkLE1BQU0sRUFBRSxPQUFPO1lBQ2YsT0FBTyxFQUNMLDZHQUE2RztZQUMvRyxPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87WUFDekIsY0FBYyxFQUFFLFFBQVEsQ0FBQyxjQUFjO1NBQ3hDLENBQUMsQ0FBQTtRQUNGLE9BQU07SUFDUixDQUFDO0lBRUQsMEVBQTBFO0lBQzFFLDZFQUE2RTtJQUM3RSxtQ0FBbUM7SUFDbkMsTUFBTSxPQUFPLEdBQUcsTUFBTSxRQUFRLENBQUMsaUJBQWlCLENBQUM7UUFDL0MsRUFBRSxFQUFFLFFBQVEsQ0FBQyxPQUFPO1FBQ3BCLG1CQUFtQixFQUFFLE9BQU8sRUFBRSxZQUFZLElBQUksSUFBSTtRQUNsRCxZQUFZLEVBQUUsUUFBUSxDQUFDLGFBQWE7S0FDckMsQ0FBQyxDQUFBO0lBRUYsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2IsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbkIsT0FBTyxFQUFFLEtBQUs7WUFDZCxNQUFNLEVBQUUsT0FBTztZQUNmLE9BQU8sRUFDTCw0R0FBNEc7WUFDOUcsT0FBTyxFQUFFLFFBQVEsQ0FBQyxPQUFPO1NBQzFCLENBQUMsQ0FBQTtRQUNGLE9BQU07SUFDUixDQUFDO0lBRUQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDbkIsT0FBTyxFQUFFLElBQUk7UUFDYixPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87UUFDekIsYUFBYSxFQUFFLFFBQVEsQ0FBQyxhQUFhO1FBQ3JDLGNBQWMsRUFBRSxRQUFRLENBQUMsY0FBYztLQUN4QyxDQUFDLENBQUE7QUFDSixDQUFDIn0=
@@ -299,6 +299,44 @@ class PrintfulModuleService extends (0, utils_1.MedusaService)({
299
299
  const [log] = await this.listPrintfulSyncLogs({ status: "running" });
300
300
  return log ?? null;
301
301
  }
302
+ /**
303
+ * Clear a specific stuck sync on an operator's instruction.
304
+ *
305
+ * Separate from `reapStaleSyncLogs` on purpose. That one is the timeout
306
+ * reaper: it selects its own victims by age and stamps them `stale_running`.
307
+ * This one clears exactly the row the operator was looking at and records a
308
+ * marker naming them as the cause, so the two are distinguishable in the log
309
+ * long after the fact.
310
+ *
311
+ * The `heartbeat_at` predicate makes the write conditional on the row still
312
+ * being as stale as the caller observed. Between the route's read and this
313
+ * write, a sync everyone believed dead can emit one more heartbeat; without
314
+ * this predicate that row would be marked `failed` underneath a live
315
+ * process. With it, the late heartbeat moves `heartbeat_at` past the
316
+ * observed value, the update matches nothing, and the caller is told the
317
+ * sync is alive after all.
318
+ *
319
+ * Returns true when a row was actually cleared.
320
+ */
321
+ async clearStuckSyncLog(input) {
322
+ const stillStale = await this.listPrintfulSyncLogs({
323
+ id: input.id,
324
+ status: "running",
325
+ heartbeat_at: input.observedHeartbeatAt
326
+ ? { $lte: input.observedHeartbeatAt }
327
+ : null,
328
+ });
329
+ if (stillStale.length === 0) {
330
+ return false;
331
+ }
332
+ await this.updatePrintfulSyncLogs({
333
+ id: input.id,
334
+ status: "failed",
335
+ error_message: input.errorMessage,
336
+ finished_at: new Date(),
337
+ });
338
+ return true;
339
+ }
302
340
  /** Refresh the claim so it is not reaped, and report progress. */
303
341
  async heartbeatSyncLog(id, progress = {}) {
304
342
  return this.updatePrintfulSyncLogs({
@@ -309,4 +347,4 @@ class PrintfulModuleService extends (0, utils_1.MedusaService)({
309
347
  }
310
348
  }
311
349
  exports.default = PrintfulModuleService;
312
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3ByaW50ZnVsL3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBZ0RBLDRDQUlDO0FBYUQsZ0NBR0M7QUFpQkQsOENBMkJDO0FBaEhELHFEQUF5RDtBQUN6RCxtQ0FBbUM7QUFDbkMsaUVBQTREO0FBRTVELHVGQUE0RDtBQUM1RCwyRkFBZ0U7QUFDaEUsbUZBQXdEO0FBQ3hELDJGQUFnRTtBQUNoRSw2RkFBa0U7QUEyQmxFOzs7Ozs7R0FNRztBQUNVLFFBQUEseUJBQXlCLEdBQUcsU0FBUyxDQUFBO0FBRWxELGdFQUFnRTtBQUNuRCxRQUFBLG9CQUFvQixHQUFHLEVBQUUsQ0FBQTtBQUV0QyxrRUFBa0U7QUFDbEUsU0FBZ0IsZ0JBQWdCLENBQUMsUUFBZ0I7SUFDL0MsTUFBTSxZQUFZLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUE7SUFDbEMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFBO0lBQ3BDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUE7QUFDbEUsQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxTQUFnQixVQUFVLENBQUMsZUFBdUI7SUFDaEQsTUFBTSxNQUFNLEdBQUcsSUFBQSxtQkFBVSxFQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUM1RSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDOUIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsR0FBWTtJQUM1QyxJQUFJLENBQUMsR0FBRyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3BDLE9BQU8sS0FBSyxDQUFBO0lBQ2QsQ0FBQztJQUNELE1BQU0sQ0FBQyxHQUFHLEdBS1QsQ0FBQTtJQUNELElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUN2QixPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFDRCxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sS0FBSyxRQUFRLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNqRSxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFDRCxJQUNFLENBQUMsQ0FBQyxJQUFJLEtBQUssY0FBYztRQUN6QixPQUFPLENBQUMsQ0FBQyxPQUFPLEtBQUssUUFBUTtRQUM3QixxQkFBcUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUM1QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBQ0QsSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxFQUFFLENBQUM7UUFDL0IsT0FBTyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDbkMsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFBO0FBQ2QsQ0FBQztBQUVELE1BQU0scUJBQXNCLFNBQVEsSUFBQSxxQkFBYSxFQUFDO0lBQ2hELG1CQUFtQixFQUFuQiwrQkFBbUI7SUFDbkIsbUJBQW1CLEVBQW5CLCtCQUFtQjtJQUNuQixlQUFlLEVBQWYsMkJBQWU7SUFDZixpQkFBaUIsRUFBakIsNkJBQWlCO0lBQ2pCLG9CQUFvQixFQUFwQixnQ0FBb0I7Q0FDckIsQ0FBQztJQU1BLFlBQ0UsU0FBK0IsRUFDL0IsT0FBK0I7UUFFL0Isc0NBQXNDO1FBQ3RDLEtBQUssQ0FBQyxHQUFHLFNBQVMsQ0FBQyxDQUFBO1FBVFgsWUFBTyxHQUEwQixJQUFJLENBQUE7UUFVN0MsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLElBQUssRUFBNEIsQ0FBQTtJQUMxRCxDQUFDO0lBRUQsS0FBSyxDQUFDLFVBQVU7UUFDZCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUE7SUFDdEIsQ0FBQztJQUVELEtBQUssQ0FBQyxTQUFTO1FBQ2IsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxJQUFJLEtBQUssQ0FDYiw4RUFBOEUsQ0FDL0UsQ0FBQTtZQUNILENBQUM7WUFDRCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksZ0NBQWMsQ0FBQztnQkFDaEMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUTtnQkFDaEMsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTzthQUMvQixDQUFDLENBQUE7UUFDSixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMsVUFBVTtRQUNkLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxPQUFPLElBQUksU0FBUyxDQUFBO0lBQzVDLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUFDLGFBQXFCO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFBO1FBQ3ZDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztZQUNqRCxpQkFBaUIsRUFBRSxPQUFPO1lBQzFCLHdCQUF3QixFQUFFLE1BQU0sQ0FBQyxhQUFhLENBQUM7U0FDaEQsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFBO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUFDLGFBQXFCO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFBO1FBQ3ZDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztZQUNqRCxpQkFBaUIsRUFBRSxPQUFPO1lBQzFCLHdCQUF3QixFQUFFLE1BQU0sQ0FBQyxhQUFhLENBQUM7U0FDaEQsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFBO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMseUJBQXlCLENBQUMsZUFBdUI7UUFDckQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLHdCQUF3QixDQUFDO1lBQ2pELGlCQUFpQixFQUFFLGVBQWU7U0FDbkMsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFBO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMsYUFBYSxDQUFDLGFBQXFCO1FBQ3ZDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztZQUMvQyxlQUFlLEVBQUUsYUFBYTtTQUMvQixDQUFDLENBQUE7UUFDRixPQUFPLElBQUksSUFBSSxJQUFJLENBQUE7SUFDckIsQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxLQUFLLENBQUMseUJBQXlCLENBQUMsZUFBdUI7UUFDckQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDO1lBQy9DLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUM7U0FDM0MsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFBO0lBQ3JCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsa0JBQWtCLENBQUMsS0FPeEI7UUFDQyxJQUFJLENBQUM7WUFDSCxPQUFPLE1BQU0sSUFBSSxDQUFDLDJCQUEyQixDQUFDO2dCQUM1QyxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7Z0JBQ3hCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDaEIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtnQkFDMUMsb0JBQW9CLEVBQUUsS0FBSyxDQUFDLG9CQUFvQixJQUFJLElBQUk7Z0JBQ3hELE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztnQkFDdEIsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksVUFBVTtnQkFDbEMsUUFBUSxFQUFFLENBQUM7Z0JBQ1gsYUFBYSxFQUFFLElBQUksSUFBSSxFQUFFO2FBQzFCLENBQUMsQ0FBQTtRQUNKLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsSUFBSSxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMzQixPQUFPLElBQUksQ0FBQTtZQUNiLENBQUM7WUFDRCxNQUFNLEdBQUcsQ0FBQTtRQUNYLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQWU7UUFDcEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLHlCQUF5QixDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUE7UUFDM0UsT0FBTyxLQUFLLElBQUksSUFBSSxDQUFBO0lBQ3RCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLG9CQUFvQixDQUFDLEtBQUssR0FBRyxFQUFFO1FBQ25DLE9BQU8sSUFBSSxDQUFDLHlCQUF5QixDQUNuQztZQUNFLE1BQU0sRUFBRSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUM7WUFDaEMsYUFBYSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLEVBQUU7WUFDbkMsUUFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFLDRCQUFvQixFQUFFO1NBQ3hDLEVBQ0QsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUNqRCxDQUFBO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7O09BZ0JHO0lBQ0gsS0FBSyxDQUFDLGFBQWEsQ0FDakIsZUFBdUIsRUFDdkIsRUFBb0I7UUFFcEIsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLGVBQWUsQ0FBQyxDQUFBO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxXQUFXLENBQ3JDLEtBQUssRUFBRSxTQUF5QixFQUFFLEVBQUU7WUFDbEMsTUFBTSxTQUFTLENBQUMsT0FBTyxDQUFDLGlDQUFpQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtZQUNqRSxPQUFPLE1BQU0sRUFBRSxFQUFFLENBQUE7UUFDbkIsQ0FBQyxDQUNGLENBQUE7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsYUFBcUI7UUFJeEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsd0JBQXdCLENBQUM7Z0JBQy9DLGVBQWUsRUFBRSxhQUFhO2dCQUM5QixpQkFBaUIsRUFBRSxpQ0FBeUI7Z0JBQzVDLFdBQVcsRUFBRSxhQUFhO2dCQUMxQixNQUFNLEVBQUUsU0FBUzthQUNsQixDQUFDLENBQUE7WUFDRixPQUFPLElBQUksQ0FBQTtRQUNiLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsSUFBSSxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMzQixPQUFPLElBQUksQ0FBQTtZQUNiLENBQUM7WUFDRCxNQUFNLEdBQUcsQ0FBQTtRQUNYLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLGdCQUFnQjtRQUNwQixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FDMUMsRUFBRSxFQUNGLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FDM0MsQ0FBQTtRQUNELE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQTtJQUN4QixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLGlCQUFpQixDQUFDLFlBQW9CO1FBQzFDLE1BQU0sTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxZQUFZLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFBO1FBQzlELE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDO1lBQzVDLE1BQU0sRUFBRSxTQUFTO1lBQ2pCLEdBQUcsRUFBRSxDQUFDLEVBQUUsWUFBWSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUM7U0FDakUsQ0FBQyxDQUFBO1FBRUYsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztnQkFDaEMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFO2dCQUNWLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixhQUFhLEVBQUUsZUFBZTtnQkFDOUIsV0FBVyxFQUFFLElBQUksSUFBSSxFQUFFO2FBQ3hCLENBQUMsQ0FBQTtRQUNKLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUE7SUFDckIsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLFlBQW9CO1FBQ3JDLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVksQ0FBQyxDQUFBO1FBRTFDLE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUE7UUFDdEIsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztnQkFDdkMsTUFBTSxFQUFFLFNBQVM7Z0JBQ2pCLFVBQVUsRUFBRSxHQUFHO2dCQUNmLFlBQVksRUFBRSxHQUFHO2dCQUNqQixnQkFBZ0IsRUFBRSxDQUFDO2dCQUNuQixnQkFBZ0IsRUFBRSxDQUFDO2dCQUNuQixlQUFlLEVBQUUsQ0FBQztnQkFDbEIsa0JBQWtCLEVBQUUsQ0FBQztnQkFDckIsY0FBYyxFQUFFLENBQUM7YUFDbEIsQ0FBQyxDQUFBO1FBQ0osQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYixJQUFJLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzNCLE9BQU8sSUFBSSxDQUFBO1lBQ2IsQ0FBQztZQUNELE1BQU0sR0FBRyxDQUFBO1FBQ1gsQ0FBQztJQUNILENBQUM7SUFFRCw0REFBNEQ7SUFDNUQsS0FBSyxDQUFDLGlCQUFpQjtRQUNyQixNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtRQUNwRSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUE7SUFDcEIsQ0FBQztJQUVELGtFQUFrRTtJQUNsRSxLQUFLLENBQUMsZ0JBQWdCLENBQ3BCLEVBQVUsRUFDVixXQUFxRSxFQUFFO1FBRXZFLE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUFDO1lBQ2pDLEVBQUU7WUFDRixZQUFZLEVBQUUsSUFBSSxJQUFJLEVBQUU7WUFDeEIsR0FBRyxRQUFRO1NBQ1osQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGO0FBRUQsa0JBQWUscUJBQXFCLENBQUEifQ==
350
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3ByaW50ZnVsL3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBZ0RBLDRDQUlDO0FBYUQsZ0NBR0M7QUFpQkQsOENBMkJDO0FBaEhELHFEQUF5RDtBQUN6RCxtQ0FBbUM7QUFDbkMsaUVBQTREO0FBRTVELHVGQUE0RDtBQUM1RCwyRkFBZ0U7QUFDaEUsbUZBQXdEO0FBQ3hELDJGQUFnRTtBQUNoRSw2RkFBa0U7QUEyQmxFOzs7Ozs7R0FNRztBQUNVLFFBQUEseUJBQXlCLEdBQUcsU0FBUyxDQUFBO0FBRWxELGdFQUFnRTtBQUNuRCxRQUFBLG9CQUFvQixHQUFHLEVBQUUsQ0FBQTtBQUV0QyxrRUFBa0U7QUFDbEUsU0FBZ0IsZ0JBQWdCLENBQUMsUUFBZ0I7SUFDL0MsTUFBTSxZQUFZLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUE7SUFDbEMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFBO0lBQ3BDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUE7QUFDbEUsQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxTQUFnQixVQUFVLENBQUMsZUFBdUI7SUFDaEQsTUFBTSxNQUFNLEdBQUcsSUFBQSxtQkFBVSxFQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUM1RSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDOUIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsR0FB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
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * Merch bundles: one Medusa product that stands for several Printful ones.
4
+ *
5
+ * Printful has no notion of a bundle — it fulfils individual items. So a
6
+ * bundle is a Medusa product whose variant records which member variants it
7
+ * contains, and order creation expands it back into those members.
8
+ *
9
+ * **Why expansion is mandatory rather than a nicety.** `create-printful-order`
10
+ * resolves one order line to one Printful item via `item.variant_id`. A bundle
11
+ * left unexpanded therefore ships a single thing where the customer bought
12
+ * three — or, if the bundle variant has no Printful link at all, the order is
13
+ * skipped as `no_printful_items` and nothing ships.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.BUNDLE_MEMBERS_KEY = void 0;
17
+ exports.bundleMembersOf = bundleMembersOf;
18
+ exports.isBundleLine = isBundleLine;
19
+ exports.expandOrderLines = expandOrderLines;
20
+ exports.medusaLineIdFor = medusaLineIdFor;
21
+ exports.planBundlePass = planBundlePass;
22
+ exports.planBundlePublication = planBundlePublication;
23
+ exports.planBundleAvailability = planBundleAvailability;
24
+ const stock_1 = require("./stock");
25
+ /** Statuses meaning a variant cannot be ordered. Mirrors `stock.ts`. */
26
+ const UNAVAILABLE = new Set([
27
+ "out_of_stock",
28
+ "temporary_out_of_stock",
29
+ "discontinued",
30
+ ]);
31
+ /** Where a bundle's composition lives, on the variant and on the order line. */
32
+ exports.BUNDLE_MEMBERS_KEY = "printful_bundle_members";
33
+ /**
34
+ * The members recorded on a line, or nothing.
35
+ *
36
+ * Metadata is free-form JSON, so this validates rather than trusts: something
37
+ * else writing a string to this key must not crash order creation.
38
+ */
39
+ function bundleMembersOf(line) {
40
+ const raw = (line?.metadata ?? {})[exports.BUNDLE_MEMBERS_KEY];
41
+ if (!Array.isArray(raw)) {
42
+ return [];
43
+ }
44
+ const members = [];
45
+ for (const entry of raw) {
46
+ if (!entry || typeof entry !== "object") {
47
+ continue;
48
+ }
49
+ const variantId = entry.variant_id;
50
+ if (typeof variantId !== "string" || !variantId.trim()) {
51
+ continue;
52
+ }
53
+ const quantity = Number(entry.quantity ?? 1);
54
+ members.push({
55
+ variant_id: variantId,
56
+ quantity: Number.isFinite(quantity) && quantity > 0 ? quantity : 1,
57
+ });
58
+ }
59
+ return members;
60
+ }
61
+ /**
62
+ * Whether a line stands for several products.
63
+ *
64
+ * A line whose member list is empty is *not* a bundle. Treating it as one
65
+ * would expand it to nothing, and an order of nothing looks identical to an
66
+ * order Printful was never asked about. Left alone, it flows through the
67
+ * ordinary unresolved-variant path, which reports it.
68
+ */
69
+ function isBundleLine(line) {
70
+ return bundleMembersOf(line).length > 0;
71
+ }
72
+ /**
73
+ * Replace every bundle line with the lines it stands for.
74
+ *
75
+ * Composition is read from the line's own metadata, captured when the customer
76
+ * bought — never looked up live. A merchant who edits a bundle after a sale
77
+ * must not change what an already-placed order ships.
78
+ *
79
+ * Ordinary lines pass through untouched and keep their position, so a cart
80
+ * mixing bundles and singles reaches Printful in the order it was built.
81
+ */
82
+ function expandOrderLines(lines) {
83
+ const out = [];
84
+ for (const line of lines) {
85
+ const members = bundleMembersOf(line);
86
+ if (members.length === 0) {
87
+ out.push(line);
88
+ continue;
89
+ }
90
+ for (const member of members) {
91
+ out.push({
92
+ // Synthesised, but stable and traceable: two bundles in one cart
93
+ // cannot collide, and the id says where the line came from.
94
+ id: `${line.id}::${member.variant_id}`,
95
+ variant_id: member.variant_id,
96
+ title: line.title,
97
+ // Two bundles each holding two stickers is four stickers. Dropping
98
+ // this multiplication ships a customer half their order.
99
+ quantity: (member.quantity ?? 1) * Number(line.quantity || 1),
100
+ metadata: {},
101
+ bundle_line_id: line.id,
102
+ });
103
+ }
104
+ }
105
+ return out;
106
+ }
107
+ /** Separates the bundle line id from the member variant id in a synthetic id. */
108
+ const SYNTHETIC_SEPARATOR = "::";
109
+ /**
110
+ * The Medusa line an `external_id` from Printful refers to.
111
+ *
112
+ * Expansion sends synthetic ids like `ordli_abc::variant_tee` as `external_id`,
113
+ * because Printful needs each item distinguishable and two members of one
114
+ * bundle would otherwise share the bundle line's id.
115
+ *
116
+ * Fulfillment reads those ids back to decide which Medusa line a parcel filled.
117
+ * Without this, a bundle's items resolve to an id no Medusa line has, every
118
+ * parcel clamps to zero open quantity, and the order is never marked shipped.
119
+ *
120
+ * A member id maps back to the *bundle* line, since that is the line the
121
+ * customer bought and the only one Medusa can fulfil.
122
+ */
123
+ function medusaLineIdFor(externalId) {
124
+ const at = externalId.indexOf(SYNTHETIC_SEPARATOR);
125
+ return at === -1 ? externalId : externalId.slice(0, at);
126
+ }
127
+ /**
128
+ * Which bundle products the sync should rewrite, and to what.
129
+ *
130
+ * Bundles are invisible to the ordinary sync: they have no Printful product of
131
+ * their own, so no `sync_product` ever names them and the per-product loop
132
+ * never reaches them. Without this pass a bundle stays on sale after a member
133
+ * sells out, and every such order fails at Printful.
134
+ *
135
+ * Availability is read from the member variants passed in, not from the bundle
136
+ * — the bundle variant has no Printful status of its own to read.
137
+ *
138
+ * Returns only products that need writing, so a sync over a catalogue with no
139
+ * bundle changes issues no updates at all.
140
+ */
141
+ function planBundlePass(input) {
142
+ const writes = [];
143
+ for (const bundle of input.bundles) {
144
+ const memberIds = (bundle.variants ?? []).flatMap((v) => bundleMembersOf({ id: v.id, quantity: 1, metadata: v.metadata }).map((m) => m.variant_id));
145
+ if (memberIds.length === 0) {
146
+ continue;
147
+ }
148
+ // A member variant the sync could not load is left out of the decision
149
+ // rather than counted as sold out: a failed lookup is not evidence that
150
+ // Printful ran out of anything, and drafting on it would hide a live
151
+ // bundle on a transient error.
152
+ const known = memberIds
153
+ .map((id) => input.variantsById.get(id))
154
+ .filter((v) => !!v);
155
+ // Knowing nothing about any member is not the same as knowing they are all
156
+ // in stock. Left to fall through, a bundle drafted for a sellout would be
157
+ // republished on the strength of a lookup that simply failed.
158
+ if (known.length === 0) {
159
+ continue;
160
+ }
161
+ const plan = planBundlePublication({
162
+ members: known,
163
+ currentStatus: bundle.status === "published" ? "published" : "draft",
164
+ currentMetadata: (bundle.metadata ?? {}),
165
+ });
166
+ if (!plan.changed) {
167
+ continue;
168
+ }
169
+ writes.push({
170
+ product_id: bundle.id,
171
+ status: plan.status,
172
+ metadata: plan.metadata,
173
+ missing: memberIds.filter((id) => {
174
+ const status = input.variantsById.get(id)?.metadata?.printful_availability_status;
175
+ return typeof status === "string" && UNAVAILABLE.has(status);
176
+ }),
177
+ });
178
+ }
179
+ return writes;
180
+ }
181
+ /**
182
+ * Whether a bundle should be published, from the stock of its members.
183
+ *
184
+ * Reuses `resolvePublication` so a bundle obeys the same ownership rule as
185
+ * every other product: the plugin undoes only unpublishes it performed, and a
186
+ * draft the merchant made themselves is left alone however available Printful
187
+ * says the members are.
188
+ *
189
+ * What differs is the threshold. `planStockActions` drafts a product only when
190
+ * *every* variant is gone, because any remaining variant is still sellable. A
191
+ * bundle is a promise to ship all of it, so one missing member already breaks
192
+ * the promise.
193
+ *
194
+ * A bundle with no members recorded is left untouched — that is a bundle the
195
+ * merchant has not finished configuring, not one that sold out.
196
+ */
197
+ function planBundlePublication(input) {
198
+ const availability = planBundleAvailability(input.members.map((m) => m?.metadata ?? {}));
199
+ // One missing member is enough. A bundle with no members recorded has no
200
+ // unavailable ones either, so it falls through as available — an
201
+ // unconfigured bundle is not a sold-out one.
202
+ const allUnavailable = availability.unavailableCount > 0;
203
+ return (0, stock_1.resolvePublication)({
204
+ plan: {
205
+ allUnavailable,
206
+ status: allUnavailable ? "draft" : "published",
207
+ hasDiscontinued: false,
208
+ variantAvailability: {},
209
+ },
210
+ currentStatus: input.currentStatus,
211
+ currentMetadata: input.currentMetadata,
212
+ });
213
+ }
214
+ /**
215
+ * Whether a bundle can be sold, from the availability of its members.
216
+ *
217
+ * A bundle is a promise to ship all of it, so one sold-out member makes the
218
+ * promise unkeepable however available the rest are.
219
+ *
220
+ * Reads `printful_availability_status`, which the sync already writes — no new
221
+ * source of truth, and no second place to keep in step with Printful.
222
+ *
223
+ * An unknown status counts as available, matching `planStockActions`: the
224
+ * unavailable set is a closed list, and a bundle must not be stricter about a
225
+ * status than the member product itself is.
226
+ */
227
+ function planBundleAvailability(members) {
228
+ let unavailable = 0;
229
+ for (const member of members) {
230
+ const status = member?.printful_availability_status;
231
+ if (typeof status === "string" && UNAVAILABLE.has(status)) {
232
+ unavailable += 1;
233
+ }
234
+ }
235
+ return {
236
+ // An empty bundle is unavailable rather than vacuously available: there is
237
+ // nothing to ship, which is not the same as everything being in stock.
238
+ available: members.length > 0 && unavailable === 0,
239
+ memberCount: members.length,
240
+ unavailableCount: unavailable,
241
+ };
242
+ }
243
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2J1bmRsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7OztHQVlHOzs7QUE4Q0gsMENBeUJDO0FBVUQsb0NBSUM7QUFZRCw0Q0E2QkM7QUFtQkQsMENBR0M7QUFtQ0Qsd0NBdURDO0FBd0JELHNEQXdCQztBQWVELHdEQW1CQztBQTlURCxtQ0FBb0U7QUFFcEUsd0VBQXdFO0FBQ3hFLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzFCLGNBQWM7SUFDZCx3QkFBd0I7SUFDeEIsY0FBYztDQUNmLENBQUMsQ0FBQTtBQUVGLGdGQUFnRjtBQUNuRSxRQUFBLGtCQUFrQixHQUFHLHlCQUF5QixDQUFBO0FBNEIzRDs7Ozs7R0FLRztBQUNILFNBQWdCLGVBQWUsQ0FDN0IsSUFBNEM7SUFFNUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLDBCQUFrQixDQUFDLENBQUE7SUFDdEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QixPQUFPLEVBQUUsQ0FBQTtJQUNYLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBbUIsRUFBRSxDQUFBO0lBQ2xDLEtBQUssTUFBTSxLQUFLLElBQUksR0FBRyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN4QyxTQUFRO1FBQ1YsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFJLEtBQXNCLENBQUMsVUFBVSxDQUFBO1FBQ3BELElBQUksT0FBTyxTQUFTLEtBQUssUUFBUSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDdkQsU0FBUTtRQUNWLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFN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