@legenki/print2medusa 0.8.2 → 0.9.3

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,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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2J1bmRsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7OztHQVlHOzs7QUE4Q0gsMENBeUJDO0FBVUQsb0NBSUM7QUFZRCw0Q0E2QkM7QUFtQkQsMENBR0M7QUFtQ0Qsd0NBdURDO0FBd0JELHNEQXdCQztBQWVELHdEQW1CQztBQTlURCxtQ0FBb0U7QUFFcEUsd0VBQXdFO0FBQ3hFLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzFCLGNBQWM7SUFDZCx3QkFBd0I7SUFDeEIsY0FBYztDQUNmLENBQUMsQ0FBQTtBQUVGLGdGQUFnRjtBQUNuRSxRQUFBLGtCQUFrQixHQUFHLHlCQUF5QixDQUFBO0FBNEIzRDs7Ozs7R0FLRztBQUNILFNBQWdCLGVBQWUsQ0FDN0IsSUFBNEM7SUFFNUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLDBCQUFrQixDQUFDLENBQUE7SUFDdEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QixPQUFPLEVBQUUsQ0FBQTtJQUNYLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBbUIsRUFBRSxDQUFBO0lBQ2xDLEtBQUssTUFBTSxLQUFLLElBQUksR0FBRyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN4QyxTQUFRO1FBQ1YsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFJLEtBQXNCLENBQUMsVUFBVSxDQUFBO1FBQ3BELElBQUksT0FBTyxTQUFTLEtBQUssUUFBUSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDdkQsU0FBUTtRQUNWLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUUsS0FBc0IsQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUE7UUFDOUQsT0FBTyxDQUFDLElBQUksQ0FBQztZQUNYLFVBQVUsRUFBRSxTQUFTO1lBQ3JCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNuRSxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsT0FBTyxPQUFPLENBQUE7QUFDaEIsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFnQixZQUFZLENBQzFCLElBQTRDO0lBRTVDLE9BQU8sZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUE7QUFDekMsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLGdCQUFnQixDQUM5QixLQUE0QjtJQUU1QixNQUFNLEdBQUcsR0FBd0IsRUFBRSxDQUFBO0lBRW5DLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7UUFDekIsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3JDLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ2QsU0FBUTtRQUNWLENBQUM7UUFFRCxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQzdCLEdBQUcsQ0FBQyxJQUFJLENBQUM7Z0JBQ1AsaUVBQWlFO2dCQUNqRSw0REFBNEQ7Z0JBQzVELEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxFQUFFLEtBQUssTUFBTSxDQUFDLFVBQVUsRUFBRTtnQkFDdEMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO2dCQUM3QixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7Z0JBQ2pCLG1FQUFtRTtnQkFDbkUseURBQXlEO2dCQUN6RCxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQztnQkFDN0QsUUFBUSxFQUFFLEVBQUU7Z0JBQ1osY0FBYyxFQUFFLElBQUksQ0FBQyxFQUFFO2FBQ3hCLENBQUMsQ0FBQTtRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxHQUFHLENBQUE7QUFDWixDQUFDO0FBRUQsaUZBQWlGO0FBQ2pGLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFBO0FBRWhDOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxTQUFnQixlQUFlLENBQUMsVUFBa0I7SUFDaEQsTUFBTSxFQUFFLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFBO0lBQ2xELE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0FBQ3pELENBQUM7QUFxQkQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxLQUk5QjtJQUNDLE1BQU0sTUFBTSxHQUF5QixFQUFFLENBQUE7SUFFdkMsS0FBSyxNQUFNLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ3RELGVBQWUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FDbEUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQ3BCLENBQ0YsQ0FBQTtRQUNELElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMzQixTQUFRO1FBQ1YsQ0FBQztRQUVELHVFQUF1RTtRQUN2RSx3RUFBd0U7UUFDeEUscUVBQXFFO1FBQ3JFLCtCQUErQjtRQUMvQixNQUFNLEtBQUssR0FBRyxTQUFTO2FBQ3BCLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDdkMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFzRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBRXpFLDJFQUEyRTtRQUMzRSwwRUFBMEU7UUFDMUUsOERBQThEO1FBQzlELElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN2QixTQUFRO1FBQ1YsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLHFCQUFxQixDQUFDO1lBQ2pDLE9BQU8sRUFBRSxLQUFLO1lBQ2QsYUFBYSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLE9BQU87WUFDcEUsZUFBZSxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQTRCO1NBQ3BFLENBQUMsQ0FBQTtRQUVGLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEIsU0FBUTtRQUNWLENBQUM7UUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDO1lBQ1YsVUFBVSxFQUFFLE1BQU0sQ0FBQyxFQUFFO1lBQ3JCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtZQUNuQixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsT0FBTyxFQUFFLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDL0IsTUFBTSxNQUFNLEdBQ1YsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLDRCQUE0QixDQUFBO2dCQUNwRSxPQUFPLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxXQUFXLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFBO1lBQzlELENBQUMsQ0FBQztTQUNILENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQTtBQUNmLENBQUM7QUFRRDs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxLQUlyQztJQUNDLE1BQU0sWUFBWSxHQUFHLHNCQUFzQixDQUN6QyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLFFBQVEsSUFBSSxFQUFFLENBQUMsQ0FDNUMsQ0FBQTtJQUVELHlFQUF5RTtJQUN6RSxpRUFBaUU7SUFDakUsNkNBQTZDO0lBQzdDLE1BQU0sY0FBYyxHQUFHLFlBQVksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLENBQUE7SUFFeEQsT0FBTyxJQUFBLDBCQUFrQixFQUFDO1FBQ3hCLElBQUksRUFBRTtZQUNKLGNBQWM7WUFDZCxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVc7WUFDOUMsZUFBZSxFQUFFLEtBQUs7WUFDdEIsbUJBQW1CLEVBQUUsRUFBRTtTQUN4QjtRQUNELGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYTtRQUNsQyxlQUFlLEVBQUUsS0FBSyxDQUFDLGVBQWU7S0FDdkMsQ0FBQyxDQUFBO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILFNBQWdCLHNCQUFzQixDQUNwQyxPQUEwRDtJQUUxRCxJQUFJLFdBQVcsR0FBRyxDQUFDLENBQUE7SUFFbkIsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM3QixNQUFNLE1BQU0sR0FBRyxNQUFNLEVBQUUsNEJBQTRCLENBQUE7UUFDbkQsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksV0FBVyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzFELFdBQVcsSUFBSSxDQUFDLENBQUE7UUFDbEIsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPO1FBQ0wsMkVBQTJFO1FBQzNFLHVFQUF1RTtRQUN2RSxTQUFTLEVBQUUsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksV0FBVyxLQUFLLENBQUM7UUFDbEQsV0FBVyxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQzNCLGdCQUFnQixFQUFFLFdBQVc7S0FDOUIsQ0FBQTtBQUNILENBQUMifQ==
@@ -1,8 +1,4 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.minorUnitFactor = minorUnitFactor;
4
- exports.isZeroDecimalCurrency = isZeroDecimalCurrency;
5
- const utils_1 = require("@medusajs/framework/utils");
6
2
  /**
7
3
  * How many minor units make one major unit of a currency.
8
4
  *
@@ -11,13 +7,73 @@ const utils_1 = require("@medusajs/framework/utils");
11
7
  * Scaling those by 100 anyway produces a value a hundredfold too large for
12
8
  * anything reading it back with Medusa's own conventions.
13
9
  *
14
- * The table is Medusa's `defaultCurrencies` (126 entries, each carrying
15
- * `decimal_digits`) rather than a list written out here. A hand-kept list is
16
- * how HUF, ISK and CLP get missed — they are zero-decimal and rarely on the
17
- * short list people remember. `@medusajs/framework` is a peer dependency, so
18
- * the table is always present in a host app; this is plain data, not a
19
- * container binding, so `src/utils/` stays testable without one.
10
+ * **Why the list is written out here rather than imported.** It used to come
11
+ * from `defaultCurrencies` in `@medusajs/framework/utils`, which is correct for
12
+ * server code and fatal for the browser: this file is also imported by the
13
+ * admin order widget, and `@medusajs/framework/utils` reaches
14
+ * `@medusajs/utils/dist/auth/token.js` → `jsonwebtoken` → `jws`, which calls
15
+ * `util.inherits`. That does not exist in a browser, so the whole Medusa admin
16
+ * failed to load with `chr.inherits is not a function` — not a broken widget,
17
+ * a blank admin.
18
+ *
19
+ * The usual objection to a hand-kept list is that HUF, ISK and CLP get missed.
20
+ * That is answered by a test rather than by discipline: `currency.test.ts`
21
+ * compares this set against Medusa's own table and fails if they diverge, so
22
+ * the data stays Medusa's while the import stays server-side.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.ZERO_DECIMAL_CURRENCIES = void 0;
26
+ exports.minorUnitFactor = minorUnitFactor;
27
+ exports.isZeroDecimalCurrency = isZeroDecimalCurrency;
28
+ /**
29
+ * Currencies with no subunit, from Medusa's `defaultCurrencies`
30
+ * (`decimal_digits === 0`). Kept in sync by test, not by hand.
31
+ *
32
+ * Exported so `currency.test.ts` can compare the set itself against Medusa's
33
+ * table in both directions — a code invented here is invisible to any check
34
+ * that only walks Medusa's side.
20
35
  */
36
+ exports.ZERO_DECIMAL_CURRENCIES = new Set([
37
+ "AFN",
38
+ "ALL",
39
+ "AMD",
40
+ "BIF",
41
+ "CLP",
42
+ "COP",
43
+ "CRC",
44
+ "DJF",
45
+ "GNF",
46
+ "HUF",
47
+ "IDR",
48
+ "IQD",
49
+ "IRR",
50
+ "IRT",
51
+ "ISK",
52
+ "JPY",
53
+ "KMF",
54
+ "KRW",
55
+ "LBP",
56
+ "MGA",
57
+ "MMK",
58
+ "MNT",
59
+ "MUR",
60
+ "PKR",
61
+ "PYG",
62
+ "RSD",
63
+ "RWF",
64
+ "SOS",
65
+ "SYP",
66
+ "TZS",
67
+ "UGX",
68
+ "UZS",
69
+ "VND",
70
+ "XAF",
71
+ "XOF",
72
+ "XPF",
73
+ "YER",
74
+ "ZMK",
75
+ "ZWL",
76
+ ]);
21
77
  function minorUnitFactor(currencyCode) {
22
78
  return isZeroDecimalCurrency(currencyCode) ? 1 : 100;
23
79
  }
@@ -36,7 +92,6 @@ function isZeroDecimalCurrency(currencyCode) {
36
92
  return false;
37
93
  }
38
94
  // Printful sends "USD", Medusa stores "usd", and both reach this.
39
- const entry = utils_1.defaultCurrencies[currencyCode.toUpperCase()];
40
- return entry?.decimal_digits === 0;
95
+ return exports.ZERO_DECIMAL_CURRENCIES.has(currencyCode.toUpperCase());
41
96
  }
42
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VycmVuY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvY3VycmVuY3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpQkEsMENBSUM7QUFZRCxzREFTQztBQTFDRCxxREFBNkQ7QUFFN0Q7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxTQUFnQixlQUFlLENBQzdCLFlBQXVDO0lBRXZDLE9BQU8scUJBQXFCLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFBO0FBQ3RELENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FDbkMsWUFBdUM7SUFFdkMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ2xCLE9BQU8sS0FBSyxDQUFBO0lBQ2QsQ0FBQztJQUNELGtFQUFrRTtJQUNsRSxNQUFNLEtBQUssR0FBRyx5QkFBaUIsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQTtJQUMzRCxPQUFPLEtBQUssRUFBRSxjQUFjLEtBQUssQ0FBQyxDQUFBO0FBQ3BDLENBQUMifQ==
97
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VycmVuY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvY3VycmVuY3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7OztBQW9ESCwwQ0FJQztBQVlELHNEQVFDO0FBMUVEOzs7Ozs7O0dBT0c7QUFDVSxRQUFBLHVCQUF1QixHQUFHLElBQUksR0FBRyxDQUFDO0lBQzdDLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztDQUNOLENBQUMsQ0FBQTtBQUVGLFNBQWdCLGVBQWUsQ0FDN0IsWUFBdUM7SUFFdkMsT0FBTyxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUE7QUFDdEQsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLHFCQUFxQixDQUNuQyxZQUF1QztJQUV2QyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDbEIsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0Qsa0VBQWtFO0lBQ2xFLE9BQU8sK0JBQXVCLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFBO0FBQ2hFLENBQUMifQ==