@thorprovider/adapters 4.2.0 → 4.3.0

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/PROVIDER_IMPLEMENTATION_ANALYSIS.md +659 -0
  3. package/README.md +19 -0
  4. package/dist/index.d.mts +249 -2
  5. package/dist/index.d.ts +249 -2
  6. package/dist/index.js +1450 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +1448 -2
  9. package/dist/index.mjs.map +1 -1
  10. package/docs/RETRY_SOLUTION_SUMMARY.md +26 -11
  11. package/docs/authentication.md +115 -62
  12. package/docs/capabilities-system.md +34 -2
  13. package/docs/category-customization.md +37 -29
  14. package/docs/fetch-reliability-solution.md +127 -278
  15. package/docs/getting-started.md +43 -29
  16. package/docs/profile-management.md +68 -38
  17. package/docs/providers-overview.md +14 -0
  18. package/docs/services-overview.md +20 -2
  19. package/package.json +10 -6
  20. package/quick-reference.md +34 -0
  21. package/src/factory/index.ts +4 -0
  22. package/src/index.ts +3 -0
  23. package/src/providers/index.ts +3 -0
  24. package/src/providers/medusa/admin.test.ts +404 -0
  25. package/src/providers/medusa/admin.ts +442 -0
  26. package/src/providers/medusa/auth.test.ts +137 -0
  27. package/src/providers/medusa/auth.ts +96 -1
  28. package/src/providers/medusa/index.ts +21 -1
  29. package/src/providers/shopify/auth.ts +6 -0
  30. package/src/providers/stelorder/client.test-helpers.ts +3 -0
  31. package/src/providers/stelorder/client.test.ts +58 -0
  32. package/src/providers/stelorder/client.ts +326 -0
  33. package/src/providers/stelorder/index.test.ts +48 -0
  34. package/src/providers/stelorder/index.ts +685 -0
  35. package/src/providers/stelorder/live-smoke.test.ts +54 -0
  36. package/src/providers/stelorder/transforms.test.ts +103 -0
  37. package/src/providers/stelorder/transforms.ts +631 -0
  38. package/src/resilience/README.md +70 -48
  39. package/src/types/capabilities.types.ts +51 -0
  40. package/vitest.config.ts +13 -0
  41. package/vitest.setup.ts +6 -0
  42. package/.turbo/turbo-build.log +0 -18
  43. package/dist/.tsbuildinfo +0 -1
  44. package/src/core/errors.js +0 -161
  45. package/src/core/fetch-utils.js +0 -240
  46. package/src/core/logger.js +0 -63
  47. package/src/metadata/channel-scope-validation.js +0 -136
  48. package/src/metadata/channel-scope.js +0 -174
  49. package/src/metadata/index.js +0 -31
  50. package/src/providers/medusa/auth.js +0 -601
  51. package/src/providers/medusa/index.js +0 -2485
  52. package/src/providers/medusa/payment.js +0 -265
  53. package/src/providers/medusa/transforms.js +0 -505
  54. package/src/types/capabilities.types.js +0 -141
  55. package/src/types/provider.js +0 -9
  56. package/src/utils/payment-utils.js +0 -152
@@ -1,2485 +0,0 @@
1
- "use strict";
2
- /**
3
- * @thorprovider/adapters v2.0
4
- * Medusa Provider - Main implementation
5
- */
6
- var __assign = (this && this.__assign) || function () {
7
- __assign = Object.assign || function(t) {
8
- for (var s, i = 1, n = arguments.length; i < n; i++) {
9
- s = arguments[i];
10
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
11
- t[p] = s[p];
12
- }
13
- return t;
14
- };
15
- return __assign.apply(this, arguments);
16
- };
17
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
- return new (P || (P = Promise))(function (resolve, reject) {
20
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
- step((generator = generator.apply(thisArg, _arguments || [])).next());
24
- });
25
- };
26
- var __generator = (this && this.__generator) || function (thisArg, body) {
27
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
28
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
- function verb(n) { return function (v) { return step([n, v]); }; }
30
- function step(op) {
31
- if (f) throw new TypeError("Generator is already executing.");
32
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
- if (y = 0, t) op = [op[0] & 2, t.value];
35
- switch (op[0]) {
36
- case 0: case 1: t = op; break;
37
- case 4: _.label++; return { value: op[1], done: false };
38
- case 5: _.label++; y = op[1]; op = [0]; continue;
39
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
- default:
41
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
- if (t[2]) _.ops.pop();
46
- _.trys.pop(); continue;
47
- }
48
- op = body.call(thisArg, _);
49
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
- }
52
- };
53
- Object.defineProperty(exports, "__esModule", { value: true });
54
- exports.MedusaProvider = void 0;
55
- var js_sdk_1 = require("@medusajs/js-sdk");
56
- var types_1 = require("@thorprovider/types");
57
- var capabilities_types_1 = require("../../types/capabilities.types");
58
- var logger_1 = require("../../core/logger");
59
- var fetch_utils_1 = require("../../core/fetch-utils");
60
- var errors_1 = require("../../core/errors");
61
- var payment_utils_1 = require("../../utils/payment-utils");
62
- var transforms_1 = require("./transforms");
63
- var auth_1 = require("./auth");
64
- var payment_1 = require("./payment");
65
- var metadata_1 = require("../../metadata");
66
- var MEDUSA_CART_RETRIEVE_FIELDS = '+items,+items.variant,+items.variant.product,+items.variant.product.thumbnail,+items.variant.options,+items.variant.options.option';
67
- /**
68
- * Medusa commerce provider
69
- *
70
- * Implements CommerceProvider interface for Medusa.js v2
71
- */
72
- var MedusaProvider = /** @class */ (function () {
73
- function MedusaProvider(config) {
74
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
75
- this.name = 'medusa';
76
- this.version = '2.0.0';
77
- /**
78
- * Medusa backend capabilities
79
- * Defines what operations Medusa supports
80
- */
81
- this.capabilities = capabilities_types_1.MEDUSA_CAPABILITIES;
82
- /**
83
- * In-memory cache for region countries
84
- * Structure: Map<regionId, { countries: Country[], expiresAt: number }>
85
- */
86
- this.regionCountriesCache = new Map();
87
- /**
88
- * Cache TTL for region countries (5 minutes)
89
- */
90
- this.REGION_COUNTRIES_CACHE_TTL = 5 * 60 * 1000;
91
- /**
92
- * In-memory cache for storefront context (60 second TTL)
93
- */
94
- this.storefrontContextCache = null;
95
- /**
96
- * Cache TTL for storefront context (60 seconds)
97
- */
98
- this.STOREFRONT_CONTEXT_CACHE_TTL = 60 * 1000;
99
- this.logger = (0, logger_1.createLogger)('MedusaProvider', config.debug);
100
- this.currencyCode = (_a = config.currencyCode) !== null && _a !== void 0 ? _a : 'USD';
101
- this.baseUrl = config.baseUrl;
102
- this.publishableKey = config.publishableKey;
103
- // Store retry configuration
104
- this.retryConfig = {
105
- maxRetries: (_c = (_b = config.retry) === null || _b === void 0 ? void 0 : _b.maxRetries) !== null && _c !== void 0 ? _c : 3,
106
- timeoutMs: (_e = (_d = config.retry) === null || _d === void 0 ? void 0 : _d.timeoutMs) !== null && _e !== void 0 ? _e : 10000,
107
- initialDelayMs: (_g = (_f = config.retry) === null || _f === void 0 ? void 0 : _f.initialDelayMs) !== null && _g !== void 0 ? _g : 300,
108
- backoffMultiplier: (_j = (_h = config.retry) === null || _h === void 0 ? void 0 : _h.backoffMultiplier) !== null && _j !== void 0 ? _j : 2,
109
- maxDelayMs: (_l = (_k = config.retry) === null || _k === void 0 ? void 0 : _k.maxDelayMs) !== null && _l !== void 0 ? _l : 5000,
110
- retryableStatusCodes: (_o = (_m = config.retry) === null || _m === void 0 ? void 0 : _m.retryableStatusCodes) !== null && _o !== void 0 ? _o : [408, 429, 500, 502, 503, 504],
111
- };
112
- this.logger.info('Initializing Medusa Provider', {
113
- baseUrl: config.baseUrl,
114
- currencyCode: this.currencyCode,
115
- hasAuth: !!config.auth,
116
- retryConfig: this.retryConfig,
117
- });
118
- this.sdk = new js_sdk_1.default({
119
- baseUrl: config.baseUrl,
120
- publishableKey: config.publishableKey,
121
- debug: (_p = config.debug) !== null && _p !== void 0 ? _p : false,
122
- // Always use JWT mode for auth - SDK needs to send Bearer tokens
123
- // Configure storage method for JWT tokens (browser only)
124
- auth: config.auth
125
- ? {
126
- type: 'jwt',
127
- // Use localStorage in browser, memory storage on server
128
- jwtTokenStorageMethod: typeof window !== 'undefined' ? 'local' : 'memory',
129
- }
130
- : undefined,
131
- });
132
- // Initialize auth provider if config is provided
133
- if (config.auth) {
134
- this.auth = new auth_1.MedusaAuthProvider(this.sdk, config.auth, config.debug);
135
- this.logger.info('Auth provider initialized');
136
- }
137
- }
138
- MedusaProvider.prototype.retrieveCartWithLineDetails = function (cartId) {
139
- return __awaiter(this, void 0, void 0, function () {
140
- var cart;
141
- return __generator(this, function (_a) {
142
- switch (_a.label) {
143
- case 0: return [4 /*yield*/, this.sdk.store.cart.retrieve(cartId, {
144
- fields: MEDUSA_CART_RETRIEVE_FIELDS,
145
- })];
146
- case 1:
147
- cart = (_a.sent()).cart;
148
- return [2 /*return*/, cart];
149
- }
150
- });
151
- });
152
- };
153
- // ============================================
154
- // Product Operations
155
- // ============================================
156
- /**
157
- * Wrapper for SDK calls with retry logic
158
- * Handles network failures and temporary backend issues
159
- */
160
- MedusaProvider.prototype.withRetry = function (operation, operationName, context) {
161
- return __awaiter(this, void 0, void 0, function () {
162
- var lastError, _loop_1, this_1, attempt, state_1;
163
- var _this = this;
164
- var _a, _b, _c, _d;
165
- return __generator(this, function (_e) {
166
- switch (_e.label) {
167
- case 0:
168
- _loop_1 = function (attempt) {
169
- var timeoutPromise, result, error_1, isRetryable, shouldRetry, delay, cappedDelay_1;
170
- return __generator(this, function (_f) {
171
- switch (_f.label) {
172
- case 0:
173
- _f.trys.push([0, 2, , 6]);
174
- timeoutPromise = new Promise(function (_, reject) {
175
- setTimeout(function () {
176
- reject(new Error("Request timeout after ".concat(_this.retryConfig.timeoutMs, "ms")));
177
- }, _this.retryConfig.timeoutMs);
178
- });
179
- return [4 /*yield*/, Promise.race([operation(), timeoutPromise])];
180
- case 1:
181
- result = _f.sent();
182
- if (attempt > 0) {
183
- this_1.logger.info("".concat(operationName, " succeeded after ").concat(attempt, " retries"), context);
184
- }
185
- return [2 /*return*/, { value: result }];
186
- case 2:
187
- error_1 = _f.sent();
188
- lastError = error_1;
189
- isRetryable = ((_a = error_1.message) === null || _a === void 0 ? void 0 : _a.includes('fetch failed')) ||
190
- ((_b = error_1.message) === null || _b === void 0 ? void 0 : _b.includes('timeout')) ||
191
- ((_c = error_1.message) === null || _c === void 0 ? void 0 : _c.includes('ECONNREFUSED')) ||
192
- ((_d = error_1.message) === null || _d === void 0 ? void 0 : _d.includes('ETIMEDOUT')) ||
193
- (error_1.status && this_1.retryConfig.retryableStatusCodes.includes(error_1.status));
194
- shouldRetry = attempt < this_1.retryConfig.maxRetries && isRetryable;
195
- if (!shouldRetry) return [3 /*break*/, 4];
196
- delay = this_1.retryConfig.initialDelayMs * Math.pow(this_1.retryConfig.backoffMultiplier, attempt);
197
- cappedDelay_1 = Math.min(delay, this_1.retryConfig.maxDelayMs);
198
- this_1.logger.warn("".concat(operationName, " failed, retrying..."), __assign(__assign({}, context), { attempt: attempt + 1, maxAttempts: this_1.retryConfig.maxRetries + 1, nextRetryIn: "".concat(cappedDelay_1, "ms"), error: error_1.message }));
199
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, cappedDelay_1); })];
200
- case 3:
201
- _f.sent();
202
- return [3 /*break*/, 5];
203
- case 4:
204
- this_1.logger.error("".concat(operationName, " failed after all retries"), __assign(__assign({}, context), { totalAttempts: attempt + 1, error: error_1.message }));
205
- return [2 /*return*/, "break"];
206
- case 5: return [3 /*break*/, 6];
207
- case 6: return [2 /*return*/];
208
- }
209
- });
210
- };
211
- this_1 = this;
212
- attempt = 0;
213
- _e.label = 1;
214
- case 1:
215
- if (!(attempt <= this.retryConfig.maxRetries)) return [3 /*break*/, 4];
216
- return [5 /*yield**/, _loop_1(attempt)];
217
- case 2:
218
- state_1 = _e.sent();
219
- if (typeof state_1 === "object")
220
- return [2 /*return*/, state_1.value];
221
- if (state_1 === "break")
222
- return [3 /*break*/, 4];
223
- _e.label = 3;
224
- case 3:
225
- attempt++;
226
- return [3 /*break*/, 1];
227
- case 4:
228
- // All retries exhausted
229
- throw lastError;
230
- }
231
- });
232
- });
233
- };
234
- MedusaProvider.prototype.getProduct = function (handle, options) {
235
- return __awaiter(this, void 0, void 0, function () {
236
- var error_2;
237
- var _this = this;
238
- return __generator(this, function (_a) {
239
- switch (_a.label) {
240
- case 0:
241
- this.logger.debug('getProduct', { handle: handle, regionId: options === null || options === void 0 ? void 0 : options.regionId });
242
- _a.label = 1;
243
- case 1:
244
- _a.trys.push([1, 3, , 4]);
245
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
246
- var baseFields, pricingFields, fields, queryParams, salesChannelId, products, transformedProduct;
247
- return __generator(this, function (_a) {
248
- switch (_a.label) {
249
- case 0:
250
- baseFields = '+variants,+variants.inventory_quantity,+options,+images,+tags';
251
- pricingFields = ',+variants.calculated_price,+variants.prices';
252
- fields = (options === null || options === void 0 ? void 0 : options.regionId) ? baseFields + pricingFields : baseFields;
253
- queryParams = {
254
- handle: handle,
255
- limit: 1,
256
- fields: fields,
257
- };
258
- // Add region_id for region-based pricing
259
- if (options === null || options === void 0 ? void 0 : options.regionId) {
260
- queryParams.region_id = options.regionId;
261
- }
262
- salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
263
- if (salesChannelId) {
264
- queryParams.sales_channel_id = [salesChannelId];
265
- }
266
- return [4 /*yield*/, this.sdk.store.product.list(queryParams)];
267
- case 1:
268
- products = (_a.sent()).products;
269
- if (!products || products.length === 0) {
270
- this.logger.debug('Product not found', { handle: handle });
271
- return [2 /*return*/, undefined];
272
- }
273
- transformedProduct = (0, transforms_1.transformProduct)(products[0], this.currencyCode);
274
- return [2 /*return*/, transformedProduct];
275
- }
276
- });
277
- }); }, 'getProduct', { handle: handle, regionId: options === null || options === void 0 ? void 0 : options.regionId })];
278
- case 2: return [2 /*return*/, _a.sent()];
279
- case 3:
280
- error_2 = _a.sent();
281
- throw new errors_1.ProviderAPIError("Failed to fetch product: ".concat(error_2.message), 'medusa', error_2.status);
282
- case 4: return [2 /*return*/];
283
- }
284
- });
285
- });
286
- };
287
- MedusaProvider.prototype.getProducts = function () {
288
- return __awaiter(this, arguments, void 0, function (options) {
289
- var error_3;
290
- var _this = this;
291
- if (options === void 0) { options = {}; }
292
- return __generator(this, function (_a) {
293
- switch (_a.label) {
294
- case 0:
295
- this.logger.debug('getProducts', options);
296
- _a.label = 1;
297
- case 1:
298
- _a.trys.push([1, 3, , 4]);
299
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
300
- var baseFields, pricingFields, fields, queryParams, salesChannelId, products;
301
- var _this = this;
302
- var _a;
303
- return __generator(this, function (_b) {
304
- switch (_b.label) {
305
- case 0:
306
- baseFields = '+variants,+variants.inventory_quantity,+options,+images,+tags';
307
- pricingFields = ',+variants.calculated_price,+variants.prices';
308
- fields = options.regionId ? baseFields + pricingFields : baseFields;
309
- queryParams = {
310
- q: options.query,
311
- order: options.sortKey,
312
- limit: (_a = options.first) !== null && _a !== void 0 ? _a : 100,
313
- offset: options.after ? parseInt(options.after, 10) : undefined,
314
- fields: fields,
315
- };
316
- // Add region_id for region-based pricing
317
- if (options.regionId) {
318
- queryParams.region_id = options.regionId;
319
- }
320
- salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
321
- if (salesChannelId) {
322
- queryParams.sales_channel_id = [salesChannelId];
323
- }
324
- return [4 /*yield*/, this.sdk.store.product.list(queryParams)];
325
- case 1:
326
- products = (_b.sent()).products;
327
- return [2 /*return*/, products.map(function (p) { return (0, transforms_1.transformProduct)(p, _this.currencyCode); })];
328
- }
329
- });
330
- }); }, 'getProducts', options)];
331
- case 2: return [2 /*return*/, _a.sent()];
332
- case 3:
333
- error_3 = _a.sent();
334
- // Enhanced error logging
335
- this.logger.error('getProducts error details', {
336
- message: error_3.message,
337
- status: error_3.status,
338
- type: error_3.type,
339
- code: error_3.code,
340
- stack: error_3.stack,
341
- fullError: JSON.stringify(error_3, null, 2),
342
- });
343
- throw new errors_1.ProviderAPIError("Failed to fetch products: ".concat(error_3.message || 'Unknown error'), 'medusa', error_3.status);
344
- case 4: return [2 /*return*/];
345
- }
346
- });
347
- });
348
- };
349
- MedusaProvider.prototype.getProductRecommendations = function (productId) {
350
- return __awaiter(this, void 0, void 0, function () {
351
- return __generator(this, function (_a) {
352
- this.logger.debug('getProductRecommendations', { productId: productId });
353
- // Medusa doesn't have built-in recommendations yet
354
- // Return empty array for now - can be extended with custom logic
355
- this.logger.warn('Product recommendations not yet implemented for Medusa');
356
- return [2 /*return*/, []];
357
- });
358
- });
359
- };
360
- // ============================================
361
- // Collection Operations
362
- // ============================================
363
- MedusaProvider.prototype.getCollection = function (handle) {
364
- return __awaiter(this, void 0, void 0, function () {
365
- var collections, error_4;
366
- return __generator(this, function (_a) {
367
- switch (_a.label) {
368
- case 0:
369
- this.logger.debug('getCollection', { handle: handle });
370
- _a.label = 1;
371
- case 1:
372
- _a.trys.push([1, 3, , 4]);
373
- return [4 /*yield*/, this.sdk.store.collection.list({
374
- handle: [handle],
375
- limit: 1,
376
- })];
377
- case 2:
378
- collections = (_a.sent()).collections;
379
- if (!collections || collections.length === 0) {
380
- this.logger.debug('Collection not found', { handle: handle });
381
- return [2 /*return*/, undefined];
382
- }
383
- return [2 /*return*/, (0, transforms_1.transformCollection)(collections[0])];
384
- case 3:
385
- error_4 = _a.sent();
386
- this.logger.error('Failed to fetch collection', { handle: handle, error: error_4.message });
387
- throw new errors_1.ProviderAPIError("Failed to fetch collection: ".concat(error_4.message), 'medusa', error_4.status);
388
- case 4: return [2 /*return*/];
389
- }
390
- });
391
- });
392
- };
393
- MedusaProvider.prototype.getCollections = function (options) {
394
- return __awaiter(this, void 0, void 0, function () {
395
- var limit, collections, result, q_1, error_5;
396
- return __generator(this, function (_a) {
397
- switch (_a.label) {
398
- case 0:
399
- this.logger.debug('getCollections', { options: options });
400
- _a.label = 1;
401
- case 1:
402
- _a.trys.push([1, 3, , 4]);
403
- limit = (options === null || options === void 0 ? void 0 : options.query) ? 1000 : ((options === null || options === void 0 ? void 0 : options.limit) || 100);
404
- return [4 /*yield*/, this.sdk.store.collection.list({
405
- limit: limit,
406
- })];
407
- case 2:
408
- collections = (_a.sent()).collections;
409
- result = collections.map(transforms_1.transformCollection);
410
- // Client-side search filtering (Medusa Store API lacks query param for collections)
411
- if (options === null || options === void 0 ? void 0 : options.query) {
412
- q_1 = options.query.toLowerCase();
413
- result = result.filter(function (c) {
414
- return c.title.toLowerCase().includes(q_1) ||
415
- c.handle.toLowerCase().includes(q_1);
416
- });
417
- }
418
- return [2 /*return*/, result];
419
- case 3:
420
- error_5 = _a.sent();
421
- this.logger.error('Failed to fetch collections', { error: error_5.message });
422
- throw new errors_1.ProviderAPIError("Failed to fetch collections: ".concat(error_5.message), 'medusa', error_5.status);
423
- case 4: return [2 /*return*/];
424
- }
425
- });
426
- });
427
- };
428
- MedusaProvider.prototype.getCollectionProducts = function (handle_1) {
429
- return __awaiter(this, arguments, void 0, function (handle, options) {
430
- var collection, collectionQueryParams, salesChannelId, products, error_6;
431
- var _this = this;
432
- var _a;
433
- if (options === void 0) { options = {}; }
434
- return __generator(this, function (_b) {
435
- switch (_b.label) {
436
- case 0:
437
- this.logger.debug('getCollectionProducts', { handle: handle, options: options });
438
- _b.label = 1;
439
- case 1:
440
- _b.trys.push([1, 4, , 5]);
441
- return [4 /*yield*/, this.getCollection(handle)];
442
- case 2:
443
- collection = _b.sent();
444
- if (!collection) {
445
- throw new errors_1.ResourceNotFoundError('Collection', handle);
446
- }
447
- collectionQueryParams = {
448
- collection_id: [collection.handle], // Medusa uses handle in queries
449
- order: options.sortKey,
450
- limit: (_a = options.first) !== null && _a !== void 0 ? _a : 100,
451
- offset: options.after ? parseInt(options.after, 10) : undefined,
452
- fields: '+variants,+variants.prices,+variants.calculated_prices,+variants.inventory_quantity,+options,+images,+tags',
453
- };
454
- salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
455
- if (salesChannelId) {
456
- collectionQueryParams.sales_channel_id = [salesChannelId];
457
- }
458
- return [4 /*yield*/, this.sdk.store.product.list(collectionQueryParams)];
459
- case 3:
460
- products = (_b.sent()).products;
461
- return [2 /*return*/, products.map(function (p) { return (0, transforms_1.transformProduct)(p, _this.currencyCode); })];
462
- case 4:
463
- error_6 = _b.sent();
464
- if (error_6 instanceof errors_1.ResourceNotFoundError)
465
- throw error_6;
466
- this.logger.error('Failed to fetch collection products', { handle: handle, error: error_6.message });
467
- throw new errors_1.ProviderAPIError("Failed to fetch collection products: ".concat(error_6.message), 'medusa', error_6.status);
468
- case 5: return [2 /*return*/];
469
- }
470
- });
471
- });
472
- };
473
- // ============================================
474
- // Category Operations
475
- // ============================================
476
- MedusaProvider.prototype.getCategory = function (idOrHandle) {
477
- return __awaiter(this, void 0, void 0, function () {
478
- var product_categories, error_7;
479
- return __generator(this, function (_a) {
480
- switch (_a.label) {
481
- case 0:
482
- this.logger.debug('getCategory', { idOrHandle: idOrHandle });
483
- _a.label = 1;
484
- case 1:
485
- _a.trys.push([1, 3, , 4]);
486
- return [4 /*yield*/, this.sdk.store.category.list({
487
- handle: [idOrHandle],
488
- limit: 1,
489
- })];
490
- case 2:
491
- product_categories = (_a.sent()).product_categories;
492
- if (!product_categories || product_categories.length === 0) {
493
- this.logger.debug('Category not found', { idOrHandle: idOrHandle });
494
- return [2 /*return*/, undefined];
495
- }
496
- return [2 /*return*/, (0, transforms_1.transformCategory)(product_categories[0])];
497
- case 3:
498
- error_7 = _a.sent();
499
- this.logger.error('Failed to fetch category', { idOrHandle: idOrHandle, error: error_7.message });
500
- throw new errors_1.ProviderAPIError("Failed to fetch category: ".concat(error_7.message), 'medusa', error_7.status);
501
- case 4: return [2 /*return*/];
502
- }
503
- });
504
- });
505
- };
506
- /**
507
- * Returns the set of product-category IDs that have at least one product
508
- * available in the given sales channel.
509
- *
510
- * Because Medusa's store/product-categories endpoint does not accept a
511
- * `sales_channel_id` filter, we derive the active category IDs by querying
512
- * store/products with the sales-channel scope and collecting the category
513
- * relations from the response. Pagination is handled internally so the
514
- * result is always complete regardless of catalog size.
515
- */
516
- MedusaProvider.prototype._getActiveCategoryIds = function (salesChannelId) {
517
- return __awaiter(this, void 0, void 0, function () {
518
- var categoryIds, limit, offset, products, _i, _a, product, _b, _c, cat;
519
- var _d;
520
- return __generator(this, function (_e) {
521
- switch (_e.label) {
522
- case 0:
523
- this.logger.debug('_getActiveCategoryIds', { salesChannelId: salesChannelId });
524
- categoryIds = new Set();
525
- limit = 500;
526
- offset = 0;
527
- _e.label = 1;
528
- case 1:
529
- if (!true) return [3 /*break*/, 3];
530
- return [4 /*yield*/, this.sdk.store.product.list({
531
- sales_channel_id: [salesChannelId],
532
- // Request only the category id relation to minimise payload size
533
- fields: '+categories.id',
534
- limit: limit,
535
- offset: offset,
536
- })];
537
- case 2:
538
- products = (_e.sent()).products;
539
- for (_i = 0, _a = products !== null && products !== void 0 ? products : []; _i < _a.length; _i++) {
540
- product = _a[_i];
541
- for (_b = 0, _c = (_d = product.categories) !== null && _d !== void 0 ? _d : []; _b < _c.length; _b++) {
542
- cat = _c[_b];
543
- if (cat === null || cat === void 0 ? void 0 : cat.id)
544
- categoryIds.add(cat.id);
545
- }
546
- }
547
- if (!products || products.length < limit)
548
- return [3 /*break*/, 3];
549
- offset += limit;
550
- return [3 /*break*/, 1];
551
- case 3:
552
- this.logger.debug('_getActiveCategoryIds result', { count: categoryIds.size });
553
- return [2 /*return*/, categoryIds];
554
- }
555
- });
556
- });
557
- };
558
- MedusaProvider.prototype.getCategories = function () {
559
- return __awaiter(this, arguments, void 0, function (options) {
560
- var customFetcher, limit, queryParams, product_categories, result, salesChannelId, activeCategoryIds_1, q_2, error_8;
561
- var _a, _b, _c;
562
- if (options === void 0) { options = {}; }
563
- return __generator(this, function (_d) {
564
- switch (_d.label) {
565
- case 0:
566
- this.logger.debug('getCategories', { options: options });
567
- customFetcher = options.customFetcher;
568
- // If custom fetcher provided, use it instead of default SDK logic
569
- if (customFetcher) {
570
- this.logger.debug('Using custom fetcher for categories');
571
- return [2 /*return*/, customFetcher(options)];
572
- }
573
- _d.label = 1;
574
- case 1:
575
- _d.trys.push([1, 5, , 6]);
576
- limit = options.query ? 1000 : ((_a = options.limit) !== null && _a !== void 0 ? _a : 100);
577
- queryParams = {
578
- limit: limit,
579
- include_descendants_tree: (_b = options.includeDescendants) !== null && _b !== void 0 ? _b : false,
580
- };
581
- if (options.parentCategoryId) {
582
- queryParams.parent_category_id = options.parentCategoryId;
583
- }
584
- return [4 /*yield*/, this.sdk.store.category.list(queryParams)];
585
- case 2:
586
- product_categories = (_d.sent()).product_categories;
587
- result = product_categories.map(transforms_1.transformCategory);
588
- salesChannelId = (_c = options.salesChannelId) !== null && _c !== void 0 ? _c : process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
589
- if (!salesChannelId) return [3 /*break*/, 4];
590
- return [4 /*yield*/, this._getActiveCategoryIds(salesChannelId)];
591
- case 3:
592
- activeCategoryIds_1 = _d.sent();
593
- result = result.filter(function (c) { return activeCategoryIds_1.has(c.id); });
594
- _d.label = 4;
595
- case 4:
596
- // Client-side search filtering
597
- if (options.query) {
598
- q_2 = options.query.toLowerCase();
599
- result = result.filter(function (c) {
600
- return c.name.toLowerCase().includes(q_2) || c.handle.toLowerCase().includes(q_2);
601
- });
602
- }
603
- return [2 /*return*/, result];
604
- case 5:
605
- error_8 = _d.sent();
606
- this.logger.error('Failed to fetch categories', { error: error_8.message });
607
- throw new errors_1.ProviderAPIError("Failed to fetch categories: ".concat(error_8.message), 'medusa', error_8.status);
608
- case 6: return [2 /*return*/];
609
- }
610
- });
611
- });
612
- };
613
- MedusaProvider.prototype.getCategoryProducts = function (handle_1) {
614
- return __awaiter(this, arguments, void 0, function (handle, options) {
615
- var category, categoryQueryParams, salesChannelId, products, error_9;
616
- var _this = this;
617
- var _a;
618
- if (options === void 0) { options = {}; }
619
- return __generator(this, function (_b) {
620
- switch (_b.label) {
621
- case 0:
622
- this.logger.debug('getCategoryProducts', { handle: handle, options: options });
623
- _b.label = 1;
624
- case 1:
625
- _b.trys.push([1, 4, , 5]);
626
- return [4 /*yield*/, this.getCategory(handle)];
627
- case 2:
628
- category = _b.sent();
629
- if (!category) {
630
- throw new errors_1.ResourceNotFoundError('Category', handle);
631
- }
632
- categoryQueryParams = {
633
- category_id: [category.id],
634
- order: options.sortKey,
635
- limit: (_a = options.first) !== null && _a !== void 0 ? _a : 100,
636
- offset: options.after ? parseInt(options.after, 10) : undefined,
637
- fields: '+variants,+variants.prices,+variants.calculated_prices,+variants.inventory_quantity,+options,+images,+tags',
638
- };
639
- salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
640
- if (salesChannelId) {
641
- categoryQueryParams.sales_channel_id = [salesChannelId];
642
- }
643
- return [4 /*yield*/, this.sdk.store.product.list(categoryQueryParams)];
644
- case 3:
645
- products = (_b.sent()).products;
646
- return [2 /*return*/, products.map(function (p) { return (0, transforms_1.transformProduct)(p, _this.currencyCode); })];
647
- case 4:
648
- error_9 = _b.sent();
649
- if (error_9 instanceof errors_1.ResourceNotFoundError)
650
- throw error_9;
651
- this.logger.error('Failed to fetch category products', { handle: handle, error: error_9.message });
652
- throw new errors_1.ProviderAPIError("Failed to fetch category products: ".concat(error_9.message), 'medusa', error_9.status);
653
- case 5: return [2 /*return*/];
654
- }
655
- });
656
- });
657
- };
658
- // ============================================
659
- // Cart Operations
660
- // ============================================
661
- MedusaProvider.prototype.createCart = function (options) {
662
- return __awaiter(this, void 0, void 0, function () {
663
- var createPayload, cart, error_10, errorMessage;
664
- return __generator(this, function (_a) {
665
- switch (_a.label) {
666
- case 0:
667
- this.logger.debug('createCart', { regionId: options === null || options === void 0 ? void 0 : options.regionId });
668
- _a.label = 1;
669
- case 1:
670
- _a.trys.push([1, 3, , 4]);
671
- createPayload = {};
672
- // If a regionId is provided, prefer letting Medusa resolve the currency
673
- // from the region. Do NOT set `currency_code` when `region_id` is present,
674
- // otherwise Medusa may use the provided currency and ignore the region.
675
- if (options === null || options === void 0 ? void 0 : options.regionId) {
676
- createPayload.region_id = options.regionId;
677
- }
678
- else {
679
- createPayload.currency_code = this.currencyCode.toLowerCase();
680
- }
681
- return [4 /*yield*/, this.sdk.store.cart.create(createPayload)];
682
- case 2:
683
- cart = (_a.sent()).cart;
684
- return [2 /*return*/, (0, transforms_1.transformCart)(cart)];
685
- case 3:
686
- error_10 = _a.sent();
687
- errorMessage = (0, errors_1.extractErrorMessage)(error_10);
688
- this.logger.error('Failed to create cart', { error: errorMessage });
689
- throw new errors_1.ProviderAPIError("Failed to create cart: ".concat(errorMessage), 'medusa', (error_10 === null || error_10 === void 0 ? void 0 : error_10.status) || (error_10 === null || error_10 === void 0 ? void 0 : error_10.statusCode));
690
- case 4: return [2 /*return*/];
691
- }
692
- });
693
- });
694
- };
695
- MedusaProvider.prototype.getCart = function (cartId) {
696
- return __awaiter(this, void 0, void 0, function () {
697
- var cart, error_11, status_1, errorMessage;
698
- return __generator(this, function (_a) {
699
- switch (_a.label) {
700
- case 0:
701
- this.logger.debug('getCart', { cartId: cartId });
702
- _a.label = 1;
703
- case 1:
704
- _a.trys.push([1, 3, , 4]);
705
- return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
706
- case 2:
707
- cart = _a.sent();
708
- if (!cart) {
709
- this.logger.debug('Cart not found', { cartId: cartId });
710
- return [2 /*return*/, undefined];
711
- }
712
- return [2 /*return*/, (0, transforms_1.transformCart)(cart)];
713
- case 3:
714
- error_11 = _a.sent();
715
- status_1 = (error_11 === null || error_11 === void 0 ? void 0 : error_11.status) || (error_11 === null || error_11 === void 0 ? void 0 : error_11.statusCode);
716
- if (status_1 === 404) {
717
- this.logger.debug('Cart not found', { cartId: cartId });
718
- return [2 /*return*/, undefined];
719
- }
720
- errorMessage = (0, errors_1.extractErrorMessage)(error_11);
721
- this.logger.error('Failed to fetch cart', { cartId: cartId, error: errorMessage });
722
- throw new errors_1.ProviderAPIError("Failed to fetch cart: ".concat(errorMessage), 'medusa', status_1);
723
- case 4: return [2 /*return*/];
724
- }
725
- });
726
- });
727
- };
728
- MedusaProvider.prototype.addToCart = function (cartId, lines) {
729
- return __awaiter(this, void 0, void 0, function () {
730
- var retrieveCtx, retrieveResult, backendCart_1, _loop_2, this_2, _i, lines_1, line, cart, error_12, errorMessage, errorDetails, err, status_2, userMessage;
731
- var _this = this;
732
- var _a, _b;
733
- return __generator(this, function (_c) {
734
- switch (_c.label) {
735
- case 0:
736
- this.logger.debug('addToCart', { cartId: cartId, lines: lines });
737
- _c.label = 1;
738
- case 1:
739
- _c.trys.push([1, 8, , 9]);
740
- retrieveCtx = { cartId: cartId };
741
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
742
- return [2 /*return*/, this.sdk.store.cart.retrieve(cartId)];
743
- }); }); }, 'retrieveCartBeforeAdd', retrieveCtx)];
744
- case 2:
745
- retrieveResult = _c.sent();
746
- console.log('retrieveResult =', JSON.stringify(retrieveResult, null, 2));
747
- backendCart_1 = retrieveResult === null || retrieveResult === void 0 ? void 0 : retrieveResult.cart;
748
- if (!backendCart_1) {
749
- this.logger.warn('Cart not found before addToCart', { cartId: cartId });
750
- throw new errors_1.ProviderAPIError('Cart not found. Please refresh and try again.', 'medusa', 404);
751
- }
752
- console.log('backendCart =', JSON.stringify(backendCart_1, null, 2));
753
- if (!backendCart_1.region_id) {
754
- this.logger.warn('Attempted to add item to cart with no region_id', { cartId: cartId });
755
- throw new errors_1.ProviderAPIError('Cart does not have a region set. Please select a region or recreate your cart and try again.', 'medusa', 400);
756
- }
757
- _loop_2 = function (line) {
758
- var variantCheckParams, salesChannelId, plist, products, foundVariant, _d, products_1, p, v, variant, hasPriceForRegion, calcCurrency, cartCurrency, prices, prices, variantErr_1, result;
759
- return __generator(this, function (_e) {
760
- switch (_e.label) {
761
- case 0:
762
- this_2.logger.debug('createLineItem payload', {
763
- cartId: cartId,
764
- variant_id: line.merchandiseId,
765
- quantity: line.quantity,
766
- cartRegion: backendCart_1.region_id,
767
- });
768
- _e.label = 1;
769
- case 1:
770
- _e.trys.push([1, 3, , 4]);
771
- variantCheckParams = {
772
- limit: 200,
773
- fields: '+variants,+variants.calculated_price,+variants.prices,+variants.money_amounts',
774
- region_id: backendCart_1.region_id,
775
- };
776
- salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
777
- if (salesChannelId) {
778
- variantCheckParams.sales_channel_id = [salesChannelId];
779
- }
780
- return [4 /*yield*/, this_2.sdk.store.product.list(variantCheckParams)];
781
- case 2:
782
- plist = _e.sent();
783
- products = (plist === null || plist === void 0 ? void 0 : plist.products) || [];
784
- foundVariant = void 0;
785
- for (_d = 0, products_1 = products; _d < products_1.length; _d++) {
786
- p = products_1[_d];
787
- if (Array.isArray(p.variants)) {
788
- v = p.variants.find(function (vv) { return vv.id === line.merchandiseId; });
789
- if (v) {
790
- foundVariant = v;
791
- break;
792
- }
793
- }
794
- }
795
- if (!foundVariant) {
796
- this_2.logger.warn('Variant not found in product.list for pricing check', {
797
- variantId: line.merchandiseId,
798
- cartRegion: backendCart_1.region_id,
799
- });
800
- throw new errors_1.ProviderAPIError('Product or variant not found. Please refresh and try again.', 'medusa', 404);
801
- }
802
- console.log('Found Variant:', JSON.stringify(foundVariant, null, 2));
803
- variant = foundVariant;
804
- hasPriceForRegion = false;
805
- if ((variant === null || variant === void 0 ? void 0 : variant.calculated_price) &&
806
- ((_a = variant.calculated_price.calculated_amount) !== null && _a !== void 0 ? _a : null) !== null) {
807
- calcCurrency = (variant.calculated_price.currency_code || '').toLowerCase();
808
- cartCurrency = (backendCart_1.currency_code ||
809
- this_2.currencyCode ||
810
- '').toLowerCase();
811
- console.log('calcCurrency =', calcCurrency);
812
- console.log('cartCurrency =', cartCurrency);
813
- console.log('this.currencyCode =', this_2.currencyCode);
814
- if (!cartCurrency ||
815
- calcCurrency === cartCurrency ||
816
- calcCurrency === this_2.currencyCode.toLowerCase()) {
817
- hasPriceForRegion = true;
818
- }
819
- }
820
- if (!hasPriceForRegion) {
821
- prices = (variant === null || variant === void 0 ? void 0 : variant.prices) || (variant === null || variant === void 0 ? void 0 : variant.money_amounts) || [];
822
- hasPriceForRegion =
823
- Array.isArray(prices) &&
824
- prices.some(function (p) {
825
- return (p.region_id === backendCart_1.region_id ||
826
- p.currency_code === backendCart_1.currency_code ||
827
- p.currency_code === _this.currencyCode ||
828
- p.currency === _this.currencyCode);
829
- });
830
- }
831
- if (!hasPriceForRegion) {
832
- prices = (variant === null || variant === void 0 ? void 0 : variant.prices) || (variant === null || variant === void 0 ? void 0 : variant.money_amounts) || [];
833
- this_2.logger.warn('Variant missing price for cart region (product.list)', {
834
- variantId: line.merchandiseId,
835
- cartRegion: backendCart_1.region_id,
836
- prices: prices,
837
- });
838
- throw new errors_1.ProviderAPIError('This product does not have pricing configured for your selected region. Please try a different region or contact support.', 'medusa', 400);
839
- }
840
- return [3 /*break*/, 4];
841
- case 3:
842
- variantErr_1 = _e.sent();
843
- this_2.logger.error('Variant price check failed', {
844
- variantId: line.merchandiseId,
845
- error: (0, errors_1.extractErrorMessage)(variantErr_1),
846
- });
847
- // Surface a clear error to avoid a 500 from backend when possible
848
- throw new errors_1.ProviderAPIError('Unable to verify variant pricing before adding to cart. Please try again later.', 'medusa', 500);
849
- case 4: return [4 /*yield*/, this_2.sdk.store.cart.createLineItem(cartId, {
850
- variant_id: line.merchandiseId,
851
- quantity: line.quantity,
852
- })];
853
- case 5:
854
- result = _e.sent();
855
- void result;
856
- return [2 /*return*/];
857
- }
858
- });
859
- };
860
- this_2 = this;
861
- _i = 0, lines_1 = lines;
862
- _c.label = 3;
863
- case 3:
864
- if (!(_i < lines_1.length)) return [3 /*break*/, 6];
865
- line = lines_1[_i];
866
- return [5 /*yield**/, _loop_2(line)];
867
- case 4:
868
- _c.sent();
869
- _c.label = 5;
870
- case 5:
871
- _i++;
872
- return [3 /*break*/, 3];
873
- case 6: return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
874
- case 7:
875
- cart = _c.sent();
876
- return [2 /*return*/, (0, transforms_1.transformCart)(cart)];
877
- case 8:
878
- error_12 = _c.sent();
879
- errorMessage = (0, errors_1.extractErrorMessage)(error_12);
880
- errorDetails = { cartId: cartId, lines: lines, message: errorMessage };
881
- if (typeof error_12 === 'object' && error_12 !== null) {
882
- err = error_12;
883
- if (err.status)
884
- errorDetails.status = err.status;
885
- if (err.statusCode)
886
- errorDetails.statusCode = err.statusCode;
887
- if (err.code)
888
- errorDetails.code = err.code;
889
- // If SDK exposes response body, include it for diagnostics
890
- if (err.response) {
891
- errorDetails.backendResponse = (_b = err.response.data) !== null && _b !== void 0 ? _b : err.response;
892
- }
893
- // Fallback: include entire error for logs
894
- try {
895
- errorDetails.fullError = JSON.stringify(err, Object.getOwnPropertyNames(err));
896
- }
897
- catch (e) {
898
- // ignore stringify errors
899
- }
900
- }
901
- this.logger.error('Failed to add to cart', errorDetails);
902
- status_2 = (error_12 === null || error_12 === void 0 ? void 0 : error_12.status) || (error_12 === null || error_12 === void 0 ? void 0 : error_12.statusCode);
903
- userMessage = errorMessage;
904
- if (status_2 === 500) {
905
- userMessage =
906
- 'Unable to add product to cart. This product may not have pricing configured for your selected region. Please try selecting a different region or contact support.';
907
- }
908
- else if (status_2 === 404) {
909
- userMessage = 'Product or cart not found. Please refresh the page and try again.';
910
- }
911
- else if (status_2 === 400 || status_2 === 422) {
912
- userMessage = 'Invalid product configuration. This product may be unavailable.';
913
- }
914
- throw new errors_1.ProviderAPIError(userMessage, 'medusa', status_2);
915
- case 9: return [2 /*return*/];
916
- }
917
- });
918
- });
919
- };
920
- MedusaProvider.prototype.removeFromCart = function (cartId, lineIds) {
921
- return __awaiter(this, void 0, void 0, function () {
922
- var _i, lineIds_1, lineId, cart, error_13, errorMessage;
923
- return __generator(this, function (_a) {
924
- switch (_a.label) {
925
- case 0:
926
- this.logger.debug('removeFromCart', { cartId: cartId, lineIds: lineIds });
927
- _a.label = 1;
928
- case 1:
929
- _a.trys.push([1, 7, , 8]);
930
- _i = 0, lineIds_1 = lineIds;
931
- _a.label = 2;
932
- case 2:
933
- if (!(_i < lineIds_1.length)) return [3 /*break*/, 5];
934
- lineId = lineIds_1[_i];
935
- return [4 /*yield*/, this.sdk.store.cart.deleteLineItem(cartId, lineId)];
936
- case 3:
937
- _a.sent();
938
- _a.label = 4;
939
- case 4:
940
- _i++;
941
- return [3 /*break*/, 2];
942
- case 5: return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
943
- case 6:
944
- cart = _a.sent();
945
- return [2 /*return*/, (0, transforms_1.transformCart)(cart)];
946
- case 7:
947
- error_13 = _a.sent();
948
- errorMessage = (0, errors_1.extractErrorMessage)(error_13);
949
- this.logger.error('Failed to remove from cart', { cartId: cartId, lineIds: lineIds, error: errorMessage });
950
- throw new errors_1.ProviderAPIError("Failed to remove from cart: ".concat(errorMessage), 'medusa', (error_13 === null || error_13 === void 0 ? void 0 : error_13.status) || (error_13 === null || error_13 === void 0 ? void 0 : error_13.statusCode));
951
- case 8: return [2 /*return*/];
952
- }
953
- });
954
- });
955
- };
956
- MedusaProvider.prototype.updateCart = function (cartId, lines) {
957
- return __awaiter(this, void 0, void 0, function () {
958
- var _i, lines_2, line, cart, error_14, errorMessage;
959
- return __generator(this, function (_a) {
960
- switch (_a.label) {
961
- case 0:
962
- this.logger.debug('updateCart', { cartId: cartId, lines: lines });
963
- _a.label = 1;
964
- case 1:
965
- _a.trys.push([1, 7, , 8]);
966
- _i = 0, lines_2 = lines;
967
- _a.label = 2;
968
- case 2:
969
- if (!(_i < lines_2.length)) return [3 /*break*/, 5];
970
- line = lines_2[_i];
971
- return [4 /*yield*/, this.sdk.store.cart.updateLineItem(cartId, line.id, {
972
- quantity: line.quantity,
973
- })];
974
- case 3:
975
- _a.sent();
976
- _a.label = 4;
977
- case 4:
978
- _i++;
979
- return [3 /*break*/, 2];
980
- case 5: return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
981
- case 6:
982
- cart = _a.sent();
983
- return [2 /*return*/, (0, transforms_1.transformCart)(cart)];
984
- case 7:
985
- error_14 = _a.sent();
986
- errorMessage = (0, errors_1.extractErrorMessage)(error_14);
987
- this.logger.error('Failed to update cart', { cartId: cartId, error: errorMessage });
988
- throw new errors_1.ProviderAPIError("Failed to update cart: ".concat(errorMessage), 'medusa', (error_14 === null || error_14 === void 0 ? void 0 : error_14.status) || (error_14 === null || error_14 === void 0 ? void 0 : error_14.statusCode));
989
- case 8: return [2 /*return*/];
990
- }
991
- });
992
- });
993
- };
994
- /**
995
- * Get available regions from Medusa
996
- * Returns region information including id, name, and currency
997
- */
998
- MedusaProvider.prototype.getRegions = function () {
999
- return __awaiter(this, void 0, void 0, function () {
1000
- var regions, error_15, errorMessage;
1001
- return __generator(this, function (_a) {
1002
- switch (_a.label) {
1003
- case 0:
1004
- this.logger.debug('getRegions');
1005
- _a.label = 1;
1006
- case 1:
1007
- _a.trys.push([1, 3, , 4]);
1008
- return [4 /*yield*/, this.sdk.store.region.list()];
1009
- case 2:
1010
- regions = (_a.sent()).regions;
1011
- return [2 /*return*/, regions.map(function (region) { return ({
1012
- id: region.id,
1013
- name: region.name,
1014
- currency_code: region.currency_code,
1015
- countries: region.countries,
1016
- }); })];
1017
- case 3:
1018
- error_15 = _a.sent();
1019
- errorMessage = (0, errors_1.extractErrorMessage)(error_15);
1020
- this.logger.error('Failed to fetch regions', { error: errorMessage });
1021
- throw new errors_1.ProviderAPIError("Failed to fetch regions: ".concat(errorMessage), 'medusa', (error_15 === null || error_15 === void 0 ? void 0 : error_15.status) || (error_15 === null || error_15 === void 0 ? void 0 : error_15.statusCode));
1022
- case 4: return [2 /*return*/];
1023
- }
1024
- });
1025
- });
1026
- };
1027
- // ============================================
1028
- // Payment Operations
1029
- // ============================================
1030
- // ============================================
1031
- // Order Operations
1032
- // ============================================
1033
- /**
1034
- * Get all orders for a customer (storefront).
1035
- *
1036
- * Note: This retrieves orders from the storefront API (store.order.list),
1037
- * which returns orders only for the authenticated customer in the JWT.
1038
- *
1039
- * @param options - Order query options (supports callbacks for custom backends)
1040
- * @returns Array of orders for the authenticated customer
1041
- *
1042
- * @example
1043
- * ```typescript
1044
- * const orders = await provider.getOrders();
1045
- * console.log(`Found ${orders.length} orders`);
1046
- * ```
1047
- */
1048
- MedusaProvider.prototype.getOrders = function () {
1049
- return __awaiter(this, arguments, void 0, function (options) {
1050
- var customFetcher, salesChannelId, result, orders, transformed, channelId, scoped, error_16, status_3, errorMessage;
1051
- var _this = this;
1052
- var _a;
1053
- if (options === void 0) { options = {}; }
1054
- return __generator(this, function (_b) {
1055
- switch (_b.label) {
1056
- case 0:
1057
- customFetcher = options.customFetcher, salesChannelId = options.salesChannelId;
1058
- // If custom fetcher provided, use it instead of default SDK logic
1059
- if (customFetcher) {
1060
- this.logger.debug('Using custom fetcher for orders');
1061
- return [2 /*return*/, customFetcher(options)];
1062
- }
1063
- this.logger.info('Getting orders for authenticated customer');
1064
- _b.label = 1;
1065
- case 1:
1066
- _b.trys.push([1, 3, , 4]);
1067
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1068
- return __generator(this, function (_a) {
1069
- return [2 /*return*/, this.sdk.store.order.list({
1070
- // Medusa v2 JS-SDK automatically includes authorization header if JWT is present
1071
- fields: '+items,+items.variant,+items.variant.product,+shipping_address,+billing_address,+customer',
1072
- })];
1073
- });
1074
- }); }, 'getOrders', {})];
1075
- case 2:
1076
- result = _b.sent();
1077
- orders = (_a = result.orders) !== null && _a !== void 0 ? _a : [];
1078
- this.logger.debug("Found ".concat(orders.length, " orders for customer"));
1079
- transformed = orders.map(function (order) { return (0, transforms_1.transformOrder)(order); });
1080
- channelId = salesChannelId !== null && salesChannelId !== void 0 ? salesChannelId : process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
1081
- if (channelId) {
1082
- scoped = (0, metadata_1.filterByChannel)(transformed, channelId);
1083
- this.logger.debug("Channel scoping: ".concat(scoped.length, "/").concat(transformed.length, " orders match channel ").concat(channelId));
1084
- return [2 /*return*/, scoped];
1085
- }
1086
- return [2 /*return*/, transformed];
1087
- case 3:
1088
- error_16 = _b.sent();
1089
- status_3 = (error_16 === null || error_16 === void 0 ? void 0 : error_16.status) || (error_16 === null || error_16 === void 0 ? void 0 : error_16.statusCode);
1090
- errorMessage = (0, errors_1.extractErrorMessage)(error_16);
1091
- this.logger.error('Error getting orders', { error: errorMessage });
1092
- throw new errors_1.ProviderAPIError("Failed to fetch orders: ".concat(errorMessage), 'medusa', status_3);
1093
- case 4: return [2 /*return*/];
1094
- }
1095
- });
1096
- });
1097
- };
1098
- /**
1099
- * Get a single order by ID
1100
- *
1101
- * @param orderId - Order ID
1102
- * @returns Order or undefined if not found
1103
- *
1104
- * @example
1105
- * ```typescript
1106
- * const order = await provider.getOrder('order_123');
1107
- * if (order) {
1108
- * console.log(`Order ${order.orderNumber} - ${order.status}`);
1109
- * }
1110
- * ```
1111
- */
1112
- MedusaProvider.prototype.getOrder = function (orderId) {
1113
- return __awaiter(this, void 0, void 0, function () {
1114
- var order, error_17, status_4, errorMessage;
1115
- var _this = this;
1116
- var _a;
1117
- return __generator(this, function (_b) {
1118
- switch (_b.label) {
1119
- case 0:
1120
- this.logger.info('Getting order', orderId);
1121
- if (!orderId) {
1122
- throw new errors_1.ProviderAPIError('Order ID is required', 'medusa');
1123
- }
1124
- _b.label = 1;
1125
- case 1:
1126
- _b.trys.push([1, 3, , 4]);
1127
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1128
- return __generator(this, function (_a) {
1129
- return [2 /*return*/, this.sdk.store.order.retrieve(orderId, {
1130
- fields: '+items,+items.variant,+items.variant.product,+shipping_address,+billing_address,+customer',
1131
- })];
1132
- });
1133
- }); }, 'getOrder', { orderId: orderId })];
1134
- case 2:
1135
- order = (_b.sent()).order;
1136
- if (!order) {
1137
- this.logger.debug("Order not found: ".concat(orderId));
1138
- return [2 /*return*/, undefined];
1139
- }
1140
- this.logger.debug("Retrieved order: ".concat((_a = order.display_id) !== null && _a !== void 0 ? _a : orderId));
1141
- return [2 /*return*/, (0, transforms_1.transformOrder)(order)];
1142
- case 3:
1143
- error_17 = _b.sent();
1144
- status_4 = (error_17 === null || error_17 === void 0 ? void 0 : error_17.status) || (error_17 === null || error_17 === void 0 ? void 0 : error_17.statusCode);
1145
- if (status_4 === 404) {
1146
- this.logger.debug("Order not found: ".concat(orderId));
1147
- return [2 /*return*/, undefined];
1148
- }
1149
- errorMessage = (0, errors_1.extractErrorMessage)(error_17);
1150
- this.logger.error('Failed to fetch order', { orderId: orderId, error: errorMessage });
1151
- throw new errors_1.ProviderAPIError("Failed to fetch order: ".concat(errorMessage), 'medusa', status_4);
1152
- case 4: return [2 /*return*/];
1153
- }
1154
- });
1155
- });
1156
- };
1157
- // ============================================
1158
- // Customer Operations
1159
- // ============================================
1160
- /**
1161
- * List customers with optional filtering and pagination.
1162
- *
1163
- * Uses the Medusa admin API — requires admin-level JWT.
1164
- *
1165
- * @param options - Query options (search, sort, pagination)
1166
- * @returns Array of customers
1167
- *
1168
- * @example
1169
- * ```typescript
1170
- * const customers = await provider.getCustomers({ search: 'john', limit: 20, offset: 0 });
1171
- * ```
1172
- */
1173
- MedusaProvider.prototype.getCustomers = function () {
1174
- return __awaiter(this, arguments, void 0, function (options) {
1175
- var search, _a, limit, _b, offset, _c, sortBy, salesChannelId, customFetcher, orderMap, filters_1, result, customers, transformed, error_18, status_5, errorMessage;
1176
- var _this = this;
1177
- var _d;
1178
- if (options === void 0) { options = {}; }
1179
- return __generator(this, function (_e) {
1180
- switch (_e.label) {
1181
- case 0:
1182
- this.logger.info('Getting customers', options);
1183
- search = options.search, _a = options.limit, limit = _a === void 0 ? 20 : _a, _b = options.offset, offset = _b === void 0 ? 0 : _b, _c = options.sortBy, sortBy = _c === void 0 ? 'createdAt' : _c, salesChannelId = options.salesChannelId, customFetcher = options.customFetcher;
1184
- // If custom fetcher provided, use it instead of default SDK logic
1185
- if (customFetcher) {
1186
- this.logger.debug('Using custom fetcher for customers');
1187
- return [2 /*return*/, customFetcher(options)];
1188
- }
1189
- orderMap = {
1190
- createdAt: 'created_at',
1191
- email: 'email',
1192
- firstName: 'first_name',
1193
- };
1194
- _e.label = 1;
1195
- case 1:
1196
- _e.trys.push([1, 3, , 4]);
1197
- filters_1 = {};
1198
- if (salesChannelId) {
1199
- filters_1.metadata = { sales_channel_id: salesChannelId };
1200
- this.logger.debug("Filtering customers by salesChannelId: ".concat(salesChannelId));
1201
- }
1202
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1203
- var _a;
1204
- return __generator(this, function (_b) {
1205
- return [2 /*return*/, this.sdk.admin.customer.list(__assign({ q: search || undefined, limit: limit, offset: offset, order: (_a = orderMap[sortBy]) !== null && _a !== void 0 ? _a : 'created_at' }, (Object.keys(filters_1).length > 0 && { filters: filters_1 })))];
1206
- });
1207
- }); }, 'getCustomers', { search: search, limit: limit, offset: offset, salesChannelId: salesChannelId })];
1208
- case 2:
1209
- result = _e.sent();
1210
- customers = (_d = result === null || result === void 0 ? void 0 : result.customers) !== null && _d !== void 0 ? _d : [];
1211
- this.logger.debug("Found ".concat(customers.length, " customers"));
1212
- transformed = customers.map(function (c) { return (0, transforms_1.transformCustomer)(c); });
1213
- return [2 /*return*/, transformed];
1214
- case 3:
1215
- error_18 = _e.sent();
1216
- status_5 = (error_18 === null || error_18 === void 0 ? void 0 : error_18.status) || (error_18 === null || error_18 === void 0 ? void 0 : error_18.statusCode);
1217
- errorMessage = (0, errors_1.extractErrorMessage)(error_18);
1218
- this.logger.error('Error getting customers', { error: errorMessage });
1219
- throw new errors_1.ProviderAPIError("Failed to fetch customers: ".concat(errorMessage), 'medusa', status_5);
1220
- case 4: return [2 /*return*/];
1221
- }
1222
- });
1223
- });
1224
- };
1225
- /**
1226
- * Get a single customer by ID.
1227
- *
1228
- * Uses the Medusa admin API.
1229
- *
1230
- * @param customerId - Customer ID
1231
- * @returns Customer or undefined if not found
1232
- */
1233
- MedusaProvider.prototype.getCustomer = function (customerId) {
1234
- return __awaiter(this, void 0, void 0, function () {
1235
- var result, error_19, status_6, errorMessage;
1236
- var _this = this;
1237
- return __generator(this, function (_a) {
1238
- switch (_a.label) {
1239
- case 0:
1240
- this.logger.info('Getting customer', customerId);
1241
- if (!customerId) {
1242
- throw new errors_1.ProviderAPIError('Customer ID is required', 'medusa');
1243
- }
1244
- _a.label = 1;
1245
- case 1:
1246
- _a.trys.push([1, 3, , 4]);
1247
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
1248
- return [2 /*return*/, this.sdk.admin.customer.retrieve(customerId)];
1249
- }); }); }, 'getCustomer', { customerId: customerId })];
1250
- case 2:
1251
- result = _a.sent();
1252
- if (!(result === null || result === void 0 ? void 0 : result.customer)) {
1253
- return [2 /*return*/, undefined];
1254
- }
1255
- return [2 /*return*/, (0, transforms_1.transformCustomer)(result.customer)];
1256
- case 3:
1257
- error_19 = _a.sent();
1258
- status_6 = (error_19 === null || error_19 === void 0 ? void 0 : error_19.status) || (error_19 === null || error_19 === void 0 ? void 0 : error_19.statusCode);
1259
- if (status_6 === 404)
1260
- return [2 /*return*/, undefined];
1261
- errorMessage = (0, errors_1.extractErrorMessage)(error_19);
1262
- this.logger.error('Failed to fetch customer', { customerId: customerId, error: errorMessage });
1263
- throw new errors_1.ProviderAPIError("Failed to fetch customer: ".concat(errorMessage), 'medusa', status_6);
1264
- case 4: return [2 /*return*/];
1265
- }
1266
- });
1267
- });
1268
- };
1269
- /**
1270
- * Update customer information.
1271
- *
1272
- * Uses the Medusa admin API.
1273
- *
1274
- * @param customerId - Customer ID
1275
- * @param data - Fields to update
1276
- * @returns Updated customer
1277
- */
1278
- MedusaProvider.prototype.updateCustomer = function (customerId, data) {
1279
- return __awaiter(this, void 0, void 0, function () {
1280
- var payload, result, error_20, status_7, errorMessage;
1281
- var _this = this;
1282
- var _a;
1283
- return __generator(this, function (_b) {
1284
- switch (_b.label) {
1285
- case 0:
1286
- this.logger.info('Updating customer', { customerId: customerId, fields: Object.keys(data) });
1287
- if (!customerId) {
1288
- throw new errors_1.ProviderAPIError('Customer ID is required', 'medusa');
1289
- }
1290
- payload = {};
1291
- if (data.firstName !== undefined)
1292
- payload.first_name = data.firstName;
1293
- if (data.lastName !== undefined)
1294
- payload.last_name = data.lastName;
1295
- if (data.phone !== undefined)
1296
- payload.phone = (_a = data.phone) !== null && _a !== void 0 ? _a : null;
1297
- if (data.email !== undefined)
1298
- payload.email = data.email;
1299
- if (data.metadata !== undefined)
1300
- payload.metadata = data.metadata;
1301
- _b.label = 1;
1302
- case 1:
1303
- _b.trys.push([1, 3, , 4]);
1304
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
1305
- return [2 /*return*/, this.sdk.admin.customer.update(customerId, payload)];
1306
- }); }); }, 'updateCustomer', { customerId: customerId })];
1307
- case 2:
1308
- result = _b.sent();
1309
- return [2 /*return*/, (0, transforms_1.transformCustomer)(result.customer)];
1310
- case 3:
1311
- error_20 = _b.sent();
1312
- status_7 = (error_20 === null || error_20 === void 0 ? void 0 : error_20.status) || (error_20 === null || error_20 === void 0 ? void 0 : error_20.statusCode);
1313
- errorMessage = (0, errors_1.extractErrorMessage)(error_20);
1314
- this.logger.error('Failed to update customer', { customerId: customerId, error: errorMessage });
1315
- throw new errors_1.ProviderAPIError("Failed to update customer: ".concat(errorMessage), 'medusa', status_7);
1316
- case 4: return [2 /*return*/];
1317
- }
1318
- });
1319
- });
1320
- };
1321
- /**
1322
- * Get orders placed by a specific customer (admin view).
1323
- *
1324
- * @param customerId - Customer ID
1325
- * @param limit - Max number of orders (default: 10)
1326
- * @returns Array of orders
1327
- */
1328
- MedusaProvider.prototype.getCustomerOrders = function (customerId_1) {
1329
- return __awaiter(this, arguments, void 0, function (customerId, limit) {
1330
- var result, orders, transformed, channelId, scoped, error_21, status_8, errorMessage;
1331
- var _this = this;
1332
- var _a;
1333
- if (limit === void 0) { limit = 10; }
1334
- return __generator(this, function (_b) {
1335
- switch (_b.label) {
1336
- case 0:
1337
- this.logger.info('Getting orders for customer (admin)', { customerId: customerId, limit: limit });
1338
- if (!customerId) {
1339
- throw new errors_1.ProviderAPIError('Customer ID is required', 'medusa');
1340
- }
1341
- _b.label = 1;
1342
- case 1:
1343
- _b.trys.push([1, 3, , 4]);
1344
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1345
- return __generator(this, function (_a) {
1346
- return [2 /*return*/, this.sdk.admin.order.list({
1347
- customer_id: customerId,
1348
- limit: limit,
1349
- order: '-created_at',
1350
- fields: '+items,+items.variant,+items.variant.product,+shipping_address',
1351
- })];
1352
- });
1353
- }); }, 'getCustomerOrders', { customerId: customerId })];
1354
- case 2:
1355
- result = _b.sent();
1356
- orders = (_a = result === null || result === void 0 ? void 0 : result.orders) !== null && _a !== void 0 ? _a : [];
1357
- this.logger.debug("Found ".concat(orders.length, " orders for customer ").concat(customerId));
1358
- transformed = orders.map(function (o) { return (0, transforms_1.transformOrder)(o); });
1359
- channelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
1360
- if (channelId) {
1361
- scoped = (0, metadata_1.filterByChannel)(transformed, channelId);
1362
- this.logger.debug("Channel scoping: ".concat(scoped.length, "/").concat(transformed.length, " orders match channel ").concat(channelId));
1363
- return [2 /*return*/, scoped];
1364
- }
1365
- return [2 /*return*/, transformed];
1366
- case 3:
1367
- error_21 = _b.sent();
1368
- status_8 = (error_21 === null || error_21 === void 0 ? void 0 : error_21.status) || (error_21 === null || error_21 === void 0 ? void 0 : error_21.statusCode);
1369
- errorMessage = (0, errors_1.extractErrorMessage)(error_21);
1370
- this.logger.error('Failed to fetch customer orders', { customerId: customerId, error: errorMessage });
1371
- throw new errors_1.ProviderAPIError("Failed to fetch customer orders: ".concat(errorMessage), 'medusa', status_8);
1372
- case 4: return [2 /*return*/];
1373
- }
1374
- });
1375
- });
1376
- };
1377
- // ============================================
1378
- // Channel Scope Operations (Multi-Tenant)
1379
- // ============================================
1380
- /**
1381
- * Assign a customer to a sales channel via metadata.
1382
- *
1383
- * This is the primary mechanism for multi-tenant isolation of entities
1384
- * that the backend does not natively scope to a sales channel
1385
- * (e.g. customers in Medusa).
1386
- *
1387
- * Writes `sales_channel_id` + audit fields into `customer.metadata`.
1388
- * After assignment, `getCustomers({ salesChannelId })` will include
1389
- * this customer in its results.
1390
- *
1391
- * @param customerId - Customer to assign
1392
- * @param channelId - Target sales channel
1393
- * @param assignedBy - Optional: who triggered the assignment
1394
- * @returns Updated customer with new metadata
1395
- *
1396
- * @example
1397
- * ```typescript
1398
- * // Dropshipper creates customer → assign to their channel
1399
- * const customer = await commerce.assignCustomerToChannel(
1400
- * 'cus_01HXXX',
1401
- * process.env.NEXT_PUBLIC_SALES_CHANNEL_ID!,
1402
- * 'admin@mystore.com',
1403
- * );
1404
- * ```
1405
- */
1406
- MedusaProvider.prototype.assignCustomerToChannel = function (customerId, channelId, assignedBy) {
1407
- return __awaiter(this, void 0, void 0, function () {
1408
- var existing, currentMeta, scopeMeta;
1409
- var _a;
1410
- return __generator(this, function (_b) {
1411
- switch (_b.label) {
1412
- case 0:
1413
- (0, metadata_1.validateChannelScopeAssignment)(customerId, channelId, assignedBy);
1414
- this.logger.info('Assigning customer to channel', { customerId: customerId, channelId: channelId, assignedBy: assignedBy });
1415
- return [4 /*yield*/, this.getCustomer(customerId)];
1416
- case 1:
1417
- existing = _b.sent();
1418
- currentMeta = (_a = existing === null || existing === void 0 ? void 0 : existing.metadata) !== null && _a !== void 0 ? _a : {};
1419
- scopeMeta = (0, metadata_1.buildChannelScopeMetadata)(channelId, assignedBy);
1420
- return [2 /*return*/, this.updateCustomer(customerId, {
1421
- metadata: __assign(__assign({}, currentMeta), scopeMeta),
1422
- })];
1423
- }
1424
- });
1425
- });
1426
- };
1427
- /**
1428
- * Assign an order to a sales channel via metadata.
1429
- *
1430
- * Same pattern as `assignCustomerToChannel` but for orders.
1431
- * Useful when orders are created through flows that don't automatically
1432
- * link them to a channel.
1433
- *
1434
- * @param orderId - Order to assign
1435
- * @param channelId - Target sales channel
1436
- * @param assignedBy - Optional: who triggered the assignment
1437
- */
1438
- MedusaProvider.prototype.assignOrderToChannel = function (orderId, channelId, assignedBy) {
1439
- return __awaiter(this, void 0, void 0, function () {
1440
- var scopeMeta, error_22, status_9, errorMessage;
1441
- var _this = this;
1442
- return __generator(this, function (_a) {
1443
- switch (_a.label) {
1444
- case 0:
1445
- (0, metadata_1.validateChannelScopeAssignment)(orderId, channelId, assignedBy);
1446
- this.logger.info('Assigning order to channel', { orderId: orderId, channelId: channelId, assignedBy: assignedBy });
1447
- scopeMeta = (0, metadata_1.buildChannelScopeMetadata)(channelId, assignedBy);
1448
- _a.label = 1;
1449
- case 1:
1450
- _a.trys.push([1, 3, , 4]);
1451
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1452
- return __generator(this, function (_a) {
1453
- return [2 /*return*/, this.sdk.admin.order.update(orderId, {
1454
- metadata: scopeMeta,
1455
- })];
1456
- });
1457
- }); }, 'assignOrderToChannel', { orderId: orderId, channelId: channelId })];
1458
- case 2:
1459
- _a.sent();
1460
- return [3 /*break*/, 4];
1461
- case 3:
1462
- error_22 = _a.sent();
1463
- status_9 = (error_22 === null || error_22 === void 0 ? void 0 : error_22.status) || (error_22 === null || error_22 === void 0 ? void 0 : error_22.statusCode);
1464
- errorMessage = (0, errors_1.extractErrorMessage)(error_22);
1465
- this.logger.error('Failed to assign order to channel', { orderId: orderId, channelId: channelId, error: errorMessage });
1466
- throw new errors_1.ProviderAPIError("Failed to assign order to channel: ".concat(errorMessage), 'medusa', status_9);
1467
- case 4: return [2 /*return*/];
1468
- }
1469
- });
1470
- });
1471
- };
1472
- // ============================================
1473
- // Payment Operations
1474
- // ============================================
1475
- /**
1476
- * Get available payment methods
1477
- *
1478
- * Queries Medusa for payment providers available in a specific region.
1479
- * Region is determined either from options.regionId or from the cart.
1480
- *
1481
- * @param options - Payment methods query options (regionId or cartId required)
1482
- * @returns Array of available payment methods
1483
- *
1484
- * @example
1485
- * ```typescript
1486
- * // Get payment methods for a region
1487
- * const methods = await provider.getPaymentMethods({
1488
- * regionId: 'reg_123',
1489
- * enabledOnly: true
1490
- * });
1491
- *
1492
- * // Get payment methods for a cart
1493
- * const methods = await provider.getPaymentMethods({
1494
- * cartId: 'cart_123'
1495
- * });
1496
- * ```
1497
- */
1498
- MedusaProvider.prototype.getPaymentMethods = function (options) {
1499
- return __awaiter(this, void 0, void 0, function () {
1500
- var methods, error_23;
1501
- return __generator(this, function (_a) {
1502
- switch (_a.label) {
1503
- case 0:
1504
- this.logger.info('Getting payment methods', options);
1505
- _a.label = 1;
1506
- case 1:
1507
- _a.trys.push([1, 3, , 4]);
1508
- return [4 /*yield*/, (0, payment_1.getPaymentMethods)(this.sdk, options)];
1509
- case 2:
1510
- methods = _a.sent();
1511
- this.logger.debug("Found ".concat(methods.length, " payment methods"));
1512
- return [2 /*return*/, methods];
1513
- case 3:
1514
- error_23 = _a.sent();
1515
- this.logger.error('Error getting payment methods', error_23);
1516
- throw error_23; // Re-throw as it's already wrapped by getPaymentMethods
1517
- case 4: return [2 /*return*/];
1518
- }
1519
- });
1520
- });
1521
- };
1522
- // ============================================
1523
- // Checkout Operations
1524
- // ============================================
1525
- /**
1526
- * Complete checkout and create order from cart
1527
- *
1528
- * Finalizes the checkout process and converts the cart into an order.
1529
- * Cart must have shipping address, shipping method, and payment session.
1530
- *
1531
- * @param cartId - Cart ID to checkout
1532
- * @returns Created order
1533
- * @throws {ProviderAPIError} If checkout fails
1534
- */
1535
- MedusaProvider.prototype.completeCheckout = function (cartId) {
1536
- return __awaiter(this, void 0, void 0, function () {
1537
- var error_24;
1538
- var _this = this;
1539
- return __generator(this, function (_a) {
1540
- switch (_a.label) {
1541
- case 0:
1542
- this.logger.debug('completeCheckout', { cartId: cartId });
1543
- _a.label = 1;
1544
- case 1:
1545
- _a.trys.push([1, 3, , 4]);
1546
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1547
- var order;
1548
- return __generator(this, function (_a) {
1549
- switch (_a.label) {
1550
- case 0: return [4 /*yield*/, this.sdk.store.cart.complete(cartId)];
1551
- case 1:
1552
- order = (_a.sent()).order;
1553
- if (!order) {
1554
- throw new errors_1.ProviderAPIError('Checkout completed but no order returned', 'medusa', 500);
1555
- }
1556
- this.logger.info('Checkout completed successfully', {
1557
- orderId: order.id,
1558
- displayId: order.display_id,
1559
- });
1560
- return [2 /*return*/, (0, transforms_1.transformOrder)(order)];
1561
- }
1562
- });
1563
- }); }, 'completeCheckout', { cartId: cartId })];
1564
- case 2: return [2 /*return*/, _a.sent()];
1565
- case 3:
1566
- error_24 = _a.sent();
1567
- this.logger.error('Failed to complete checkout', { cartId: cartId, error: error_24.message });
1568
- throw new errors_1.ProviderAPIError("Failed to complete checkout: ".concat(error_24.message), 'medusa', error_24.status);
1569
- case 4: return [2 /*return*/];
1570
- }
1571
- });
1572
- });
1573
- };
1574
- /**
1575
- * Get available shipping methods for cart
1576
- *
1577
- * Fetches shipping options based on cart region and shipping address.
1578
- *
1579
- * @param cartId - Cart ID
1580
- * @returns List of shipping methods with prices
1581
- * @throws {ProviderAPIError} If cart not found or region not configured
1582
- */
1583
- MedusaProvider.prototype.getShippingMethods = function (cartId) {
1584
- return __awaiter(this, void 0, void 0, function () {
1585
- var error_25;
1586
- var _this = this;
1587
- return __generator(this, function (_a) {
1588
- switch (_a.label) {
1589
- case 0:
1590
- this.logger.info('🚚 [DEBUG] getShippingMethods called', { cartId: cartId });
1591
- _a.label = 1;
1592
- case 1:
1593
- _a.trys.push([1, 3, , 4]);
1594
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1595
- var cartResponse, cart, shippingResponse, shipping_options, storeAny, baseUrl, url, response, sdkError_1, methods;
1596
- var _this = this;
1597
- var _a, _b;
1598
- return __generator(this, function (_c) {
1599
- switch (_c.label) {
1600
- case 0:
1601
- // Get raw cart to access region
1602
- this.logger.info('🚚 [DEBUG] Step 1: Retrieving cart from Medusa...', { cartId: cartId });
1603
- return [4 /*yield*/, this.sdk.store.cart.retrieve(cartId)];
1604
- case 1:
1605
- cartResponse = (_c.sent());
1606
- cart = cartResponse.cart;
1607
- // Log raw cart response for debugging
1608
- this.logger.info('🚚 [DEBUG] Step 2: Cart retrieved from backend', {
1609
- cartId: cartId,
1610
- hasCart: !!cart,
1611
- cartKeys: cart ? Object.keys(cart) : [],
1612
- regionId: cart === null || cart === void 0 ? void 0 : cart.region_id,
1613
- currencyCode: cart === null || cart === void 0 ? void 0 : cart.currency_code,
1614
- shippingAddress: (cart === null || cart === void 0 ? void 0 : cart.shipping_address)
1615
- ? {
1616
- country: cart.shipping_address.country_code,
1617
- postal: cart.shipping_address.postal_code,
1618
- }
1619
- : null,
1620
- });
1621
- if (!cart) {
1622
- this.logger.error('🚚 [DEBUG] ERROR: Cart not found in response', {
1623
- cartId: cartId,
1624
- cartResponse: cartResponse,
1625
- });
1626
- throw new errors_1.ResourceNotFoundError('Cart', cartId);
1627
- }
1628
- if (!cart.region_id) {
1629
- this.logger.error('🚚 [DEBUG] ERROR: Cart has no region_id', {
1630
- cartId: cartId,
1631
- cart: {
1632
- id: cart.id,
1633
- region_id: cart.region_id,
1634
- region: cart.region,
1635
- allKeys: Object.keys(cart),
1636
- },
1637
- });
1638
- throw new errors_1.ProviderAPIError('Cart has no region assigned', 'medusa', 400);
1639
- }
1640
- // Fetch shipping options for cart
1641
- // Medusa v2 endpoint: GET /store/shipping-options?cart_id=...
1642
- this.logger.info('🚚 [DEBUG] Step 3: Fetching shipping options from Medusa...', {
1643
- cartId: cartId,
1644
- regionId: cart.region_id,
1645
- endpoint: "".concat(this.baseUrl, "store/shipping-options?cart_id=").concat(cartId),
1646
- note: 'About to fetch shipping options (SDK when available, otherwise HTTP)',
1647
- });
1648
- _c.label = 2;
1649
- case 2:
1650
- _c.trys.push([2, 8, , 9]);
1651
- storeAny = this.sdk.store;
1652
- if (!((_a = storeAny === null || storeAny === void 0 ? void 0 : storeAny.shippingOption) === null || _a === void 0 ? void 0 : _a.list)) return [3 /*break*/, 4];
1653
- return [4 /*yield*/, storeAny.shippingOption.list({
1654
- cart_id: cartId,
1655
- })];
1656
- case 3:
1657
- shippingResponse = (_c.sent());
1658
- return [3 /*break*/, 7];
1659
- case 4:
1660
- baseUrl = this.baseUrl.endsWith('/') ? this.baseUrl : "".concat(this.baseUrl, "/");
1661
- url = new URL('store/shipping-options', baseUrl);
1662
- url.searchParams.set('cart_id', cartId);
1663
- return [4 /*yield*/, (0, fetch_utils_1.fetchWithRetry)(url.toString(), {
1664
- method: 'GET',
1665
- headers: {
1666
- 'x-publishable-api-key': this.publishableKey,
1667
- 'content-type': 'application/json',
1668
- },
1669
- }, this.retryConfig)];
1670
- case 5:
1671
- response = _c.sent();
1672
- return [4 /*yield*/, response.json()];
1673
- case 6:
1674
- shippingResponse = (_c.sent());
1675
- _c.label = 7;
1676
- case 7:
1677
- shipping_options = shippingResponse.shipping_options;
1678
- return [3 /*break*/, 9];
1679
- case 8:
1680
- sdkError_1 = _c.sent();
1681
- // Log detailed error from Medusa backend
1682
- this.logger.error('🚚 [DEBUG] ERROR: Medusa SDK threw error when fetching shipping options', {
1683
- cartId: cartId,
1684
- regionId: cart.region_id,
1685
- errorType: (_b = sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.constructor) === null || _b === void 0 ? void 0 : _b.name,
1686
- errorMessage: sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.message,
1687
- errorStatus: sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.status,
1688
- errorCode: sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.code,
1689
- errorResponse: (sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.response)
1690
- ? JSON.stringify(sdkError_1.response, null, 2)
1691
- : 'N/A',
1692
- errorBody: (sdkError_1 === null || sdkError_1 === void 0 ? void 0 : sdkError_1.body) ? JSON.stringify(sdkError_1.body, null, 2) : 'N/A',
1693
- fullError: JSON.stringify(sdkError_1, Object.getOwnPropertyNames(sdkError_1), 2),
1694
- });
1695
- throw sdkError_1;
1696
- case 9:
1697
- // Log raw shipping options response
1698
- this.logger.info('🚚 [DEBUG] Step 4: Shipping options received from backend', {
1699
- cartId: cartId,
1700
- totalOptions: (shipping_options === null || shipping_options === void 0 ? void 0 : shipping_options.length) || 0,
1701
- rawResponse: JSON.stringify(shippingResponse, null, 2),
1702
- firstOption: (shipping_options === null || shipping_options === void 0 ? void 0 : shipping_options[0])
1703
- ? {
1704
- id: shipping_options[0].id,
1705
- name: shipping_options[0].name,
1706
- allKeys: Object.keys(shipping_options[0]),
1707
- price_incl_tax: shipping_options[0].price_incl_tax,
1708
- amount: shipping_options[0].amount,
1709
- data: shipping_options[0].data,
1710
- }
1711
- : null,
1712
- });
1713
- methods = shipping_options.map(function (option) {
1714
- var _a, _b, _c, _d, _e;
1715
- return ({
1716
- id: option.id,
1717
- name: option.name,
1718
- price: {
1719
- amount: ((_a = option.price_incl_tax) === null || _a === void 0 ? void 0 : _a.toString()) || ((_b = option.amount) === null || _b === void 0 ? void 0 : _b.toString()) || '0',
1720
- currencyCode: ((_c = cart.currency_code) === null || _c === void 0 ? void 0 : _c.toUpperCase()) || _this.currencyCode,
1721
- },
1722
- description: (_d = option.data) === null || _d === void 0 ? void 0 : _d.description,
1723
- estimatedDays: ((_e = option.data) === null || _e === void 0 ? void 0 : _e.estimated_days) || 'N/A',
1724
- });
1725
- });
1726
- // Log transformed methods
1727
- this.logger.info('🚚 [DEBUG] Step 5: Transformed methods for Thor types', {
1728
- cartId: cartId,
1729
- count: methods.length,
1730
- methods: JSON.stringify(methods, null, 2),
1731
- });
1732
- return [2 /*return*/, methods];
1733
- }
1734
- });
1735
- }); }, 'getShippingMethods', { cartId: cartId })];
1736
- case 2: return [2 /*return*/, _a.sent()];
1737
- case 3:
1738
- error_25 = _a.sent();
1739
- this.logger.error('🚚 [DEBUG] ERROR: Failed to fetch shipping methods', {
1740
- cartId: cartId,
1741
- errorMessage: error_25.message,
1742
- errorStack: error_25.stack,
1743
- errorStatus: error_25.status,
1744
- });
1745
- throw new errors_1.ProviderAPIError("Failed to fetch shipping methods: ".concat(error_25.message), 'medusa', error_25.status);
1746
- case 4: return [2 /*return*/];
1747
- }
1748
- });
1749
- });
1750
- };
1751
- // ============================================
1752
- // Inventory Operations (Admin-only via Proxy)
1753
- // ============================================
1754
- /**
1755
- * Fetch stock locations, optionally filtered by sales channel.
1756
- *
1757
- * Note: Medusa Store API does NOT expose stock locations. This requires Admin API access.
1758
- * Implement in L5 (starter) using a secure proxy (Server Actions).
1759
- */
1760
- MedusaProvider.prototype.getStockLocations = function (params) {
1761
- return __awaiter(this, void 0, void 0, function () {
1762
- return __generator(this, function (_a) {
1763
- void params;
1764
- throw new Error('MedusaProvider.getStockLocations requires Admin API access. ' +
1765
- 'Call it via the B2C inventory proxy (Server Actions) instead.');
1766
- });
1767
- });
1768
- };
1769
- /**
1770
- * Check inventory levels for a variant across locations.
1771
- *
1772
- * Note: Admin API only. Implement in L5 (starter) proxy.
1773
- */
1774
- MedusaProvider.prototype.checkInventoryLevels = function (variantId, salesChannelId) {
1775
- return __awaiter(this, void 0, void 0, function () {
1776
- return __generator(this, function (_a) {
1777
- void variantId;
1778
- void salesChannelId;
1779
- throw new Error('MedusaProvider.checkInventoryLevels requires Admin API access. ' +
1780
- 'Call it via the B2C inventory proxy (Server Actions) instead.');
1781
- });
1782
- });
1783
- };
1784
- /**
1785
- * Validate cart stock availability.
1786
- *
1787
- * Note: Multi-location inventory validation requires Admin API.
1788
- * Use L5 proxy for real validation.
1789
- */
1790
- MedusaProvider.prototype.validateCartStock = function (cartId) {
1791
- return __awaiter(this, void 0, void 0, function () {
1792
- return __generator(this, function (_a) {
1793
- void cartId;
1794
- throw new Error('MedusaProvider.validateCartStock requires Admin API access. ' +
1795
- 'Use validateCartInventory() in the starter inventory proxy instead.');
1796
- });
1797
- });
1798
- };
1799
- /**
1800
- * Get fulfillment options enriched with stock location data.
1801
- *
1802
- * Note: This requires fulfillment planning + Admin inventory. Implement in L5.
1803
- */
1804
- MedusaProvider.prototype.getFulfillmentOptions = function (cartId, salesChannelId) {
1805
- return __awaiter(this, void 0, void 0, function () {
1806
- return __generator(this, function (_a) {
1807
- void cartId;
1808
- void salesChannelId;
1809
- throw new Error('MedusaProvider.getFulfillmentOptions is not available via Store API. ' +
1810
- 'Implement in the starter using the fulfillment planner + admin proxy.');
1811
- });
1812
- });
1813
- };
1814
- /**
1815
- * Get available countries for a region
1816
- *
1817
- * Returns list of countries that can be used for shipping addresses
1818
- * in the specified region. Results are cached for 5 minutes.
1819
- *
1820
- * @param regionId - Region ID
1821
- * @returns Array of countries with codes and names
1822
- * @throws {ProviderAPIError} If region not found or API error
1823
- *
1824
- * @example
1825
- * ```typescript
1826
- * const countries = await medusa.getRegionCountries('reg_01KHCJQ5YXYRWWCKSTYQ4SCM8V');
1827
- * // [{ code: 'ES', name: 'Spain' }, { code: 'FR', name: 'France' }, ...]
1828
- * ```
1829
- */
1830
- MedusaProvider.prototype.getRegionCountries = function (regionId) {
1831
- return __awaiter(this, void 0, void 0, function () {
1832
- var cached, now, error_26;
1833
- var _this = this;
1834
- return __generator(this, function (_a) {
1835
- switch (_a.label) {
1836
- case 0:
1837
- this.logger.info('🌍 [DEBUG] getRegionCountries called', { regionId: regionId });
1838
- cached = this.regionCountriesCache.get(regionId);
1839
- now = Date.now();
1840
- if (cached && cached.expiresAt > now) {
1841
- this.logger.info('🌍 [DEBUG] Returning cached countries', {
1842
- regionId: regionId,
1843
- count: cached.countries.length,
1844
- cacheAge: Math.round((now - (cached.expiresAt - this.REGION_COUNTRIES_CACHE_TTL)) / 1000) + 's',
1845
- });
1846
- return [2 /*return*/, cached.countries];
1847
- }
1848
- _a.label = 1;
1849
- case 1:
1850
- _a.trys.push([1, 3, , 4]);
1851
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1852
- var region, countries;
1853
- var _a;
1854
- return __generator(this, function (_b) {
1855
- switch (_b.label) {
1856
- case 0:
1857
- this.logger.info('🌍 [DEBUG] Fetching countries from Medusa API...', { regionId: regionId });
1858
- return [4 /*yield*/, this.sdk.store.region.retrieve(regionId, {
1859
- fields: '+countries.iso_2,+countries.display_name,+countries.name,+countries.iso_3,+countries.num_code',
1860
- })];
1861
- case 1:
1862
- region = (_b.sent()).region;
1863
- if (!region) {
1864
- throw new errors_1.ResourceNotFoundError('Region', regionId);
1865
- }
1866
- this.logger.info('🌍 [DEBUG] Region retrieved', {
1867
- regionId: regionId,
1868
- regionName: region.name,
1869
- hasCountries: !!region.countries,
1870
- countriesCount: ((_a = region.countries) === null || _a === void 0 ? void 0 : _a.length) || 0,
1871
- });
1872
- countries = (region.countries || []).map(function (c) { return ({
1873
- code: c.iso_2.toUpperCase(), // Frontend expects uppercase for validation
1874
- name: c.display_name || c.name,
1875
- iso3: c.iso_3,
1876
- numCode: c.num_code,
1877
- }); });
1878
- // Sort by name for better UX
1879
- countries.sort(function (a, b) { return a.name.localeCompare(b.name); });
1880
- this.logger.info('🌍 [DEBUG] Countries transformed and sorted', {
1881
- regionId: regionId,
1882
- count: countries.length,
1883
- firstThree: countries.slice(0, 3).map(function (c) { return "".concat(c.code, ": ").concat(c.name); }),
1884
- });
1885
- // Cache the result
1886
- this.regionCountriesCache.set(regionId, {
1887
- countries: countries,
1888
- expiresAt: now + this.REGION_COUNTRIES_CACHE_TTL,
1889
- });
1890
- return [2 /*return*/, countries];
1891
- }
1892
- });
1893
- }); }, 'getRegionCountries', { regionId: regionId })];
1894
- case 2: return [2 /*return*/, _a.sent()];
1895
- case 3:
1896
- error_26 = _a.sent();
1897
- this.logger.error('🌍 [DEBUG] ERROR: Failed to fetch region countries', {
1898
- regionId: regionId,
1899
- errorMessage: error_26.message,
1900
- errorStatus: error_26.status,
1901
- });
1902
- // Provide helpful error messages
1903
- if (error_26.status === 404) {
1904
- throw new errors_1.ResourceNotFoundError('Region', regionId);
1905
- }
1906
- throw new errors_1.ProviderAPIError("Failed to fetch countries for region: ".concat(error_26.message), 'medusa', error_26.status);
1907
- case 4: return [2 /*return*/];
1908
- }
1909
- });
1910
- });
1911
- };
1912
- /**
1913
- * Add shipping method to cart
1914
- *
1915
- * Applies a shipping method to the cart and updates totals.
1916
- *
1917
- * @param cartId - Cart ID
1918
- * @param methodId - Shipping method ID (from getShippingMethods)
1919
- * @returns Updated cart with shipping
1920
- * @throws {ProviderAPIError} If method invalid or cart not ready
1921
- */
1922
- MedusaProvider.prototype.addShippingMethod = function (cartId, methodId) {
1923
- return __awaiter(this, void 0, void 0, function () {
1924
- var error_27;
1925
- var _this = this;
1926
- return __generator(this, function (_a) {
1927
- switch (_a.label) {
1928
- case 0:
1929
- this.logger.debug('addShippingMethod', { cartId: cartId, methodId: methodId });
1930
- _a.label = 1;
1931
- case 1:
1932
- _a.trys.push([1, 3, , 4]);
1933
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1934
- var cart, updatedCart;
1935
- return __generator(this, function (_a) {
1936
- switch (_a.label) {
1937
- case 0: return [4 /*yield*/, this.sdk.store.cart.addShippingMethod(cartId, {
1938
- option_id: methodId,
1939
- })];
1940
- case 1:
1941
- cart = (_a.sent()).cart;
1942
- this.logger.info('Shipping method added successfully', { cartId: cartId, methodId: methodId });
1943
- void cart;
1944
- return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
1945
- case 2:
1946
- updatedCart = _a.sent();
1947
- return [2 /*return*/, (0, transforms_1.transformCart)(updatedCart)];
1948
- }
1949
- });
1950
- }); }, 'addShippingMethod', { cartId: cartId, methodId: methodId })];
1951
- case 2: return [2 /*return*/, _a.sent()];
1952
- case 3:
1953
- error_27 = _a.sent();
1954
- this.logger.error('Failed to add shipping method', {
1955
- cartId: cartId,
1956
- methodId: methodId,
1957
- error: error_27.message,
1958
- });
1959
- throw new errors_1.ProviderAPIError("Failed to add shipping method: ".concat(error_27.message), 'medusa', error_27.status);
1960
- case 4: return [2 /*return*/];
1961
- }
1962
- });
1963
- });
1964
- };
1965
- /**
1966
- * Initiate payment session with provider
1967
- *
1968
- * Creates a payment session for the cart with the specified provider.
1969
- *
1970
- * @param cartId - Cart ID
1971
- * @param providerId - Payment provider ID (from getPaymentMethods)
1972
- * @throws {ProviderAPIError} If provider invalid or cart not ready
1973
- */
1974
- MedusaProvider.prototype.initiatePaymentSession = function (cartId, providerId) {
1975
- return __awaiter(this, void 0, void 0, function () {
1976
- var error_28;
1977
- var _this = this;
1978
- return __generator(this, function (_a) {
1979
- switch (_a.label) {
1980
- case 0:
1981
- this.logger.info('💳 [DEBUG] initiatePaymentSession called', { cartId: cartId, providerId: providerId });
1982
- _a.label = 1;
1983
- case 1:
1984
- _a.trys.push([1, 3, , 4]);
1985
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
1986
- var rawCart, existingSessions, paymentResponse, sdkError_2;
1987
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1988
- return __generator(this, function (_m) {
1989
- switch (_m.label) {
1990
- case 0:
1991
- // Get RAW cart object from Medusa SDK (not transformed)
1992
- // CHANGE 1: Add payment_collection fields to query
1993
- this.logger.info('💳 [DEBUG] Step 1: Retrieving RAW cart from Medusa for payment session...', { cartId: cartId });
1994
- return [4 /*yield*/, this.sdk.store.cart.retrieve(cartId, {
1995
- fields: '+shipping_methods,+shipping_address,+email,+region_id,+total,+items,+payment_collection,+payment_collection.payment_sessions,+billing_address',
1996
- })];
1997
- case 1:
1998
- rawCart = (_m.sent()).cart;
1999
- this.logger.info('💳 [DEBUG] Step 2: RAW cart retrieved, checking state...', {
2000
- cartId: rawCart.id,
2001
- hasShippingMethod: !!((_a = rawCart.shipping_methods) === null || _a === void 0 ? void 0 : _a.length),
2002
- shippingMethodIds: ((_b = rawCart.shipping_methods) === null || _b === void 0 ? void 0 : _b.map(function (sm) { return sm.id; })) || [],
2003
- hasShippingAddress: !!rawCart.shipping_address,
2004
- shippingAddressCity: ((_c = rawCart.shipping_address) === null || _c === void 0 ? void 0 : _c.city) || 'N/A',
2005
- hasEmail: !!rawCart.email,
2006
- email: rawCart.email || 'N/A',
2007
- hasBillingAddress: !!rawCart.billing_address,
2008
- hasPaymentCollection: !!rawCart.payment_collection,
2009
- existingSessionsCount: ((_e = (_d = rawCart.payment_collection) === null || _d === void 0 ? void 0 : _d.payment_sessions) === null || _e === void 0 ? void 0 : _e.length) || 0,
2010
- regionId: rawCart.region_id,
2011
- total: rawCart.total,
2012
- itemCount: ((_f = rawCart.items) === null || _f === void 0 ? void 0 : _f.length) || 0,
2013
- });
2014
- // 🛡️ VALIDATION: Cart must have items to create payment session
2015
- if (!rawCart.items || rawCart.items.length === 0) {
2016
- this.logger.error('💳 [DEBUG] ERROR: Cannot create payment session for empty cart', {
2017
- cartId: cartId,
2018
- itemCount: 0,
2019
- reason: 'Cart has no items',
2020
- });
2021
- throw new errors_1.ProviderAPIError('Cannot create payment session: cart is empty. Please add items to your cart before checking out.', 'medusa', 400);
2022
- }
2023
- // 🛡️ VALIDATION: Required fields
2024
- if (!rawCart.shipping_address) {
2025
- this.logger.error('💳 [DEBUG] ERROR: Shipping address required', { cartId: cartId });
2026
- throw new errors_1.ProviderAPIError('Shipping address is required before initiating payment session', 'medusa', 400);
2027
- }
2028
- if (!((_g = rawCart.shipping_methods) === null || _g === void 0 ? void 0 : _g.length)) {
2029
- this.logger.error('💳 [DEBUG] ERROR: Shipping method required', { cartId: cartId });
2030
- throw new errors_1.ProviderAPIError('Shipping method is required before initiating payment session', 'medusa', 400);
2031
- }
2032
- if (!rawCart.email) {
2033
- this.logger.error('💳 [DEBUG] ERROR: Email required', { cartId: cartId });
2034
- throw new errors_1.ProviderAPIError('Email is required before initiating payment session', 'medusa', 400);
2035
- }
2036
- // CHANGE 2: Validate billing address and warn if missing
2037
- if (!rawCart.billing_address) {
2038
- this.logger.warn('💳 [DEBUG] WARNING: Billing address not set, payment provider may require it', {
2039
- cartId: rawCart.id,
2040
- shippingAddress: rawCart.shipping_address,
2041
- });
2042
- }
2043
- existingSessions = ((_h = rawCart.payment_collection) === null || _h === void 0 ? void 0 : _h.payment_sessions) || [];
2044
- if (existingSessions.length > 0) {
2045
- this.logger.info('💳 [DEBUG] Payment session already exists, skipping creation', {
2046
- cartId: rawCart.id,
2047
- sessionCount: existingSessions.length,
2048
- sessionIds: existingSessions.map(function (s) { return s.id; }),
2049
- });
2050
- // Return early - session already exists
2051
- return [2 /*return*/];
2052
- }
2053
- this.logger.info('💳 [DEBUG] Step 2.5: No existing payment sessions, will create new one', {
2054
- cartId: rawCart.id,
2055
- hasPaymentCollection: !!rawCart.payment_collection,
2056
- providerId: providerId,
2057
- });
2058
- // Medusa v2 SDK: sdk.store.payment.initiatePaymentSession(cart, options)
2059
- this.logger.info('💳 [DEBUG] Step 3: Calling Medusa SDK initiatePaymentSession...', {
2060
- cartId: cartId,
2061
- providerId: providerId,
2062
- endpoint: "".concat(this.baseUrl, "store/payment-collections"),
2063
- note: 'About to call SDK method',
2064
- });
2065
- // VALIDATION: Ensure provider_id is a valid backend ID
2066
- // Prevent sending normalized types like 'card', 'wallet', 'cash_on_delivery'
2067
- this.logger.info('💳 [DEBUG] Step 2.5: Validating provider ID...', {
2068
- providerId: providerId,
2069
- });
2070
- try {
2071
- (0, payment_utils_1.validatePaymentId)(providerId);
2072
- this.logger.info('💳 [DEBUG] Provider ID validation passed', { providerId: providerId });
2073
- }
2074
- catch (validationError) {
2075
- this.logger.error('💳 [DEBUG] ERROR: Invalid provider ID detected', {
2076
- providerId: providerId,
2077
- error: validationError.message,
2078
- hint: 'Use getBackendProviderId(paymentMethod) to extract correct ID',
2079
- });
2080
- throw new errors_1.ProviderAPIError(validationError.message, 'medusa', 400);
2081
- }
2082
- _m.label = 2;
2083
- case 2:
2084
- _m.trys.push([2, 4, , 5]);
2085
- return [4 /*yield*/, this.sdk.store.payment.initiatePaymentSession(rawCart, {
2086
- provider_id: providerId,
2087
- })];
2088
- case 3:
2089
- paymentResponse = _m.sent();
2090
- this.logger.info('💳 [DEBUG] Step 4: Payment session response received', {
2091
- cartId: cartId,
2092
- providerId: providerId,
2093
- responseKeys: paymentResponse ? Object.keys(paymentResponse) : [],
2094
- response: JSON.stringify(paymentResponse, null, 2),
2095
- });
2096
- return [3 /*break*/, 5];
2097
- case 4:
2098
- sdkError_2 = _m.sent();
2099
- // CHANGE 4: Enhanced error context
2100
- this.logger.error('💳 [DEBUG] ERROR: Medusa SDK threw error when initiating payment session', {
2101
- cartId: cartId,
2102
- providerId: providerId,
2103
- errorType: (_j = sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.constructor) === null || _j === void 0 ? void 0 : _j.name,
2104
- errorMessage: sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.message,
2105
- errorStatus: sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.status,
2106
- errorCode: sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.code,
2107
- errorResponse: (sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.response)
2108
- ? JSON.stringify(sdkError_2.response, null, 2)
2109
- : 'N/A',
2110
- errorBody: (sdkError_2 === null || sdkError_2 === void 0 ? void 0 : sdkError_2.body) ? JSON.stringify(sdkError_2.body, null, 2) : 'N/A',
2111
- fullError: JSON.stringify(sdkError_2, Object.getOwnPropertyNames(sdkError_2), 2),
2112
- // Include cart state in error for debugging
2113
- cartState: {
2114
- hasShippingMethod: !!((_k = rawCart.shipping_methods) === null || _k === void 0 ? void 0 : _k.length),
2115
- hasShippingAddress: !!rawCart.shipping_address,
2116
- hasBillingAddress: !!rawCart.billing_address,
2117
- hasEmail: !!rawCart.email,
2118
- total: rawCart.total,
2119
- itemCount: ((_l = rawCart.items) === null || _l === void 0 ? void 0 : _l.length) || 0,
2120
- },
2121
- });
2122
- throw sdkError_2;
2123
- case 5:
2124
- this.logger.info('💳 [DEBUG] Payment session initiated successfully', {
2125
- cartId: cartId,
2126
- providerId: providerId,
2127
- });
2128
- return [2 /*return*/];
2129
- }
2130
- });
2131
- }); }, 'initiatePaymentSession', { cartId: cartId, providerId: providerId })];
2132
- case 2:
2133
- _a.sent();
2134
- return [3 /*break*/, 4];
2135
- case 3:
2136
- error_28 = _a.sent();
2137
- this.logger.error('💳 [DEBUG] ERROR: Failed to initiate payment session', {
2138
- cartId: cartId,
2139
- providerId: providerId,
2140
- errorMessage: error_28.message,
2141
- errorStack: error_28.stack,
2142
- errorStatus: error_28.status,
2143
- });
2144
- throw new errors_1.ProviderAPIError("Failed to initiate payment session: ".concat(error_28.message), 'medusa', error_28.status);
2145
- case 4: return [2 /*return*/];
2146
- }
2147
- });
2148
- });
2149
- };
2150
- /**
2151
- * Apply discount code to cart
2152
- *
2153
- * Validates and applies a discount/promo code to the cart.
2154
- *
2155
- * @param cartId - Cart ID
2156
- * @param code - Discount code
2157
- * @returns Updated cart with discount
2158
- * @throws {ProviderAPIError} If code invalid or expired
2159
- */
2160
- MedusaProvider.prototype.applyDiscountCode = function (cartId, code) {
2161
- return __awaiter(this, void 0, void 0, function () {
2162
- var error_29;
2163
- var _this = this;
2164
- return __generator(this, function (_a) {
2165
- switch (_a.label) {
2166
- case 0:
2167
- this.logger.debug('applyDiscountCode', { cartId: cartId, code: code });
2168
- _a.label = 1;
2169
- case 1:
2170
- _a.trys.push([1, 3, , 4]);
2171
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
2172
- var response, error, medusaCart, updatedCart;
2173
- return __generator(this, function (_a) {
2174
- switch (_a.label) {
2175
- case 0: return [4 /*yield*/, fetch("".concat(this.baseUrl, "/store/carts/").concat(cartId, "/promotions"), {
2176
- method: 'POST',
2177
- headers: {
2178
- 'Content-Type': 'application/json',
2179
- 'x-publishable-api-key': this.publishableKey || '',
2180
- },
2181
- body: JSON.stringify({
2182
- promo_codes: [code],
2183
- }),
2184
- })];
2185
- case 1:
2186
- response = _a.sent();
2187
- if (!!response.ok) return [3 /*break*/, 3];
2188
- return [4 /*yield*/, response.json()];
2189
- case 2:
2190
- error = _a.sent();
2191
- throw new Error(error.message || 'Failed to apply discount code');
2192
- case 3: return [4 /*yield*/, response.json()];
2193
- case 4:
2194
- medusaCart = (_a.sent()).cart;
2195
- this.logger.info('Discount code applied successfully', { cartId: cartId, code: code });
2196
- void medusaCart;
2197
- return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
2198
- case 5:
2199
- updatedCart = _a.sent();
2200
- return [2 /*return*/, (0, transforms_1.transformCart)(updatedCart)];
2201
- }
2202
- });
2203
- }); }, 'applyDiscountCode', { cartId: cartId, code: code })];
2204
- case 2: return [2 /*return*/, _a.sent()];
2205
- case 3:
2206
- error_29 = _a.sent();
2207
- this.logger.error('Failed to apply discount code', { cartId: cartId, code: code, error: error_29.message });
2208
- throw new errors_1.ProviderAPIError("Failed to apply discount code: ".concat(error_29.message), 'medusa', error_29.status);
2209
- case 4: return [2 /*return*/];
2210
- }
2211
- });
2212
- });
2213
- };
2214
- /**
2215
- * Remove discount code from cart
2216
- *
2217
- * Removes a previously applied discount code.
2218
- *
2219
- * @param cartId - Cart ID
2220
- * @param code - Discount code to remove
2221
- * @returns Updated cart without discount
2222
- * @throws {ProviderAPIError} If cart not found
2223
- */
2224
- MedusaProvider.prototype.removeDiscountCode = function (cartId, code) {
2225
- return __awaiter(this, void 0, void 0, function () {
2226
- var error_30;
2227
- var _this = this;
2228
- return __generator(this, function (_a) {
2229
- switch (_a.label) {
2230
- case 0:
2231
- this.logger.debug('removeDiscountCode', { cartId: cartId, code: code });
2232
- _a.label = 1;
2233
- case 1:
2234
- _a.trys.push([1, 3, , 4]);
2235
- return [4 /*yield*/, this.withRetry(function () { return __awaiter(_this, void 0, void 0, function () {
2236
- var response, error, medusaCart, updatedCart;
2237
- return __generator(this, function (_a) {
2238
- switch (_a.label) {
2239
- case 0: return [4 /*yield*/, fetch("".concat(this.baseUrl, "/store/carts/").concat(cartId, "/promotions"), {
2240
- method: 'DELETE',
2241
- headers: {
2242
- 'Content-Type': 'application/json',
2243
- 'x-publishable-api-key': this.publishableKey || '',
2244
- },
2245
- body: JSON.stringify({
2246
- promo_codes: [code],
2247
- }),
2248
- })];
2249
- case 1:
2250
- response = _a.sent();
2251
- if (!!response.ok) return [3 /*break*/, 3];
2252
- return [4 /*yield*/, response.json()];
2253
- case 2:
2254
- error = _a.sent();
2255
- throw new Error(error.message || 'Failed to remove discount code');
2256
- case 3: return [4 /*yield*/, response.json()];
2257
- case 4:
2258
- medusaCart = (_a.sent()).cart;
2259
- this.logger.info('Discount code removed successfully', { cartId: cartId, code: code });
2260
- void medusaCart;
2261
- return [4 /*yield*/, this.retrieveCartWithLineDetails(cartId)];
2262
- case 5:
2263
- updatedCart = _a.sent();
2264
- return [2 /*return*/, (0, transforms_1.transformCart)(updatedCart)];
2265
- }
2266
- });
2267
- }); }, 'removeDiscountCode', { cartId: cartId, code: code })];
2268
- case 2: return [2 /*return*/, _a.sent()];
2269
- case 3:
2270
- error_30 = _a.sent();
2271
- this.logger.error('Failed to remove discount code', { cartId: cartId, code: code, error: error_30.message });
2272
- throw new errors_1.ProviderAPIError("Failed to remove discount code: ".concat(error_30.message), 'medusa', error_30.status);
2273
- case 4: return [2 /*return*/];
2274
- }
2275
- });
2276
- });
2277
- };
2278
- /**
2279
- * Update cart shipping address
2280
- * @param cartId - Cart ID
2281
- * @param address - Shipping address details
2282
- * @returns Updated cart
2283
- *
2284
- * **CRITICAL**: Must be called BEFORE initiatePaymentSession
2285
- * Medusa requires shipping_address on cart before creating payment session
2286
- */
2287
- MedusaProvider.prototype.updateShippingAddress = function (cartId, address) {
2288
- return __awaiter(this, void 0, void 0, function () {
2289
- var rawCart, error_31, errorMessage, status_10, userMessage;
2290
- return __generator(this, function (_a) {
2291
- switch (_a.label) {
2292
- case 0:
2293
- this.logger.info('📫 [DEBUG] updateShippingAddress called', {
2294
- cartId: cartId,
2295
- email: address.email,
2296
- city: address.city,
2297
- countryCode: address.countryCode,
2298
- });
2299
- _a.label = 1;
2300
- case 1:
2301
- _a.trys.push([1, 3, , 4]);
2302
- return [4 /*yield*/, this.sdk.store.cart.update(cartId, {
2303
- email: address.email,
2304
- shipping_address: {
2305
- first_name: address.firstName,
2306
- last_name: address.lastName,
2307
- address_1: address.address1,
2308
- address_2: address.address2 || '',
2309
- company: address.company || '',
2310
- city: address.city,
2311
- province: address.province,
2312
- postal_code: address.postalCode,
2313
- country_code: address.countryCode.toLowerCase(), // Medusa expects lowercase
2314
- phone: address.phone,
2315
- },
2316
- })];
2317
- case 2:
2318
- rawCart = (_a.sent()).cart;
2319
- this.logger.info('📫 [DEBUG] Shipping address updated successfully', {
2320
- cartId: cartId,
2321
- hasEmail: !!rawCart.email,
2322
- hasShippingAddress: !!rawCart.shipping_address,
2323
- });
2324
- return [3 /*break*/, 4];
2325
- case 3:
2326
- error_31 = _a.sent();
2327
- errorMessage = (0, errors_1.extractErrorMessage)(error_31);
2328
- status_10 = (error_31 === null || error_31 === void 0 ? void 0 : error_31.status) || (error_31 === null || error_31 === void 0 ? void 0 : error_31.statusCode);
2329
- this.logger.error('Failed to update shipping address', {
2330
- cartId: cartId,
2331
- error: errorMessage,
2332
- status: status_10,
2333
- });
2334
- userMessage = errorMessage;
2335
- if (errorMessage.includes('is not within region')) {
2336
- // Region/Country mismatch
2337
- userMessage = "The selected country is not available for shipping in your current region. Please select a different country or change your region.";
2338
- }
2339
- else if (status_10 === 400) {
2340
- userMessage = "Invalid shipping address: ".concat(errorMessage);
2341
- }
2342
- throw new errors_1.ProviderAPIError(userMessage, 'medusa', status_10);
2343
- case 4: return [2 /*return*/];
2344
- }
2345
- });
2346
- });
2347
- };
2348
- /**
2349
- * Update cart billing address
2350
- * @param cartId - Cart ID
2351
- * @param address - Billing address details
2352
- * @returns Updated cart
2353
- *
2354
- * **Usage**: Call when billing address differs from shipping address
2355
- * Recommended to call BEFORE initiatePaymentSession
2356
- */
2357
- MedusaProvider.prototype.updateBillingAddress = function (cartId, address) {
2358
- return __awaiter(this, void 0, void 0, function () {
2359
- var rawCart, error_32, errorMessage, status_11, userMessage;
2360
- return __generator(this, function (_a) {
2361
- switch (_a.label) {
2362
- case 0:
2363
- this.logger.info('📫 [DEBUG] updateBillingAddress called', {
2364
- cartId: cartId,
2365
- city: address.city,
2366
- countryCode: address.countryCode,
2367
- });
2368
- _a.label = 1;
2369
- case 1:
2370
- _a.trys.push([1, 3, , 4]);
2371
- return [4 /*yield*/, this.sdk.store.cart.update(cartId, {
2372
- billing_address: {
2373
- first_name: address.firstName,
2374
- last_name: address.lastName,
2375
- address_1: address.address1,
2376
- address_2: address.address2 || '',
2377
- company: address.company || '',
2378
- city: address.city,
2379
- province: address.province,
2380
- postal_code: address.postalCode,
2381
- country_code: address.countryCode.toLowerCase(), // Medusa expects lowercase
2382
- phone: address.phone || '',
2383
- },
2384
- })];
2385
- case 2:
2386
- rawCart = (_a.sent()).cart;
2387
- this.logger.info('📫 [DEBUG] Billing address updated successfully', {
2388
- cartId: cartId,
2389
- hasBillingAddress: !!rawCart.billing_address,
2390
- });
2391
- return [2 /*return*/, (0, transforms_1.transformCart)(rawCart)];
2392
- case 3:
2393
- error_32 = _a.sent();
2394
- errorMessage = (0, errors_1.extractErrorMessage)(error_32);
2395
- status_11 = (error_32 === null || error_32 === void 0 ? void 0 : error_32.status) || (error_32 === null || error_32 === void 0 ? void 0 : error_32.statusCode);
2396
- this.logger.error('Failed to update billing address', {
2397
- cartId: cartId,
2398
- error: errorMessage,
2399
- status: status_11,
2400
- });
2401
- userMessage = errorMessage;
2402
- if (errorMessage.includes('is not within region')) {
2403
- userMessage = "The billing address country is not available in your current region. Please select a different country or change your region.";
2404
- }
2405
- else if (status_11 === 400) {
2406
- userMessage = "Invalid billing address: ".concat(errorMessage);
2407
- }
2408
- throw new errors_1.ProviderAPIError(userMessage, 'medusa', status_11);
2409
- case 4: return [2 /*return*/];
2410
- }
2411
- });
2412
- });
2413
- };
2414
- // ============================================
2415
- // Storefront / Multi-Tenant Operations
2416
- // ============================================
2417
- /**
2418
- * Get the current storefront/sales channel context.
2419
- *
2420
- * Validates that NEXT_PUBLIC_SALES_CHANNEL_ID is set and that the
2421
- * corresponding sales channel exists in the Medusa backend.
2422
- * Results are cached for 60 seconds.
2423
- *
2424
- * @returns StorefrontContext for the current storefront
2425
- * @throws {StorefrontConfigError} if NEXT_PUBLIC_SALES_CHANNEL_ID is missing or invalid
2426
- * @throws {ProviderAPIError} if the backend request fails
2427
- */
2428
- MedusaProvider.prototype.getStorefrontContext = function () {
2429
- return __awaiter(this, void 0, void 0, function () {
2430
- var channelId, context, errorMessage;
2431
- var _a;
2432
- return __generator(this, function (_b) {
2433
- // Check cache first
2434
- if (this.storefrontContextCache &&
2435
- Date.now() < this.storefrontContextCache.expiresAt) {
2436
- return [2 /*return*/, this.storefrontContextCache.context];
2437
- }
2438
- channelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
2439
- if (!channelId) {
2440
- throw new types_1.StorefrontConfigError('Medusa requires NEXT_PUBLIC_SALES_CHANNEL_ID to be configured. ' +
2441
- 'Each storefront must be linked to a sales channel. ' +
2442
- 'Set this in your .env file or environment variables.', 'medusa', 'NEXT_PUBLIC_SALES_CHANNEL_ID');
2443
- }
2444
- try {
2445
- context = {
2446
- id: channelId,
2447
- name: channelId, // Use ID as fallback name
2448
- platformType: 'medusa',
2449
- requiresProductScoping: true,
2450
- currencyCode: this.currencyCode,
2451
- metadata: {
2452
- // Store channel ID for use in API requests
2453
- channelId: channelId,
2454
- },
2455
- };
2456
- // Cache for 60 seconds
2457
- this.storefrontContextCache = {
2458
- context: context,
2459
- expiresAt: Date.now() + this.STOREFRONT_CONTEXT_CACHE_TTL,
2460
- };
2461
- this.logger.info('Storefront context initialized', {
2462
- id: context.id,
2463
- channelId: channelId,
2464
- });
2465
- return [2 /*return*/, context];
2466
- }
2467
- catch (error) {
2468
- if (error instanceof types_1.StorefrontConfigError)
2469
- throw error;
2470
- errorMessage = (0, errors_1.extractErrorMessage)(error);
2471
- throw new errors_1.ProviderAPIError("Failed to initialize storefront context: ".concat(errorMessage), 'medusa', (_a = error === null || error === void 0 ? void 0 : error.status) !== null && _a !== void 0 ? _a : 500);
2472
- }
2473
- return [2 /*return*/];
2474
- });
2475
- });
2476
- };
2477
- /**
2478
- * Medusa always requires storefront configuration for multi-tenant support.
2479
- */
2480
- MedusaProvider.prototype.isStorefrontRequired = function () {
2481
- return true;
2482
- };
2483
- return MedusaProvider;
2484
- }());
2485
- exports.MedusaProvider = MedusaProvider;