@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.js CHANGED
@@ -67,8 +67,11 @@ __export(src_exports, {
67
67
  buildChannelScopeMetadata: () => buildChannelScopeMetadata,
68
68
  calculateDistance: () => calculateDistance,
69
69
  createBackendMetadataAdapter: () => createBackendMetadataAdapter,
70
+ createFetchWithRetry: () => createFetchWithRetry,
70
71
  createLogger: () => createLogger,
71
72
  createProvider: () => createProvider,
73
+ extractErrorMessage: () => extractErrorMessage,
74
+ fetchWithRetry: () => fetchWithRetry,
72
75
  filterByChannel: () => filterByChannel,
73
76
  filterGlobalOnly: () => filterGlobalOnly,
74
77
  geocodeAddress: () => geocodeAddress,
@@ -617,6 +620,9 @@ async function fetchWithRetry(url, init, retryConfig) {
617
620
  }
618
621
  throw lastError;
619
622
  }
623
+ function createFetchWithRetry(retryConfig) {
624
+ return (url, init) => fetchWithRetry(url, init, retryConfig);
625
+ }
620
626
 
621
627
  // src/resilience/circuit-breaker.ts
622
628
  var CircuitBreaker = class {
@@ -1823,17 +1829,11 @@ var MedusaAuthProvider = class {
1823
1829
  logger;
1824
1830
  authConfig;
1825
1831
  storageManager;
1826
- /** Medusa backend base URL — needed for raw fetch calls */
1827
- baseUrl;
1828
- /** Publishable API key — sent as x-publishable-api-key on store calls */
1829
- publishableKey;
1830
- constructor(sdk, authConfig, debug = false, baseUrl = "", publishableKey = "") {
1832
+ constructor(sdk, authConfig, debug = false) {
1831
1833
  this.sdk = sdk;
1832
1834
  this.authConfig = authConfig;
1833
1835
  this.logger = createLogger("MedusaAuthProvider", debug);
1834
1836
  this.storageManager = new AuthStorageManager(authConfig);
1835
- this.baseUrl = baseUrl;
1836
- this.publishableKey = publishableKey;
1837
1837
  this.logger.info("Medusa Auth Provider initialized", {
1838
1838
  method: authConfig.method,
1839
1839
  storage: authConfig.storage
@@ -1845,17 +1845,28 @@ var MedusaAuthProvider = class {
1845
1845
  async login(credentials) {
1846
1846
  this.logger.debug("login", { email: credentials.email });
1847
1847
  try {
1848
- const token = await this.sdk.auth.login("customer", "emailpass", {
1848
+ const loginResult = await this.sdk.auth.login("customer", "emailpass", {
1849
1849
  email: credentials.email,
1850
1850
  password: credentials.password
1851
1851
  });
1852
- if (typeof token !== "string") {
1853
- this.logger.warn("Authentication requires additional actions", token);
1854
- return {
1855
- requiresAction: true,
1856
- redirectUrl: token.location
1857
- };
1852
+ if (typeof loginResult !== "string") {
1853
+ if ("verification_required" in loginResult && loginResult.verification_required) {
1854
+ this.logger.warn("Authentication requires email verification", loginResult);
1855
+ return {
1856
+ requiresAction: true,
1857
+ token: loginResult.token
1858
+ };
1859
+ }
1860
+ if ("location" in loginResult) {
1861
+ this.logger.warn("Authentication requires additional actions", loginResult);
1862
+ return {
1863
+ requiresAction: true,
1864
+ redirectUrl: loginResult.location
1865
+ };
1866
+ }
1867
+ throw new Error("Unexpected login result type");
1858
1868
  }
1869
+ const token = loginResult;
1859
1870
  if (this.authConfig.method === "jwt") {
1860
1871
  await this.storageManager.setToken(token);
1861
1872
  }
@@ -1877,19 +1888,38 @@ var MedusaAuthProvider = class {
1877
1888
  async register(data) {
1878
1889
  this.logger.debug("register", { email: data.email });
1879
1890
  try {
1880
- const token = await this.sdk.auth.register("customer", "emailpass", {
1891
+ await this.sdk.auth.register("customer", "emailpass", {
1881
1892
  email: data.email,
1882
1893
  password: data.password
1883
1894
  });
1884
- if (typeof token !== "string") {
1885
- throw new Error("Registration returned non-string token");
1886
- }
1887
1895
  const { customer } = await this.sdk.store.customer.create({
1888
1896
  email: data.email,
1889
1897
  first_name: data.first_name,
1890
1898
  last_name: data.last_name,
1891
1899
  phone: data.phone
1892
1900
  });
1901
+ const loginResult = await this.sdk.auth.login("customer", "emailpass", {
1902
+ email: data.email,
1903
+ password: data.password
1904
+ });
1905
+ if (typeof loginResult !== "string") {
1906
+ if ("verification_required" in loginResult && loginResult.verification_required) {
1907
+ this.logger.warn("Registration requires email verification", loginResult);
1908
+ return {
1909
+ requiresAction: true,
1910
+ token: loginResult.token
1911
+ };
1912
+ }
1913
+ if ("location" in loginResult) {
1914
+ this.logger.warn("Registration requires additional actions", loginResult);
1915
+ return {
1916
+ requiresAction: true,
1917
+ redirectUrl: loginResult.location
1918
+ };
1919
+ }
1920
+ throw new Error("Unexpected login result after registration");
1921
+ }
1922
+ const token = loginResult;
1893
1923
  if (this.authConfig.method === "jwt") {
1894
1924
  await this.storageManager.setToken(token);
1895
1925
  }
@@ -2109,81 +2139,6 @@ var MedusaAuthProvider = class {
2109
2139
  void 0
2110
2140
  );
2111
2141
  }
2112
- // ========================================
2113
- // Multi-Tenant — Channel Link
2114
- // ========================================
2115
- /**
2116
- * Link the currently authenticated customer to the storefront's sales channel.
2117
- *
2118
- * Must be called immediately after a successful `login()` so the customer
2119
- * appears in the admin panel of the correct storefront channel.
2120
- *
2121
- * Implements `POST /store/thor/customers/me/channels`.
2122
- * Idempotent — returns `{ linked: false, reason: 'already_linked' }` when
2123
- * the link already exists.
2124
- *
2125
- * @throws {ProviderAPIError} When not authenticated (401) or channel cannot
2126
- * be resolved from the publishable key (400).
2127
- */
2128
- async linkCustomerToChannel() {
2129
- this.logger.debug("linkCustomerToChannel");
2130
- if (!this.baseUrl || !this.publishableKey) {
2131
- throw new ProviderAPIError(
2132
- "linkCustomerToChannel requires baseUrl and publishableKey to be set on the auth provider.",
2133
- "CONFIGURATION_ERROR",
2134
- void 0
2135
- );
2136
- }
2137
- const token = await this.storageManager.getToken();
2138
- const headers = {
2139
- "x-publishable-api-key": this.publishableKey,
2140
- "Content-Type": "application/json"
2141
- };
2142
- if (token) {
2143
- headers["Authorization"] = `Bearer ${token}`;
2144
- }
2145
- try {
2146
- const url = `${this.baseUrl}/store/thor/customers/me/channels`;
2147
- const response = await fetch(url, {
2148
- method: "POST",
2149
- headers
2150
- });
2151
- if (response.status === 401) {
2152
- throw new ProviderAPIError(
2153
- "linkCustomerToChannel: not authenticated. Call login() first.",
2154
- "NOT_AUTHENTICATED",
2155
- 401
2156
- );
2157
- }
2158
- if (response.status === 400) {
2159
- const body = await response.json().catch(() => ({}));
2160
- throw new ProviderAPIError(
2161
- `linkCustomerToChannel: could not resolve sales channel from publishable key. ${body?.message ?? ""}`.trim(),
2162
- "CHANNEL_RESOLUTION_FAILED",
2163
- 400
2164
- );
2165
- }
2166
- if (!response.ok) {
2167
- const body = await response.json().catch(() => ({}));
2168
- throw new ProviderAPIError(
2169
- `linkCustomerToChannel failed with status ${response.status}: ${body?.message ?? "Unknown error"}`,
2170
- "LINK_CHANNEL_FAILED",
2171
- response.status
2172
- );
2173
- }
2174
- const data = await response.json();
2175
- this.logger.info("Customer linked to channel", { linked: data.linked, reason: data.reason });
2176
- return data;
2177
- } catch (error) {
2178
- if (error instanceof ProviderAPIError) throw error;
2179
- this.logger.error("linkCustomerToChannel failed", error);
2180
- throw new ProviderAPIError(
2181
- `linkCustomerToChannel failed: ${error.message}`,
2182
- "LINK_CHANNEL_FAILED",
2183
- error
2184
- );
2185
- }
2186
- }
2187
2142
  };
2188
2143
 
2189
2144
  // src/providers/medusa/payment.ts
@@ -2326,290 +2281,6 @@ async function getPaymentMethods(sdk, options) {
2326
2281
  }
2327
2282
  }
2328
2283
 
2329
- // src/providers/medusa/admin.ts
2330
- var MedusaAdminClient = class {
2331
- baseUrl;
2332
- apiKey;
2333
- logger;
2334
- constructor(config) {
2335
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
2336
- this.apiKey = config.apiKey;
2337
- this.logger = createLogger("MedusaAdminClient", config.debug);
2338
- }
2339
- // -----------------------------------------------------------------------
2340
- // Private — HTTP helper
2341
- // -----------------------------------------------------------------------
2342
- async request(method, path, body) {
2343
- const url = `${this.baseUrl}${path}`;
2344
- this.logger.debug(`[admin] ${method} ${path}`);
2345
- const headers = {
2346
- "x-medusa-access-token": this.apiKey,
2347
- "Content-Type": "application/json"
2348
- };
2349
- const init = {
2350
- method,
2351
- headers,
2352
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
2353
- };
2354
- let response;
2355
- try {
2356
- response = await fetch(url, init);
2357
- } catch (networkError) {
2358
- throw new ProviderAPIError(
2359
- `[admin] Network error on ${method} ${path}: ${networkError.message}`,
2360
- "NETWORK_ERROR",
2361
- networkError
2362
- );
2363
- }
2364
- if (!response.ok) {
2365
- let message = `HTTP ${response.status}`;
2366
- try {
2367
- const json = await response.json();
2368
- message = json?.message ?? message;
2369
- } catch {
2370
- }
2371
- throw new ProviderAPIError(
2372
- `[admin] ${method} ${path} failed: ${message}`,
2373
- `ADMIN_API_${response.status}`,
2374
- response.status
2375
- );
2376
- }
2377
- return response.json();
2378
- }
2379
- // -----------------------------------------------------------------------
2380
- // 3.1 — Sales Channel: Customers
2381
- // -----------------------------------------------------------------------
2382
- /**
2383
- * Paginated list of customers linked to a sales channel.
2384
- *
2385
- * `GET /admin/thor/sales-channels/:id/customers`
2386
- */
2387
- async getChannelCustomers(salesChannelId, options = {}) {
2388
- const { limit = 20, offset = 0 } = options;
2389
- return this.request(
2390
- "GET",
2391
- `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`
2392
- );
2393
- }
2394
- // -----------------------------------------------------------------------
2395
- // 3.2 — Sales Channel: API Keys
2396
- // -----------------------------------------------------------------------
2397
- /**
2398
- * Publishable API keys associated with a sales channel.
2399
- *
2400
- * `GET /admin/thor/sales-channels/:id/api-keys`
2401
- */
2402
- async getChannelApiKeys(salesChannelId) {
2403
- return this.request(
2404
- "GET",
2405
- `/admin/thor/sales-channels/${salesChannelId}/api-keys`
2406
- );
2407
- }
2408
- // -----------------------------------------------------------------------
2409
- // 3.3 — Sales Channel: Categories
2410
- // -----------------------------------------------------------------------
2411
- /**
2412
- * Product categories assigned to a sales channel.
2413
- *
2414
- * `GET /admin/thor/sales-channels/:id/categories`
2415
- */
2416
- async getChannelCategories(salesChannelId, options = {}) {
2417
- const { limit = 20, offset = 0, include_descendants = false } = options;
2418
- const qs = new URLSearchParams({
2419
- limit: String(limit),
2420
- offset: String(offset),
2421
- include_descendants: String(include_descendants)
2422
- });
2423
- return this.request(
2424
- "GET",
2425
- `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`
2426
- );
2427
- }
2428
- // -----------------------------------------------------------------------
2429
- // 3.4 — Category: Sales Channels
2430
- // -----------------------------------------------------------------------
2431
- /**
2432
- * Sales channels to which a category is assigned.
2433
- *
2434
- * `GET /admin/thor/categories/:id/sales-channels`
2435
- */
2436
- async getCategorySalesChannels(categoryId) {
2437
- return this.request(
2438
- "GET",
2439
- `/admin/thor/categories/${categoryId}/sales-channels`
2440
- );
2441
- }
2442
- // -----------------------------------------------------------------------
2443
- // 3.5 — Category: Assign to Sales Channels
2444
- // -----------------------------------------------------------------------
2445
- /**
2446
- * Assign a category to one or more sales channels (idempotent).
2447
- *
2448
- * `POST /admin/thor/categories/:id/sales-channels`
2449
- */
2450
- async assignCategoryToChannels(categoryId, body) {
2451
- return this.request(
2452
- "POST",
2453
- `/admin/thor/categories/${categoryId}/sales-channels`,
2454
- body
2455
- );
2456
- }
2457
- // -----------------------------------------------------------------------
2458
- // 3.6 — Category: Unassign from Sales Channels
2459
- // -----------------------------------------------------------------------
2460
- /**
2461
- * Remove category assignment from one or more sales channels (idempotent).
2462
- *
2463
- * `DELETE /admin/thor/categories/:id/sales-channels`
2464
- */
2465
- async unassignCategoryFromChannels(categoryId, body) {
2466
- return this.request(
2467
- "DELETE",
2468
- `/admin/thor/categories/${categoryId}/sales-channels`,
2469
- body
2470
- );
2471
- }
2472
- // -----------------------------------------------------------------------
2473
- // 3.7 — Collection: Sales Channels
2474
- // -----------------------------------------------------------------------
2475
- /**
2476
- * Sales channels to which a collection is assigned.
2477
- *
2478
- * `GET /admin/thor/collections/:id/sales-channels`
2479
- */
2480
- async getCollectionSalesChannels(collectionId) {
2481
- return this.request(
2482
- "GET",
2483
- `/admin/thor/collections/${collectionId}/sales-channels`
2484
- );
2485
- }
2486
- // -----------------------------------------------------------------------
2487
- // 3.8 — Collection: Assign to Sales Channels
2488
- // -----------------------------------------------------------------------
2489
- /**
2490
- * Assign a collection to one or more sales channels (idempotent).
2491
- *
2492
- * `POST /admin/thor/collections/:id/sales-channels`
2493
- */
2494
- async assignCollectionToChannels(collectionId, body) {
2495
- return this.request(
2496
- "POST",
2497
- `/admin/thor/collections/${collectionId}/sales-channels`,
2498
- body
2499
- );
2500
- }
2501
- // -----------------------------------------------------------------------
2502
- // 3.9 — Collection: Unassign from Sales Channels
2503
- // -----------------------------------------------------------------------
2504
- /**
2505
- * Remove collection assignment from one or more sales channels (idempotent).
2506
- *
2507
- * `DELETE /admin/thor/collections/:id/sales-channels`
2508
- */
2509
- async unassignCollectionFromChannels(collectionId, body) {
2510
- return this.request(
2511
- "DELETE",
2512
- `/admin/thor/collections/${collectionId}/sales-channels`,
2513
- body
2514
- );
2515
- }
2516
- // -----------------------------------------------------------------------
2517
- // 3.10 — Storefront Config: Read
2518
- // -----------------------------------------------------------------------
2519
- /**
2520
- * Read the visual storefront configuration for a channel.
2521
- * `:id` is the `sales_channel_id`.
2522
- *
2523
- * `GET /admin/thor/storefront-config/:id`
2524
- */
2525
- async getStorefrontConfig(salesChannelId) {
2526
- return this.request(
2527
- "GET",
2528
- `/admin/thor/storefront-config/${salesChannelId}`
2529
- );
2530
- }
2531
- // -----------------------------------------------------------------------
2532
- // 3.11 — Storefront Config: Update
2533
- // -----------------------------------------------------------------------
2534
- /**
2535
- * Update the visual storefront configuration for a channel.
2536
- * Triggers the `storefront_config.updated` event → ISR webhook.
2537
- *
2538
- * `PUT /admin/thor/storefront-config/:id`
2539
- */
2540
- async updateStorefrontConfig(salesChannelId, body) {
2541
- return this.request(
2542
- "PUT",
2543
- `/admin/thor/storefront-config/${salesChannelId}`,
2544
- body
2545
- );
2546
- }
2547
- // -----------------------------------------------------------------------
2548
- // 3.12 — Site Designer Config: Read
2549
- // -----------------------------------------------------------------------
2550
- /**
2551
- * Read the active Site Designer configuration for a channel, including the
2552
- * last 10 history entries.
2553
- *
2554
- * `GET /admin/thor/site-config/:sales_channel_id`
2555
- */
2556
- async getSiteConfig(salesChannelId) {
2557
- return this.request(
2558
- "GET",
2559
- `/admin/thor/site-config/${salesChannelId}`
2560
- );
2561
- }
2562
- // -----------------------------------------------------------------------
2563
- // 3.13 — Site Designer Config: Update
2564
- // -----------------------------------------------------------------------
2565
- /**
2566
- * Update the Site Designer configuration for a channel.
2567
- * Creates a new history entry on every PUT.
2568
- *
2569
- * `PUT /admin/thor/site-config/:sales_channel_id`
2570
- */
2571
- async updateSiteConfig(salesChannelId, body) {
2572
- return this.request(
2573
- "PUT",
2574
- `/admin/thor/site-config/${salesChannelId}`,
2575
- body
2576
- );
2577
- }
2578
- // -----------------------------------------------------------------------
2579
- // 3.14 — Site Designer Config: History
2580
- // -----------------------------------------------------------------------
2581
- /**
2582
- * Full paginated history of Site Designer versions for a channel.
2583
- * Entries are immutable — they are never deleted.
2584
- *
2585
- * `GET /admin/thor/site-config/:sales_channel_id/history`
2586
- */
2587
- async getSiteConfigHistory(salesChannelId, options = {}) {
2588
- const { limit = 20, offset = 0 } = options;
2589
- return this.request(
2590
- "GET",
2591
- `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`
2592
- );
2593
- }
2594
- // -----------------------------------------------------------------------
2595
- // 3.15 — Site Designer Config: Restore
2596
- // -----------------------------------------------------------------------
2597
- /**
2598
- * Restore a previous Site Designer version.
2599
- * Internally runs the update workflow with the stored config of the target
2600
- * version — this creates a **new** history entry and does NOT mutate past
2601
- * entries.
2602
- *
2603
- * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`
2604
- */
2605
- async restoreSiteConfig(salesChannelId, version) {
2606
- return this.request(
2607
- "POST",
2608
- `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`
2609
- );
2610
- }
2611
- };
2612
-
2613
2284
  // src/providers/medusa/index.ts
2614
2285
  var MEDUSA_CART_RETRIEVE_FIELDS = "+items,+items.variant,+items.variant.product,+items.variant.product.thumbnail,+items.variant.options,+items.variant.options.option";
2615
2286
  var MedusaProvider = class {
@@ -2644,18 +2315,6 @@ var MedusaProvider = class {
2644
2315
  * Only created when adminConfig.apiKey is provided.
2645
2316
  */
2646
2317
  sdkAdmin;
2647
- /**
2648
- * Admin client for Thor multi-tenant endpoints (`/admin/thor/`).
2649
- * Available when `adminConfig.apiKey` is provided.
2650
- *
2651
- * @example
2652
- * ```typescript
2653
- * const { customers } = await commerce.admin.getChannelCustomers('sc_01JXXXXX');
2654
- * const { api_keys } = await commerce.admin.getChannelApiKeys('sc_01JXXXXX');
2655
- * await commerce.admin.updateStorefrontConfig('sc_01JXXXXX', { theme_accent_color: '#EF4444', ... });
2656
- * ```
2657
- */
2658
- admin;
2659
2318
  /** Cached distinct product status values — rarely changes, cached for process lifetime */
2660
2319
  _cachedProductStatuses = null;
2661
2320
  /**
@@ -2726,15 +2385,10 @@ var MedusaProvider = class {
2726
2385
  debug: config.debug ?? false
2727
2386
  // No publishableKey or auth config: this instance is admin-only, no JWT needed
2728
2387
  });
2729
- this.admin = new MedusaAdminClient({
2730
- baseUrl: config.baseUrl,
2731
- apiKey: config.adminConfig.apiKey,
2732
- debug: config.debug
2733
- });
2734
2388
  this.logger.info("[Admin Auth] Dedicated admin SDK instance created with API key");
2735
2389
  }
2736
2390
  if (config.auth) {
2737
- this.auth = new MedusaAuthProvider(this.sdk, config.auth, config.debug, config.baseUrl, config.publishableKey);
2391
+ this.auth = new MedusaAuthProvider(this.sdk, config.auth, config.debug);
2738
2392
  this.logger.info("Auth provider initialized");
2739
2393
  }
2740
2394
  this._capabilitiesPromise = this._fetchCapabilities();
@@ -10590,8 +10244,11 @@ function isProviderType(provider, type) {
10590
10244
  buildChannelScopeMetadata,
10591
10245
  calculateDistance,
10592
10246
  createBackendMetadataAdapter,
10247
+ createFetchWithRetry,
10593
10248
  createLogger,
10594
10249
  createProvider,
10250
+ extractErrorMessage,
10251
+ fetchWithRetry,
10595
10252
  filterByChannel,
10596
10253
  filterGlobalOnly,
10597
10254
  geocodeAddress,