@cronvello/shop-sdk 0.1.0 → 0.2.2

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.
@@ -1,6 +1,6 @@
1
- import { S as ShopClientOptions, H as HeaderProvider, a as ShopClient } from './error-C-cJ6OgX.cjs';
2
- export { B as BaseUrlProvider, M as MaybePromise, b as SHOP_API_URL, c as ShopApiError, d as ShopAuthType, e as ShopConfigurationError, f as ShopRequestContext, g as ShopRequestOptions, h as ShopRoute, i as ShopRouteAuth, j as ShopRouteBody, k as ShopRouteInput, l as ShopRouteKey, m as ShopRouteMethod, n as ShopRouteParams, o as ShopRouteQuery, p as ShopRouteResponse, q as ShopRouteResponseData } from './error-C-cJ6OgX.cjs';
3
- import './index-CIpUb0vL.cjs';
1
+ import { S as ShopClientOptions, H as HeaderProvider, a as ShopClient } from './error-1WqH-FhJ.cjs';
2
+ export { B as BaseUrlProvider, C as CONTRACT_SHA256, M as MaybePromise, b as SHOP_API_URL, c as ShopApiError, d as ShopAuthType, e as ShopConfigurationError, f as ShopContractStatus, g as ShopDiagnoseOptions, h as ShopDiagnosis, i as ShopRequestContext, j as ShopRequestOptions, k as ShopRoute, l as ShopRouteAuth, m as ShopRouteBody, n as ShopRouteInput, o as ShopRouteKey, p as ShopRouteMethod, q as ShopRouteParams, r as ShopRouteQuery, s as ShopRouteResponse, t as ShopRouteResponseData, u as diagnoseShop } from './error-1WqH-FhJ.cjs';
3
+ import './index-DC6jGVkP.cjs';
4
4
 
5
5
  type ShopBrowserClientOptions = Omit<ShopClientOptions, "headers"> & {
6
6
  headers?: HeadersInit | HeaderProvider;
package/dist/browser.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as ShopClientOptions, H as HeaderProvider, a as ShopClient } from './error-BFzxyQkW.js';
2
- export { B as BaseUrlProvider, M as MaybePromise, b as SHOP_API_URL, c as ShopApiError, d as ShopAuthType, e as ShopConfigurationError, f as ShopRequestContext, g as ShopRequestOptions, h as ShopRoute, i as ShopRouteAuth, j as ShopRouteBody, k as ShopRouteInput, l as ShopRouteKey, m as ShopRouteMethod, n as ShopRouteParams, o as ShopRouteQuery, p as ShopRouteResponse, q as ShopRouteResponseData } from './error-BFzxyQkW.js';
3
- import './index-CIpUb0vL.js';
1
+ import { S as ShopClientOptions, H as HeaderProvider, a as ShopClient } from './error-D3Jrcd-j.js';
2
+ export { B as BaseUrlProvider, C as CONTRACT_SHA256, M as MaybePromise, b as SHOP_API_URL, c as ShopApiError, d as ShopAuthType, e as ShopConfigurationError, f as ShopContractStatus, g as ShopDiagnoseOptions, h as ShopDiagnosis, i as ShopRequestContext, j as ShopRequestOptions, k as ShopRoute, l as ShopRouteAuth, m as ShopRouteBody, n as ShopRouteInput, o as ShopRouteKey, p as ShopRouteMethod, q as ShopRouteParams, r as ShopRouteQuery, s as ShopRouteResponse, t as ShopRouteResponseData, u as diagnoseShop } from './error-D3Jrcd-j.js';
3
+ import './index-DC6jGVkP.js';
4
4
 
5
5
  type ShopBrowserClientOptions = Omit<ShopClientOptions, "headers"> & {
6
6
  headers?: HeadersInit | HeaderProvider;
package/dist/browser.js CHANGED
@@ -496,7 +496,7 @@ var apiRoutes_b2b = {
496
496
  meta: {
497
497
  tags: ["b2b"],
498
498
  summary: "Create B2B dynamic checkout session",
499
- description: "Creates a Stripe checkout session with dynamic price_data for trusted external apps. Supports mixed carts (one-time + recurring). Auth: Bearer BACKEND_TO_BACKEND_API_KEY.",
499
+ description: "Creates a Stripe checkout session with dynamic price_data for trusted external apps. Supports mixed carts (one-time + recurring). Auth: Bearer BACKEND_TO_BACKEND_API_KEY or App-Scoped API Key.",
500
500
  bodyContentType: "application/json",
501
501
  validated: { "params": false, "query": false, "body": true }
502
502
  },
@@ -1708,6 +1708,19 @@ var apiRoutes_external_apps = {
1708
1708
  },
1709
1709
  types: null
1710
1710
  },
1711
+ "external_apps_service_rotate_key": {
1712
+ method: "POST",
1713
+ path: "/external-apps/service/rotate-key/:appId",
1714
+ auth: { "type": "x_api_key_https" },
1715
+ meta: {
1716
+ tags: ["external-apps"],
1717
+ summary: "Rotate external app api key (B2B zero-downtime)",
1718
+ description: "Rotates the API key of an external app. The previous key remains valid during the specified gracePeriodHours (default: 2h) to prevent downtime during deployments. Authenticated via backend-to-backend API key.",
1719
+ bodyContentType: "application/json",
1720
+ validated: { "params": true, "query": true, "body": true }
1721
+ },
1722
+ types: null
1723
+ },
1711
1724
  "external_apps_service_delete": {
1712
1725
  method: "DELETE",
1713
1726
  path: "/external-apps/service/delete/:appId",
@@ -1727,7 +1740,7 @@ var apiRoutes_external_apps = {
1727
1740
  meta: {
1728
1741
  tags: ["external-apps"],
1729
1742
  summary: "Get external app registration status (B2B)",
1730
- description: "Returns registration status for an app identified by its string appId. Used by AMP to discover existing connections."
1743
+ description: "Returns registration status for an app identified by its string appId. Used by AMP to discover existing connections. Includes authMethod and, for OAuth apps, the oauth client_id we will present to that app plus a truncated SHA-256 fingerprint of the stored client secret, so the other side can prove a rotation actually landed here. Never the secret itself. Also reports the entitlement paths we have stored, because registration is an upsert: a caller that only wants to hand us new credentials must send these back unchanged, or it silently repoints where we fetch entitlements from."
1731
1744
  },
1732
1745
  types: null
1733
1746
  },
@@ -5270,7 +5283,7 @@ function createShopClient(options = {}) {
5270
5283
  const defaultTimeoutMs = options.timeoutMs ?? 3e4;
5271
5284
  const defaultRetries = options.retries ?? 2;
5272
5285
  const retryDelayMs = options.retryDelayMs ?? 250;
5273
- async function resolveBaseUrl() {
5286
+ async function resolveBaseUrl2() {
5274
5287
  const value = typeof baseUrl === "function" ? await baseUrl() : baseUrl;
5275
5288
  return normalizeBaseUrl(value);
5276
5289
  }
@@ -5292,7 +5305,7 @@ function createShopClient(options = {}) {
5292
5305
  const body = hasBody ? JSON.stringify(values.body) : void 0;
5293
5306
  const retries = Math.max(0, requestOptions.retries ?? defaultRetries);
5294
5307
  const canRetry = SAFE_METHODS.has(route.method) || requestOptions.retryUnsafe === true;
5295
- const resolvedBaseUrl = await resolveBaseUrl();
5308
+ const resolvedBaseUrl = await resolveBaseUrl2();
5296
5309
  for (let attempt = 0; ; attempt += 1) {
5297
5310
  const timeout = createRequestSignal(requestOptions.signal, requestOptions.timeoutMs ?? defaultTimeoutMs);
5298
5311
  try {
@@ -5369,6 +5382,102 @@ function createShopClient(options = {}) {
5369
5382
  return { baseUrl, request, requestText, requestRaw };
5370
5383
  }
5371
5384
 
5385
+ // src/contract-hash.ts
5386
+ var CONTRACT_SHA256 = "05f34929e71fb2fcb3a4c04707facca22ee46f8960a4cc47ce0a3f1a6df36056";
5387
+
5388
+ // src/client/diagnose.ts
5389
+ var SDK_VERSION = "0.2.2" ;
5390
+ async function resolveBaseUrl(options) {
5391
+ const provider = options.client?.baseUrl ?? options.baseUrl ?? SHOP_API_URL;
5392
+ const value = typeof provider === "function" ? await provider() : provider;
5393
+ return normalizeBaseUrl(value);
5394
+ }
5395
+ async function diagnoseShop(options = {}) {
5396
+ const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
5397
+ const baseUrl = await resolveBaseUrl(options);
5398
+ const doFetch = options.fetch ?? globalThis.fetch;
5399
+ const timeoutMs = options.timeoutMs ?? 5e3;
5400
+ const base = {
5401
+ ok: false,
5402
+ baseUrl,
5403
+ sdkVersion: SDK_VERSION,
5404
+ reachable: false,
5405
+ contract: { status: "unknown", sdk: CONTRACT_SHA256, live: null, files: null },
5406
+ problems: [],
5407
+ checkedAt
5408
+ };
5409
+ if (typeof doFetch !== "function") {
5410
+ return { ...base, problems: ["No fetch implementation available; pass `fetch` explicitly."] };
5411
+ }
5412
+ const controller = new AbortController();
5413
+ const onAbort = () => controller.abort(options.signal?.reason);
5414
+ options.signal?.addEventListener("abort", onAbort, { once: true });
5415
+ if (options.signal?.aborted) controller.abort(options.signal.reason);
5416
+ const timer = setTimeout(() => controller.abort(new Error(`Contract probe timed out after ${timeoutMs}ms`)), timeoutMs);
5417
+ let response;
5418
+ try {
5419
+ response = await doFetch(`${baseUrl}/health/contract`, {
5420
+ method: "GET",
5421
+ headers: { accept: "application/json" },
5422
+ signal: controller.signal
5423
+ });
5424
+ } catch (error) {
5425
+ const detail = error instanceof Error ? error.message : String(error);
5426
+ return { ...base, problems: [`node-shop at ${baseUrl} could not be reached: ${detail}`] };
5427
+ } finally {
5428
+ clearTimeout(timer);
5429
+ options.signal?.removeEventListener("abort", onAbort);
5430
+ }
5431
+ if (response.status === 404) {
5432
+ return {
5433
+ ...base,
5434
+ reachable: true,
5435
+ problems: [
5436
+ `node-shop at ${baseUrl} does not serve GET /health/contract, so the contract cannot be verified. Deploy a node-shop that includes it.`
5437
+ ]
5438
+ };
5439
+ }
5440
+ if (!response.ok) {
5441
+ return {
5442
+ ...base,
5443
+ reachable: true,
5444
+ problems: [`node-shop at ${baseUrl} answered ${response.status} for GET /health/contract; contract not verified.`]
5445
+ };
5446
+ }
5447
+ let body;
5448
+ try {
5449
+ body = await response.json();
5450
+ } catch {
5451
+ return { ...base, reachable: true, problems: [`node-shop at ${baseUrl} returned a non-JSON contract fingerprint.`] };
5452
+ }
5453
+ const live = typeof body.contractSha256 === "string" && body.contractSha256 ? body.contractSha256 : null;
5454
+ const files = typeof body.files === "number" ? body.files : null;
5455
+ if (!live) {
5456
+ return {
5457
+ ...base,
5458
+ reachable: true,
5459
+ contract: { ...base.contract, files },
5460
+ problems: [`node-shop at ${baseUrl} could not compute its own contract fingerprint; contract not verified.`]
5461
+ };
5462
+ }
5463
+ if (live !== CONTRACT_SHA256) {
5464
+ return {
5465
+ ...base,
5466
+ reachable: true,
5467
+ contract: { status: "drift", sdk: CONTRACT_SHA256, live, files },
5468
+ problems: [
5469
+ `Contract drift: node-shop at ${baseUrl} speaks ${live.slice(0, 12)}, @cronvello/shop-sdk ${SDK_VERSION} was built against ${CONTRACT_SHA256.slice(0, 12)}. Pin a newer SDK version, or deploy the node-shop the SDK was built from.`
5470
+ ]
5471
+ };
5472
+ }
5473
+ return {
5474
+ ...base,
5475
+ ok: true,
5476
+ reachable: true,
5477
+ contract: { status: "match", sdk: CONTRACT_SHA256, live, files }
5478
+ };
5479
+ }
5480
+
5372
5481
  // src/browser.ts
5373
5482
  function createShopBrowserClient(options = {}) {
5374
5483
  const configured = options.headers;
@@ -5385,6 +5494,6 @@ function createShopBrowserClient(options = {}) {
5385
5494
  });
5386
5495
  }
5387
5496
 
5388
- export { SHOP_API_URL, ShopApiError, ShopConfigurationError, createShopBrowserClient };
5497
+ export { CONTRACT_SHA256, SHOP_API_URL, ShopApiError, ShopConfigurationError, createShopBrowserClient, diagnoseShop };
5389
5498
  //# sourceMappingURL=browser.js.map
5390
5499
  //# sourceMappingURL=browser.js.map