@doswiftly/storefront-sdk 22.1.0 → 22.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.
@@ -432,6 +432,15 @@ export const OrderPaymentStatus = {
432
432
  Unpaid: 'UNPAID',
433
433
  Voided: 'VOIDED'
434
434
  };
435
+ export const PaymentAcknowledgementDocumentKind = {
436
+ InformationObligation: 'INFORMATION_OBLIGATION',
437
+ PrivacyPolicy: 'PRIVACY_POLICY',
438
+ Terms: 'TERMS'
439
+ };
440
+ export const PaymentAcknowledgementEnforcement = {
441
+ GatewayFallback: 'GATEWAY_FALLBACK',
442
+ StorefrontRequired: 'STOREFRONT_REQUIRED'
443
+ };
435
444
  export const PaymentInitiationFlow = {
436
445
  InstantDirect: 'INSTANT_DIRECT',
437
446
  OfflineManual: 'OFFLINE_MANUAL',
@@ -41,12 +41,22 @@ export interface ServerClientOptions extends Omit<StorefrontClientConfig, 'middl
41
41
  */
42
42
  middleware?: Middleware[];
43
43
  /**
44
- * OPTIONAL override for the buyer-IP source. Forwarded-IP signing is
45
- * auto-configured: by default the SDK reads the request's `cf-connecting-ip`
46
- * via `next/headers` (a server-rendered storefront would otherwise collapse
47
- * every buyer onto its own server IP for rate limiting). Provide this only for
48
- * non-Next server runtimes where `next/headers` is unavailable. May be async.
44
+ * Buyer-IP source that ENABLES forwarded-IP signing (opt-in). The forwarded-IP
45
+ * middleware is wired ONLY when this is provided — without it the client never
46
+ * reads the buyer IP and never signs (a fully static-safe, inert pass-through).
47
+ *
48
+ * Reading the buyer IP needs a request-scoped dynamic API (e.g. `next/headers`
49
+ * `headers()`), which is ILLEGAL in statically-generated / ISR routes — calling it
50
+ * there crashes the page ("static to dynamic at runtime"). So provide this ONLY on
51
+ * routes that are already dynamic (per-request rendered). A server-rendered
52
+ * storefront otherwise collapses every buyer onto its own server IP for rate
53
+ * limiting; forwarding the real IP restores per-buyer limits. May be async.
49
54
  * Server-side only.
55
+ *
56
+ * @example
57
+ * // ONLY on a dynamic route — `headers()` forces dynamic rendering:
58
+ * import { headers } from 'next/headers';
59
+ * getStorefrontClient({ apiUrl, shopSlug, getBuyerIp: async () => (await headers()).get('cf-connecting-ip') });
50
60
  */
51
61
  getBuyerIp?: () => string | null | undefined | Promise<string | null | undefined>;
52
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"get-storefront-client.d.ts","sourceRoot":"","sources":["../../../src/react/server/get-storefront-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACrF;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAE1B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAElF;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC7F;AAqBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,CA4BlF"}
1
+ {"version":3,"file":"get-storefront-client.d.ts","sourceRoot":"","sources":["../../../src/react/server/get-storefront-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACrF;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAE1B;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAElF;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC7F;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,CAkClF"}
@@ -24,25 +24,6 @@ import { retryMiddleware } from '../../core/middleware/retry';
24
24
  import { timeoutMiddleware } from '../../core/middleware/timeout';
25
25
  import { errorMiddleware } from '../../core/middleware/errors';
26
26
  import { forwardedIpMiddleware } from '../../core/middleware/forwarded-ip';
27
- /**
28
- * Default buyer-IP source: the request's `cf-connecting-ip` header, read via
29
- * `next/headers` (the same dynamic-import pattern used to read request cookies — a
30
- * graceful no-op outside a Next request scope or in runtimes without
31
- * `next/headers`). Override via `getBuyerIp` for other server frameworks.
32
- */
33
- async function readCfConnectingIp() {
34
- try {
35
- const { headers } = await import('next/headers');
36
- const store = await headers();
37
- // Prefer a forwarded client-IP header when present: if the request was
38
- // proxied, the direct `cf-connecting-ip` is the proxy's address while this
39
- // header carries the original client IP. Fall back to the direct connection IP.
40
- return store.get('x-doswiftly-client-ip') ?? store.get('cf-connecting-ip');
41
- }
42
- catch {
43
- return null;
44
- }
45
- }
46
27
  /**
47
28
  * Create a StorefrontClient for server-side use.
48
29
  *
@@ -52,23 +33,29 @@ async function readCfConnectingIp() {
52
33
  */
53
34
  export function getStorefrontClient(options) {
54
35
  const { middleware: customMiddleware = [], getBuyerIp, getForwardedIpSecret, ...config } = options;
55
- // Forward the real buyer IP for per-buyer rate limiting fully self-configured,
56
- // nothing for the storefront to wire. Buyer IP defaults to the request's
57
- // `cf-connecting-ip` (via next/headers); the signing secret defaults to
58
- // `process.env.DOSWIFTLY_FORWARDED_IP_SECRET` (set in the DoSwiftly deployment
59
- // environment). The slug comes from the `X-Shop-Slug` header the client already
60
- // sends, so the
61
- // signed value matches what the backend verifies. The middleware signs ONLY when
62
- // BOTH a buyer IP and a secret resolve at request time — so with no secret
63
- // configured (or outside a Next request) it is an inert pass-through. Both
64
- // getters can be overridden for non-Next runtimes.
65
- const resolveBuyerIp = getBuyerIp ?? readCfConnectingIp;
66
- const resolveSecret = getForwardedIpSecret ??
67
- (() => (typeof process !== 'undefined' ? process.env?.DOSWIFTLY_FORWARDED_IP_SECRET : undefined));
36
+ // Forwarded-IP signing is OPT-IN: the middleware is wired ONLY when the caller
37
+ // supplies `getBuyerIp`. Reading the buyer IP needs a request-scoped dynamic API
38
+ // (`next/headers` `headers()`), which is illegal in statically-generated / ISR
39
+ // routes auto-reading it there crashes the page ("static to dynamic at runtime").
40
+ // So the caller provides the IP source and uses it ONLY on dynamic routes; without
41
+ // `getBuyerIp` this client is a fully static-safe pass-through. The slug comes from
42
+ // the `X-Shop-Slug` header the client already sends, so the signed value matches
43
+ // what the backend verifies. The secret defaults to
44
+ // `process.env.DOSWIFTLY_FORWARDED_IP_SECRET` (override via `getForwardedIpSecret`);
45
+ // signing happens only when BOTH a buyer IP and a secret resolve at request time.
46
+ const forwardedIp = getBuyerIp
47
+ ? [
48
+ forwardedIpMiddleware({
49
+ getBuyerIp,
50
+ getSecret: getForwardedIpSecret ??
51
+ (() => (typeof process !== 'undefined' ? process.env?.DOSWIFTLY_FORWARDED_IP_SECRET : undefined)),
52
+ }),
53
+ ]
54
+ : [];
68
55
  return createStorefrontClient({
69
56
  ...config,
70
57
  middleware: [
71
- forwardedIpMiddleware({ getBuyerIp: resolveBuyerIp, getSecret: resolveSecret }),
58
+ ...forwardedIp,
72
59
  ...customMiddleware,
73
60
  retryMiddleware({ maxRetries: 2 }),
74
61
  timeoutMiddleware({ timeout: 10000 }), // Server-side: 10s timeout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doswiftly/storefront-sdk",
3
- "version": "22.1.0",
3
+ "version": "22.3.0",
4
4
  "description": "Storefront runtime SDK for DoSwiftly Commerce — layered transport, middleware pipeline, React providers, Zustand stores, cache strategies. 0 runtime dependencies in core.",
5
5
  "type": "module",
6
6
  "sideEffects": false,