@thorprovider/adapters 4.3.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -523,6 +523,9 @@ async function fetchWithRetry(url, init, retryConfig) {
523
523
  }
524
524
  throw lastError;
525
525
  }
526
+ function createFetchWithRetry(retryConfig) {
527
+ return (url, init) => fetchWithRetry(url, init, retryConfig);
528
+ }
526
529
 
527
530
  // src/resilience/circuit-breaker.ts
528
531
  var CircuitBreaker = class {
@@ -1729,17 +1732,11 @@ var MedusaAuthProvider = class {
1729
1732
  logger;
1730
1733
  authConfig;
1731
1734
  storageManager;
1732
- /** Medusa backend base URL — needed for raw fetch calls */
1733
- baseUrl;
1734
- /** Publishable API key — sent as x-publishable-api-key on store calls */
1735
- publishableKey;
1736
- constructor(sdk, authConfig, debug = false, baseUrl = "", publishableKey = "") {
1735
+ constructor(sdk, authConfig, debug = false) {
1737
1736
  this.sdk = sdk;
1738
1737
  this.authConfig = authConfig;
1739
1738
  this.logger = createLogger("MedusaAuthProvider", debug);
1740
1739
  this.storageManager = new AuthStorageManager(authConfig);
1741
- this.baseUrl = baseUrl;
1742
- this.publishableKey = publishableKey;
1743
1740
  this.logger.info("Medusa Auth Provider initialized", {
1744
1741
  method: authConfig.method,
1745
1742
  storage: authConfig.storage
@@ -1751,17 +1748,28 @@ var MedusaAuthProvider = class {
1751
1748
  async login(credentials) {
1752
1749
  this.logger.debug("login", { email: credentials.email });
1753
1750
  try {
1754
- const token = await this.sdk.auth.login("customer", "emailpass", {
1751
+ const loginResult = await this.sdk.auth.login("customer", "emailpass", {
1755
1752
  email: credentials.email,
1756
1753
  password: credentials.password
1757
1754
  });
1758
- if (typeof token !== "string") {
1759
- this.logger.warn("Authentication requires additional actions", token);
1760
- return {
1761
- requiresAction: true,
1762
- redirectUrl: token.location
1763
- };
1755
+ if (typeof loginResult !== "string") {
1756
+ if ("verification_required" in loginResult && loginResult.verification_required) {
1757
+ this.logger.warn("Authentication requires email verification", loginResult);
1758
+ return {
1759
+ requiresAction: true,
1760
+ token: loginResult.token
1761
+ };
1762
+ }
1763
+ if ("location" in loginResult) {
1764
+ this.logger.warn("Authentication requires additional actions", loginResult);
1765
+ return {
1766
+ requiresAction: true,
1767
+ redirectUrl: loginResult.location
1768
+ };
1769
+ }
1770
+ throw new Error("Unexpected login result type");
1764
1771
  }
1772
+ const token = loginResult;
1765
1773
  if (this.authConfig.method === "jwt") {
1766
1774
  await this.storageManager.setToken(token);
1767
1775
  }
@@ -1783,19 +1791,38 @@ var MedusaAuthProvider = class {
1783
1791
  async register(data) {
1784
1792
  this.logger.debug("register", { email: data.email });
1785
1793
  try {
1786
- const token = await this.sdk.auth.register("customer", "emailpass", {
1794
+ await this.sdk.auth.register("customer", "emailpass", {
1787
1795
  email: data.email,
1788
1796
  password: data.password
1789
1797
  });
1790
- if (typeof token !== "string") {
1791
- throw new Error("Registration returned non-string token");
1792
- }
1793
1798
  const { customer } = await this.sdk.store.customer.create({
1794
1799
  email: data.email,
1795
1800
  first_name: data.first_name,
1796
1801
  last_name: data.last_name,
1797
1802
  phone: data.phone
1798
1803
  });
1804
+ const loginResult = await this.sdk.auth.login("customer", "emailpass", {
1805
+ email: data.email,
1806
+ password: data.password
1807
+ });
1808
+ if (typeof loginResult !== "string") {
1809
+ if ("verification_required" in loginResult && loginResult.verification_required) {
1810
+ this.logger.warn("Registration requires email verification", loginResult);
1811
+ return {
1812
+ requiresAction: true,
1813
+ token: loginResult.token
1814
+ };
1815
+ }
1816
+ if ("location" in loginResult) {
1817
+ this.logger.warn("Registration requires additional actions", loginResult);
1818
+ return {
1819
+ requiresAction: true,
1820
+ redirectUrl: loginResult.location
1821
+ };
1822
+ }
1823
+ throw new Error("Unexpected login result after registration");
1824
+ }
1825
+ const token = loginResult;
1799
1826
  if (this.authConfig.method === "jwt") {
1800
1827
  await this.storageManager.setToken(token);
1801
1828
  }
@@ -2015,81 +2042,6 @@ var MedusaAuthProvider = class {
2015
2042
  void 0
2016
2043
  );
2017
2044
  }
2018
- // ========================================
2019
- // Multi-Tenant — Channel Link
2020
- // ========================================
2021
- /**
2022
- * Link the currently authenticated customer to the storefront's sales channel.
2023
- *
2024
- * Must be called immediately after a successful `login()` so the customer
2025
- * appears in the admin panel of the correct storefront channel.
2026
- *
2027
- * Implements `POST /store/thor/customers/me/channels`.
2028
- * Idempotent — returns `{ linked: false, reason: 'already_linked' }` when
2029
- * the link already exists.
2030
- *
2031
- * @throws {ProviderAPIError} When not authenticated (401) or channel cannot
2032
- * be resolved from the publishable key (400).
2033
- */
2034
- async linkCustomerToChannel() {
2035
- this.logger.debug("linkCustomerToChannel");
2036
- if (!this.baseUrl || !this.publishableKey) {
2037
- throw new ProviderAPIError(
2038
- "linkCustomerToChannel requires baseUrl and publishableKey to be set on the auth provider.",
2039
- "CONFIGURATION_ERROR",
2040
- void 0
2041
- );
2042
- }
2043
- const token = await this.storageManager.getToken();
2044
- const headers = {
2045
- "x-publishable-api-key": this.publishableKey,
2046
- "Content-Type": "application/json"
2047
- };
2048
- if (token) {
2049
- headers["Authorization"] = `Bearer ${token}`;
2050
- }
2051
- try {
2052
- const url = `${this.baseUrl}/store/thor/customers/me/channels`;
2053
- const response = await fetch(url, {
2054
- method: "POST",
2055
- headers
2056
- });
2057
- if (response.status === 401) {
2058
- throw new ProviderAPIError(
2059
- "linkCustomerToChannel: not authenticated. Call login() first.",
2060
- "NOT_AUTHENTICATED",
2061
- 401
2062
- );
2063
- }
2064
- if (response.status === 400) {
2065
- const body = await response.json().catch(() => ({}));
2066
- throw new ProviderAPIError(
2067
- `linkCustomerToChannel: could not resolve sales channel from publishable key. ${body?.message ?? ""}`.trim(),
2068
- "CHANNEL_RESOLUTION_FAILED",
2069
- 400
2070
- );
2071
- }
2072
- if (!response.ok) {
2073
- const body = await response.json().catch(() => ({}));
2074
- throw new ProviderAPIError(
2075
- `linkCustomerToChannel failed with status ${response.status}: ${body?.message ?? "Unknown error"}`,
2076
- "LINK_CHANNEL_FAILED",
2077
- response.status
2078
- );
2079
- }
2080
- const data = await response.json();
2081
- this.logger.info("Customer linked to channel", { linked: data.linked, reason: data.reason });
2082
- return data;
2083
- } catch (error) {
2084
- if (error instanceof ProviderAPIError) throw error;
2085
- this.logger.error("linkCustomerToChannel failed", error);
2086
- throw new ProviderAPIError(
2087
- `linkCustomerToChannel failed: ${error.message}`,
2088
- "LINK_CHANNEL_FAILED",
2089
- error
2090
- );
2091
- }
2092
- }
2093
2045
  };
2094
2046
 
2095
2047
  // src/providers/medusa/payment.ts
@@ -2232,290 +2184,6 @@ async function getPaymentMethods(sdk, options) {
2232
2184
  }
2233
2185
  }
2234
2186
 
2235
- // src/providers/medusa/admin.ts
2236
- var MedusaAdminClient = class {
2237
- baseUrl;
2238
- apiKey;
2239
- logger;
2240
- constructor(config) {
2241
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
2242
- this.apiKey = config.apiKey;
2243
- this.logger = createLogger("MedusaAdminClient", config.debug);
2244
- }
2245
- // -----------------------------------------------------------------------
2246
- // Private — HTTP helper
2247
- // -----------------------------------------------------------------------
2248
- async request(method, path, body) {
2249
- const url = `${this.baseUrl}${path}`;
2250
- this.logger.debug(`[admin] ${method} ${path}`);
2251
- const headers = {
2252
- "x-medusa-access-token": this.apiKey,
2253
- "Content-Type": "application/json"
2254
- };
2255
- const init = {
2256
- method,
2257
- headers,
2258
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
2259
- };
2260
- let response;
2261
- try {
2262
- response = await fetch(url, init);
2263
- } catch (networkError) {
2264
- throw new ProviderAPIError(
2265
- `[admin] Network error on ${method} ${path}: ${networkError.message}`,
2266
- "NETWORK_ERROR",
2267
- networkError
2268
- );
2269
- }
2270
- if (!response.ok) {
2271
- let message = `HTTP ${response.status}`;
2272
- try {
2273
- const json = await response.json();
2274
- message = json?.message ?? message;
2275
- } catch {
2276
- }
2277
- throw new ProviderAPIError(
2278
- `[admin] ${method} ${path} failed: ${message}`,
2279
- `ADMIN_API_${response.status}`,
2280
- response.status
2281
- );
2282
- }
2283
- return response.json();
2284
- }
2285
- // -----------------------------------------------------------------------
2286
- // 3.1 — Sales Channel: Customers
2287
- // -----------------------------------------------------------------------
2288
- /**
2289
- * Paginated list of customers linked to a sales channel.
2290
- *
2291
- * `GET /admin/thor/sales-channels/:id/customers`
2292
- */
2293
- async getChannelCustomers(salesChannelId, options = {}) {
2294
- const { limit = 20, offset = 0 } = options;
2295
- return this.request(
2296
- "GET",
2297
- `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`
2298
- );
2299
- }
2300
- // -----------------------------------------------------------------------
2301
- // 3.2 — Sales Channel: API Keys
2302
- // -----------------------------------------------------------------------
2303
- /**
2304
- * Publishable API keys associated with a sales channel.
2305
- *
2306
- * `GET /admin/thor/sales-channels/:id/api-keys`
2307
- */
2308
- async getChannelApiKeys(salesChannelId) {
2309
- return this.request(
2310
- "GET",
2311
- `/admin/thor/sales-channels/${salesChannelId}/api-keys`
2312
- );
2313
- }
2314
- // -----------------------------------------------------------------------
2315
- // 3.3 — Sales Channel: Categories
2316
- // -----------------------------------------------------------------------
2317
- /**
2318
- * Product categories assigned to a sales channel.
2319
- *
2320
- * `GET /admin/thor/sales-channels/:id/categories`
2321
- */
2322
- async getChannelCategories(salesChannelId, options = {}) {
2323
- const { limit = 20, offset = 0, include_descendants = false } = options;
2324
- const qs = new URLSearchParams({
2325
- limit: String(limit),
2326
- offset: String(offset),
2327
- include_descendants: String(include_descendants)
2328
- });
2329
- return this.request(
2330
- "GET",
2331
- `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`
2332
- );
2333
- }
2334
- // -----------------------------------------------------------------------
2335
- // 3.4 — Category: Sales Channels
2336
- // -----------------------------------------------------------------------
2337
- /**
2338
- * Sales channels to which a category is assigned.
2339
- *
2340
- * `GET /admin/thor/categories/:id/sales-channels`
2341
- */
2342
- async getCategorySalesChannels(categoryId) {
2343
- return this.request(
2344
- "GET",
2345
- `/admin/thor/categories/${categoryId}/sales-channels`
2346
- );
2347
- }
2348
- // -----------------------------------------------------------------------
2349
- // 3.5 — Category: Assign to Sales Channels
2350
- // -----------------------------------------------------------------------
2351
- /**
2352
- * Assign a category to one or more sales channels (idempotent).
2353
- *
2354
- * `POST /admin/thor/categories/:id/sales-channels`
2355
- */
2356
- async assignCategoryToChannels(categoryId, body) {
2357
- return this.request(
2358
- "POST",
2359
- `/admin/thor/categories/${categoryId}/sales-channels`,
2360
- body
2361
- );
2362
- }
2363
- // -----------------------------------------------------------------------
2364
- // 3.6 — Category: Unassign from Sales Channels
2365
- // -----------------------------------------------------------------------
2366
- /**
2367
- * Remove category assignment from one or more sales channels (idempotent).
2368
- *
2369
- * `DELETE /admin/thor/categories/:id/sales-channels`
2370
- */
2371
- async unassignCategoryFromChannels(categoryId, body) {
2372
- return this.request(
2373
- "DELETE",
2374
- `/admin/thor/categories/${categoryId}/sales-channels`,
2375
- body
2376
- );
2377
- }
2378
- // -----------------------------------------------------------------------
2379
- // 3.7 — Collection: Sales Channels
2380
- // -----------------------------------------------------------------------
2381
- /**
2382
- * Sales channels to which a collection is assigned.
2383
- *
2384
- * `GET /admin/thor/collections/:id/sales-channels`
2385
- */
2386
- async getCollectionSalesChannels(collectionId) {
2387
- return this.request(
2388
- "GET",
2389
- `/admin/thor/collections/${collectionId}/sales-channels`
2390
- );
2391
- }
2392
- // -----------------------------------------------------------------------
2393
- // 3.8 — Collection: Assign to Sales Channels
2394
- // -----------------------------------------------------------------------
2395
- /**
2396
- * Assign a collection to one or more sales channels (idempotent).
2397
- *
2398
- * `POST /admin/thor/collections/:id/sales-channels`
2399
- */
2400
- async assignCollectionToChannels(collectionId, body) {
2401
- return this.request(
2402
- "POST",
2403
- `/admin/thor/collections/${collectionId}/sales-channels`,
2404
- body
2405
- );
2406
- }
2407
- // -----------------------------------------------------------------------
2408
- // 3.9 — Collection: Unassign from Sales Channels
2409
- // -----------------------------------------------------------------------
2410
- /**
2411
- * Remove collection assignment from one or more sales channels (idempotent).
2412
- *
2413
- * `DELETE /admin/thor/collections/:id/sales-channels`
2414
- */
2415
- async unassignCollectionFromChannels(collectionId, body) {
2416
- return this.request(
2417
- "DELETE",
2418
- `/admin/thor/collections/${collectionId}/sales-channels`,
2419
- body
2420
- );
2421
- }
2422
- // -----------------------------------------------------------------------
2423
- // 3.10 — Storefront Config: Read
2424
- // -----------------------------------------------------------------------
2425
- /**
2426
- * Read the visual storefront configuration for a channel.
2427
- * `:id` is the `sales_channel_id`.
2428
- *
2429
- * `GET /admin/thor/storefront-config/:id`
2430
- */
2431
- async getStorefrontConfig(salesChannelId) {
2432
- return this.request(
2433
- "GET",
2434
- `/admin/thor/storefront-config/${salesChannelId}`
2435
- );
2436
- }
2437
- // -----------------------------------------------------------------------
2438
- // 3.11 — Storefront Config: Update
2439
- // -----------------------------------------------------------------------
2440
- /**
2441
- * Update the visual storefront configuration for a channel.
2442
- * Triggers the `storefront_config.updated` event → ISR webhook.
2443
- *
2444
- * `PUT /admin/thor/storefront-config/:id`
2445
- */
2446
- async updateStorefrontConfig(salesChannelId, body) {
2447
- return this.request(
2448
- "PUT",
2449
- `/admin/thor/storefront-config/${salesChannelId}`,
2450
- body
2451
- );
2452
- }
2453
- // -----------------------------------------------------------------------
2454
- // 3.12 — Site Designer Config: Read
2455
- // -----------------------------------------------------------------------
2456
- /**
2457
- * Read the active Site Designer configuration for a channel, including the
2458
- * last 10 history entries.
2459
- *
2460
- * `GET /admin/thor/site-config/:sales_channel_id`
2461
- */
2462
- async getSiteConfig(salesChannelId) {
2463
- return this.request(
2464
- "GET",
2465
- `/admin/thor/site-config/${salesChannelId}`
2466
- );
2467
- }
2468
- // -----------------------------------------------------------------------
2469
- // 3.13 — Site Designer Config: Update
2470
- // -----------------------------------------------------------------------
2471
- /**
2472
- * Update the Site Designer configuration for a channel.
2473
- * Creates a new history entry on every PUT.
2474
- *
2475
- * `PUT /admin/thor/site-config/:sales_channel_id`
2476
- */
2477
- async updateSiteConfig(salesChannelId, body) {
2478
- return this.request(
2479
- "PUT",
2480
- `/admin/thor/site-config/${salesChannelId}`,
2481
- body
2482
- );
2483
- }
2484
- // -----------------------------------------------------------------------
2485
- // 3.14 — Site Designer Config: History
2486
- // -----------------------------------------------------------------------
2487
- /**
2488
- * Full paginated history of Site Designer versions for a channel.
2489
- * Entries are immutable — they are never deleted.
2490
- *
2491
- * `GET /admin/thor/site-config/:sales_channel_id/history`
2492
- */
2493
- async getSiteConfigHistory(salesChannelId, options = {}) {
2494
- const { limit = 20, offset = 0 } = options;
2495
- return this.request(
2496
- "GET",
2497
- `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`
2498
- );
2499
- }
2500
- // -----------------------------------------------------------------------
2501
- // 3.15 — Site Designer Config: Restore
2502
- // -----------------------------------------------------------------------
2503
- /**
2504
- * Restore a previous Site Designer version.
2505
- * Internally runs the update workflow with the stored config of the target
2506
- * version — this creates a **new** history entry and does NOT mutate past
2507
- * entries.
2508
- *
2509
- * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`
2510
- */
2511
- async restoreSiteConfig(salesChannelId, version) {
2512
- return this.request(
2513
- "POST",
2514
- `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`
2515
- );
2516
- }
2517
- };
2518
-
2519
2187
  // src/providers/medusa/index.ts
2520
2188
  var MEDUSA_CART_RETRIEVE_FIELDS = "+items,+items.variant,+items.variant.product,+items.variant.product.thumbnail,+items.variant.options,+items.variant.options.option";
2521
2189
  var MedusaProvider = class {
@@ -2550,18 +2218,6 @@ var MedusaProvider = class {
2550
2218
  * Only created when adminConfig.apiKey is provided.
2551
2219
  */
2552
2220
  sdkAdmin;
2553
- /**
2554
- * Admin client for Thor multi-tenant endpoints (`/admin/thor/`).
2555
- * Available when `adminConfig.apiKey` is provided.
2556
- *
2557
- * @example
2558
- * ```typescript
2559
- * const { customers } = await commerce.admin.getChannelCustomers('sc_01JXXXXX');
2560
- * const { api_keys } = await commerce.admin.getChannelApiKeys('sc_01JXXXXX');
2561
- * await commerce.admin.updateStorefrontConfig('sc_01JXXXXX', { theme_accent_color: '#EF4444', ... });
2562
- * ```
2563
- */
2564
- admin;
2565
2221
  /** Cached distinct product status values — rarely changes, cached for process lifetime */
2566
2222
  _cachedProductStatuses = null;
2567
2223
  /**
@@ -2632,15 +2288,10 @@ var MedusaProvider = class {
2632
2288
  debug: config.debug ?? false
2633
2289
  // No publishableKey or auth config: this instance is admin-only, no JWT needed
2634
2290
  });
2635
- this.admin = new MedusaAdminClient({
2636
- baseUrl: config.baseUrl,
2637
- apiKey: config.adminConfig.apiKey,
2638
- debug: config.debug
2639
- });
2640
2291
  this.logger.info("[Admin Auth] Dedicated admin SDK instance created with API key");
2641
2292
  }
2642
2293
  if (config.auth) {
2643
- this.auth = new MedusaAuthProvider(this.sdk, config.auth, config.debug, config.baseUrl, config.publishableKey);
2294
+ this.auth = new MedusaAuthProvider(this.sdk, config.auth, config.debug);
2644
2295
  this.logger.info("Auth provider initialized");
2645
2296
  }
2646
2297
  this._capabilitiesPromise = this._fetchCapabilities();
@@ -10495,8 +10146,11 @@ export {
10495
10146
  buildChannelScopeMetadata,
10496
10147
  calculateDistance,
10497
10148
  createBackendMetadataAdapter,
10149
+ createFetchWithRetry,
10498
10150
  createLogger,
10499
10151
  createProvider,
10152
+ extractErrorMessage,
10153
+ fetchWithRetry,
10500
10154
  filterByChannel,
10501
10155
  filterGlobalOnly,
10502
10156
  geocodeAddress,