@thorprovider/adapters 4.2.1 → 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.
- package/PROVIDER_IMPLEMENTATION_ANALYSIS.md +659 -0
- package/dist/index.d.mts +160 -1
- package/dist/index.d.ts +160 -1
- package/dist/index.js +384 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +384 -2
- package/dist/index.mjs.map +1 -1
- package/docs/RETRY_SOLUTION_SUMMARY.md +26 -11
- package/docs/authentication.md +115 -62
- package/docs/capabilities-system.md +4 -2
- package/docs/category-customization.md +37 -29
- package/docs/fetch-reliability-solution.md +127 -278
- package/docs/getting-started.md +43 -29
- package/docs/profile-management.md +68 -38
- package/docs/services-overview.md +4 -2
- package/package.json +1 -1
- package/quick-reference.md +33 -0
- package/src/providers/medusa/admin.test.ts +404 -0
- package/src/providers/medusa/admin.ts +442 -0
- package/src/providers/medusa/auth.test.ts +137 -0
- package/src/providers/medusa/auth.ts +96 -1
- package/src/providers/medusa/index.ts +21 -1
- package/src/providers/shopify/auth.ts +6 -0
- package/src/resilience/README.md +70 -48
- package/src/core/errors.js +0 -161
- package/src/core/fetch-utils.js +0 -240
- package/src/core/logger.js +0 -63
- package/src/metadata/channel-scope-validation.js +0 -136
- package/src/metadata/channel-scope.js +0 -174
- package/src/metadata/index.js +0 -31
- package/src/providers/medusa/auth.js +0 -601
- package/src/providers/medusa/index.js +0 -2485
- package/src/providers/medusa/payment.js +0 -265
- package/src/providers/medusa/transforms.js +0 -505
- package/src/types/capabilities.types.js +0 -141
- package/src/types/provider.js +0 -9
- 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;
|