@doswiftly/storefront-sdk 4.0.0 → 4.1.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.
Files changed (109) hide show
  1. package/README.md +33 -6
  2. package/dist/core/bot-protection/abstract-manager.d.ts +57 -0
  3. package/dist/core/bot-protection/abstract-manager.d.ts.map +1 -0
  4. package/dist/core/bot-protection/abstract-manager.js +144 -0
  5. package/dist/core/bot-protection/create-manager.d.ts +15 -0
  6. package/dist/core/bot-protection/create-manager.d.ts.map +1 -0
  7. package/dist/core/bot-protection/create-manager.js +33 -0
  8. package/dist/core/bot-protection/eucaptcha-manager.d.ts +15 -0
  9. package/dist/core/bot-protection/eucaptcha-manager.d.ts.map +1 -0
  10. package/dist/core/bot-protection/eucaptcha-manager.js +76 -0
  11. package/dist/core/bot-protection/fallback-manager.d.ts +18 -0
  12. package/dist/core/bot-protection/fallback-manager.d.ts.map +1 -0
  13. package/dist/core/bot-protection/fallback-manager.js +42 -0
  14. package/dist/core/bot-protection/turnstile-manager.d.ts +15 -0
  15. package/dist/core/bot-protection/turnstile-manager.d.ts.map +1 -0
  16. package/dist/core/bot-protection/turnstile-manager.js +78 -0
  17. package/dist/core/cart/cookie-config.d.ts +14 -0
  18. package/dist/core/cart/cookie-config.d.ts.map +1 -0
  19. package/dist/core/cart/cookie-config.js +13 -0
  20. package/dist/core/currency/cookie-config.d.ts +14 -0
  21. package/dist/core/currency/cookie-config.d.ts.map +1 -0
  22. package/dist/core/currency/cookie-config.js +13 -0
  23. package/dist/core/index.d.ts +7 -0
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/core/index.js +11 -0
  26. package/dist/core/language/cookie-config.d.ts +14 -0
  27. package/dist/core/language/cookie-config.d.ts.map +1 -0
  28. package/dist/core/language/cookie-config.js +13 -0
  29. package/dist/core/middleware/bot-protection.d.ts +71 -0
  30. package/dist/core/middleware/bot-protection.d.ts.map +1 -0
  31. package/dist/core/middleware/bot-protection.js +63 -0
  32. package/dist/core/middleware/currency.d.ts.map +1 -1
  33. package/dist/core/middleware/currency.js +2 -1
  34. package/dist/core/middleware/language.d.ts +18 -0
  35. package/dist/core/middleware/language.d.ts.map +1 -0
  36. package/dist/core/middleware/language.js +25 -0
  37. package/dist/react/bot-protection/bot-protection-context.d.ts +12 -0
  38. package/dist/react/bot-protection/bot-protection-context.d.ts.map +1 -0
  39. package/dist/react/bot-protection/bot-protection-context.js +9 -0
  40. package/dist/react/bot-protection/bot-protection-widget.d.ts +13 -0
  41. package/dist/react/bot-protection/bot-protection-widget.d.ts.map +1 -0
  42. package/dist/react/bot-protection/bot-protection-widget.js +34 -0
  43. package/dist/react/cookies.d.ts +17 -0
  44. package/dist/react/cookies.d.ts.map +1 -1
  45. package/dist/react/cookies.js +36 -3
  46. package/dist/react/hooks/use-bot-protection.d.ts +16 -0
  47. package/dist/react/hooks/use-bot-protection.d.ts.map +1 -0
  48. package/dist/react/hooks/use-bot-protection.js +24 -0
  49. package/dist/react/index.d.ts +10 -1
  50. package/dist/react/index.d.ts.map +1 -1
  51. package/dist/react/index.js +9 -1
  52. package/dist/react/providers/language-provider.d.ts +18 -0
  53. package/dist/react/providers/language-provider.d.ts.map +1 -0
  54. package/dist/react/providers/language-provider.js +24 -0
  55. package/dist/react/providers/storefront-client-provider.d.ts +7 -2
  56. package/dist/react/providers/storefront-client-provider.d.ts.map +1 -1
  57. package/dist/react/providers/storefront-client-provider.js +14 -3
  58. package/dist/react/providers/storefront-provider.d.ts +7 -1
  59. package/dist/react/providers/storefront-provider.d.ts.map +1 -1
  60. package/dist/react/providers/storefront-provider.js +11 -4
  61. package/dist/react/stores/cart.context.d.ts +12 -0
  62. package/dist/react/stores/cart.context.d.ts.map +1 -0
  63. package/dist/react/stores/cart.context.js +3 -0
  64. package/dist/react/stores/cart.store.d.ts +71 -0
  65. package/dist/react/stores/cart.store.d.ts.map +1 -0
  66. package/dist/react/stores/cart.store.js +166 -0
  67. package/dist/react/stores/currency.store.d.ts +6 -9
  68. package/dist/react/stores/currency.store.d.ts.map +1 -1
  69. package/dist/react/stores/currency.store.js +5 -22
  70. package/dist/react/stores/language.store.d.ts +33 -0
  71. package/dist/react/stores/language.store.d.ts.map +1 -0
  72. package/dist/react/stores/language.store.js +67 -0
  73. package/dist/react/stores/store-context.d.ts +5 -0
  74. package/dist/react/stores/store-context.d.ts.map +1 -1
  75. package/dist/react/stores/store-context.js +14 -0
  76. package/dist/react/types/shop-config.d.ts +19 -0
  77. package/dist/react/types/shop-config.d.ts.map +1 -0
  78. package/dist/react/types/shop-config.js +7 -0
  79. package/package.json +1 -1
  80. package/src/__tests__/unit/bot-protection.test.ts +461 -0
  81. package/src/__tests__/unit/cart-store.test.ts +349 -0
  82. package/src/core/bot-protection/abstract-manager.ts +185 -0
  83. package/src/core/bot-protection/create-manager.ts +37 -0
  84. package/src/core/bot-protection/eucaptcha-manager.ts +88 -0
  85. package/src/core/bot-protection/fallback-manager.ts +43 -0
  86. package/src/core/bot-protection/turnstile-manager.ts +92 -0
  87. package/src/core/bot-protection/types/eucaptcha.d.ts +28 -0
  88. package/src/core/bot-protection/types/turnstile.d.ts +33 -0
  89. package/src/core/cart/cookie-config.ts +13 -0
  90. package/src/core/currency/cookie-config.ts +13 -0
  91. package/src/core/index.ts +23 -0
  92. package/src/core/language/cookie-config.ts +13 -0
  93. package/src/core/middleware/bot-protection.ts +140 -0
  94. package/src/core/middleware/currency.ts +2 -1
  95. package/src/core/middleware/language.ts +30 -0
  96. package/src/react/bot-protection/bot-protection-context.ts +17 -0
  97. package/src/react/bot-protection/bot-protection-widget.tsx +46 -0
  98. package/src/react/cookies.ts +39 -4
  99. package/src/react/hooks/use-bot-protection.ts +31 -0
  100. package/src/react/index.ts +27 -1
  101. package/src/react/providers/language-provider.tsx +34 -0
  102. package/src/react/providers/storefront-client-provider.tsx +20 -3
  103. package/src/react/providers/storefront-provider.tsx +34 -6
  104. package/src/react/stores/cart.context.ts +10 -0
  105. package/src/react/stores/cart.store.ts +254 -0
  106. package/src/react/stores/currency.store.ts +12 -32
  107. package/src/react/stores/language.store.ts +90 -0
  108. package/src/react/stores/store-context.tsx +21 -0
  109. package/src/react/types/shop-config.ts +22 -0
package/README.md CHANGED
@@ -317,7 +317,33 @@ const {
317
317
  });
318
318
  ```
319
319
 
320
- ### useCartManager
320
+ ### Cart Store (DI-based) — recommended for templates
321
+
322
+ ```typescript
323
+ import { createCartStore, CartProvider, useCartStore, type CartActions } from '@doswiftly/storefront-sdk/react';
324
+
325
+ // Template provides CartActions implementation (transport layer)
326
+ const store = createCartStore({
327
+ getActions: () => cartActions, // getter — called per operation (fresh refs)
328
+ onMutationSuccess: (action, cart) => { /* toast, cache invalidation */ },
329
+ onMutationError: (action, error) => { /* error toast */ },
330
+ });
331
+
332
+ // Provider (separate from StorefrontProvider — template composes in StoresProvider)
333
+ <CartProvider store={store}>{children}</CartProvider>
334
+
335
+ // Hooks (Context-based, selector overloads)
336
+ const { cartId, isOpen, isLoading, addToCart, clearCart, openCart } = useCartStore();
337
+ const cartId = useCartStore(s => s.cartId); // with selector
338
+
339
+ // Selectors
340
+ import { selectCartId, selectIsCartOpen, selectCartIsLoading } from '@doswiftly/storefront-sdk/react';
341
+ ```
342
+
343
+ SDK orchestrates: auto-init (fetch or create), expired cart recovery, loading/error state, mutation callbacks.
344
+ Template provides: CartActions DI implementation (GraphQL hooks, React Query, fetch — any transport).
345
+
346
+ ### useCartManager (alternative — cookie-based, simple)
321
347
 
322
348
  ```typescript
323
349
  const {
@@ -330,7 +356,7 @@ const {
330
356
  } = useCartManager();
331
357
  ```
332
358
 
333
- Cart ID is persisted in a cookie (SSR/edge visible).
359
+ Cart ID is persisted in a cookie (SSR/edge visible). Plain async + useState, no React Query dependency.
334
360
 
335
361
  ### useHydrated
336
362
 
@@ -412,10 +438,11 @@ Storefronts (Next.js templates) import SDK for **infrastructure** and own their
412
438
  SDK provides: Template owns:
413
439
  ├── Transport + Middleware ├── codegen.ts + generated/graphql.ts
414
440
  ├── CartClient + AuthClient ├── lib/graphql/hooks.ts (React Query)
415
- ├── Providers + Zustand stores ├── lib/graphql/server.ts (React cache)
416
- ├── Format utilities ├── lib/graphql/fragments/
417
- ├── sanitizeHtml ├── stores/ (UI state via createStoreContext)
418
- ├── normalizeConnection ├── hooks/ (use-auth, use-cart-actions, etc.)
441
+ ├── Cart Store (DI-based) ├── lib/graphql/server.ts (React cache)
442
+ ├── Providers + Zustand stores ├── lib/graphql/fragments/
443
+ ├── Format utilities ├── hooks/use-cart-di.ts (CartActions DI impl)
444
+ ├── sanitizeHtml ├── hooks/use-cart-actions.ts (UX wrapper)
445
+ ├── normalizeConnection ├── stores/ (checkout, wishlist via createStoreContext)
419
446
  ├── Auth handlers + token client ├── lib/auth/routes.ts (route config)
420
447
  ├── useHydrated + useDebouncedValue
421
448
  ├── createStoreContext └── components/providers/
@@ -0,0 +1,57 @@
1
+ /**
2
+ * AbstractBotProtectionManager — base class for all bot protection providers.
3
+ *
4
+ * DRY: singleton script loading, lazy mount, in-flight deduplication, timeout.
5
+ * Subclasses override only: _loadScript(), _renderWidget(), _executeChallenge(), _destroyWidget().
6
+ *
7
+ * Framework-agnostic (DOM APIs only) — works in React, Vue, Svelte, vanilla JS.
8
+ */
9
+ import type { BotProtectionTokenProvider } from '../middleware/bot-protection';
10
+ export declare abstract class AbstractBotProtectionManager implements BotProtectionTokenProvider {
11
+ protected readonly siteKey: string;
12
+ protected readonly scriptUrl: string;
13
+ /** Singleton script loading promise — one load per provider globally */
14
+ private scriptPromise;
15
+ /** In-flight deduplication — prevents double-submit */
16
+ private inFlight;
17
+ /** Whether the widget has been mounted */
18
+ protected widgetId: string | null;
19
+ /** Container element for the widget */
20
+ protected container: HTMLElement | null;
21
+ constructor(siteKey: string, scriptUrl: string);
22
+ /**
23
+ * Load the provider's script tag. Singleton — only loads once.
24
+ * Exposed publicly so React wrapper can trigger preload.
25
+ */
26
+ loadScript(): Promise<void>;
27
+ /**
28
+ * Mount the invisible widget into a container element.
29
+ * Lazy — called automatically on first execute() if not mounted.
30
+ */
31
+ mount(container: HTMLElement): void;
32
+ /**
33
+ * Execute challenge and get a fresh token.
34
+ * In-flight dedup + timeout + lazy mount + lazy script load.
35
+ */
36
+ execute(options?: {
37
+ action?: string;
38
+ timeoutMs?: number;
39
+ }): Promise<string | null>;
40
+ /**
41
+ * Cleanup widget and resources.
42
+ */
43
+ destroy(): void;
44
+ private _doExecute;
45
+ private _ensureMounted;
46
+ /** Wait for the provider API to be available on window */
47
+ protected abstract _waitForApi(): Promise<void>;
48
+ /** Optional: setup global onload callback for the script */
49
+ protected _setupOnloadCallback(_resolve: () => void): void;
50
+ /** Render the invisible widget. Return widget ID. */
51
+ protected abstract _renderWidget(container: HTMLElement, action?: string): string;
52
+ /** Execute the challenge and return a token. Called after mount. */
53
+ protected abstract _executeChallenge(widgetId: string, action?: string): Promise<string | null>;
54
+ /** Destroy/remove the widget. */
55
+ protected abstract _destroyWidget(widgetId: string): void;
56
+ }
57
+ //# sourceMappingURL=abstract-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstract-manager.d.ts","sourceRoot":"","sources":["../../../src/core/bot-protection/abstract-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,8BAAsB,4BAA6B,YAAW,0BAA0B;IACtF,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACnC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC,wEAAwE;IACxE,OAAO,CAAC,aAAa,CAA8B;IACnD,uDAAuD;IACvD,OAAO,CAAC,QAAQ,CAAuC;IACvD,0CAA0C;IAC1C,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACzC,uCAAuC;IACvC,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAQ;gBAEnC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAK9C;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC3B;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAInC;;;OAGG;IACG,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAaxF;;OAEG;IACH,OAAO,IAAI,IAAI;YAgBD,UAAU;YA4BV,cAAc;IAsB5B,0DAA0D;IAC1D,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/C,4DAA4D;IAC5D,SAAS,CAAC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI1D,qDAAqD;IACrD,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAEjF,oEAAoE;IACpE,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAE/F,iCAAiC;IACjC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAC1D"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * AbstractBotProtectionManager — base class for all bot protection providers.
3
+ *
4
+ * DRY: singleton script loading, lazy mount, in-flight deduplication, timeout.
5
+ * Subclasses override only: _loadScript(), _renderWidget(), _executeChallenge(), _destroyWidget().
6
+ *
7
+ * Framework-agnostic (DOM APIs only) — works in React, Vue, Svelte, vanilla JS.
8
+ */
9
+ export class AbstractBotProtectionManager {
10
+ siteKey;
11
+ scriptUrl;
12
+ /** Singleton script loading promise — one load per provider globally */
13
+ scriptPromise = null;
14
+ /** In-flight deduplication — prevents double-submit */
15
+ inFlight = null;
16
+ /** Whether the widget has been mounted */
17
+ widgetId = null;
18
+ /** Container element for the widget */
19
+ container = null;
20
+ constructor(siteKey, scriptUrl) {
21
+ this.siteKey = siteKey;
22
+ this.scriptUrl = scriptUrl;
23
+ }
24
+ /**
25
+ * Load the provider's script tag. Singleton — only loads once.
26
+ * Exposed publicly so React wrapper can trigger preload.
27
+ */
28
+ loadScript() {
29
+ if (this.scriptPromise)
30
+ return this.scriptPromise;
31
+ this.scriptPromise = new Promise((resolve, reject) => {
32
+ // Skip in SSR
33
+ if (typeof document === 'undefined') {
34
+ resolve();
35
+ return;
36
+ }
37
+ // Check if script already exists
38
+ const existing = document.querySelector(`script[src="${this.scriptUrl}"]`);
39
+ if (existing) {
40
+ // Script tag exists — wait for API to be available
41
+ this._waitForApi().then(resolve).catch(reject);
42
+ return;
43
+ }
44
+ const script = document.createElement('script');
45
+ script.src = this.scriptUrl;
46
+ script.async = true;
47
+ script.defer = true;
48
+ // Set up onload callback if provider supports it
49
+ this._setupOnloadCallback(resolve);
50
+ script.onload = () => {
51
+ this._waitForApi().then(resolve).catch(reject);
52
+ };
53
+ script.onerror = () => {
54
+ this.scriptPromise = null; // Allow retry
55
+ reject(new Error(`Failed to load bot protection script: ${this.scriptUrl}`));
56
+ };
57
+ document.head.appendChild(script);
58
+ });
59
+ return this.scriptPromise;
60
+ }
61
+ /**
62
+ * Mount the invisible widget into a container element.
63
+ * Lazy — called automatically on first execute() if not mounted.
64
+ */
65
+ mount(container) {
66
+ this.container = container;
67
+ }
68
+ /**
69
+ * Execute challenge and get a fresh token.
70
+ * In-flight dedup + timeout + lazy mount + lazy script load.
71
+ */
72
+ async execute(options) {
73
+ // In-flight deduplication — return existing promise if one is running
74
+ if (this.inFlight)
75
+ return this.inFlight;
76
+ const timeoutMs = options?.timeoutMs ?? 10000;
77
+ this.inFlight = this._doExecute(options?.action, timeoutMs).finally(() => {
78
+ this.inFlight = null;
79
+ });
80
+ return this.inFlight;
81
+ }
82
+ /**
83
+ * Cleanup widget and resources.
84
+ */
85
+ destroy() {
86
+ try {
87
+ if (this.widgetId) {
88
+ this._destroyWidget(this.widgetId);
89
+ }
90
+ }
91
+ catch {
92
+ // Ignore cleanup errors
93
+ }
94
+ this.widgetId = null;
95
+ this.container = null;
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Private execution pipeline
99
+ // ---------------------------------------------------------------------------
100
+ async _doExecute(action, timeoutMs) {
101
+ try {
102
+ // 1. Lazy script load
103
+ await this.loadScript();
104
+ // 2. Lazy mount — create container if needed
105
+ if (!this.widgetId) {
106
+ await this._ensureMounted(action);
107
+ }
108
+ if (!this.widgetId) {
109
+ return null; // Mount failed — fail-open
110
+ }
111
+ // 3. Execute challenge with timeout
112
+ const tokenPromise = this._executeChallenge(this.widgetId, action);
113
+ const timeoutPromise = new Promise((resolve) => {
114
+ setTimeout(() => resolve(null), timeoutMs);
115
+ });
116
+ return await Promise.race([tokenPromise, timeoutPromise]);
117
+ }
118
+ catch {
119
+ // Any error → return null (fail-open at middleware level)
120
+ return null;
121
+ }
122
+ }
123
+ async _ensureMounted(action) {
124
+ // Create an invisible container if none provided
125
+ if (!this.container && typeof document !== 'undefined') {
126
+ this.container = document.createElement('div');
127
+ this.container.style.display = 'none';
128
+ this.container.setAttribute('data-bot-protection', 'true');
129
+ document.body.appendChild(this.container);
130
+ }
131
+ if (!this.container)
132
+ return;
133
+ try {
134
+ this.widgetId = this._renderWidget(this.container, action);
135
+ }
136
+ catch {
137
+ this.widgetId = null;
138
+ }
139
+ }
140
+ /** Optional: setup global onload callback for the script */
141
+ _setupOnloadCallback(_resolve) {
142
+ // Default: no-op. Override if provider uses a callback pattern.
143
+ }
144
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Bot protection manager factory.
3
+ *
4
+ * Creates the appropriate manager based on provider config from shop query.
5
+ * Supports runtime fallback chain via FallbackBotProtectionManager.
6
+ */
7
+ import type { BotProtectionTokenProvider, BotProtectionConfig } from '../middleware/bot-protection';
8
+ /**
9
+ * Create a bot protection manager with optional fallback chain.
10
+ *
11
+ * @param config - Bot protection configuration from shop query
12
+ * @returns BotProtectionTokenProvider (FallbackBotProtectionManager if fallback configured)
13
+ */
14
+ export declare function createBotProtectionManager(config: BotProtectionConfig): BotProtectionTokenProvider;
15
+ //# sourceMappingURL=create-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-manager.d.ts","sourceRoot":"","sources":["../../../src/core/bot-protection/create-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAA+B,MAAM,8BAA8B,CAAC;AAmBjI;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,mBAAmB,GAAG,0BAA0B,CAIlG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Bot protection manager factory.
3
+ *
4
+ * Creates the appropriate manager based on provider config from shop query.
5
+ * Supports runtime fallback chain via FallbackBotProtectionManager.
6
+ */
7
+ import { EuCaptchaManager } from './eucaptcha-manager';
8
+ import { TurnstileManager } from './turnstile-manager';
9
+ import { FallbackBotProtectionManager } from './fallback-manager';
10
+ /**
11
+ * Create a single provider manager instance.
12
+ */
13
+ function createSingleManager(config) {
14
+ switch (config.provider) {
15
+ case 'eucaptcha':
16
+ return new EuCaptchaManager(config.siteKey, config.scriptUrl);
17
+ case 'turnstile':
18
+ return new TurnstileManager(config.siteKey, config.scriptUrl);
19
+ default:
20
+ throw new Error(`Unknown bot protection provider: ${config.provider}`);
21
+ }
22
+ }
23
+ /**
24
+ * Create a bot protection manager with optional fallback chain.
25
+ *
26
+ * @param config - Bot protection configuration from shop query
27
+ * @returns BotProtectionTokenProvider (FallbackBotProtectionManager if fallback configured)
28
+ */
29
+ export function createBotProtectionManager(config) {
30
+ const primary = createSingleManager(config.primary);
31
+ const fallback = config.fallback ? createSingleManager(config.fallback) : null;
32
+ return new FallbackBotProtectionManager(primary, fallback);
33
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * EuCaptchaManager — EU CAPTCHA (Myra Security) bot protection provider.
3
+ *
4
+ * Default provider — GDPR by design, EU-hosted (Germany), privacy-first.
5
+ * Implements BotProtectionTokenProvider via AbstractBotProtectionManager.
6
+ * Invisible behavioral analysis, zero user interaction.
7
+ */
8
+ import { AbstractBotProtectionManager } from './abstract-manager';
9
+ export declare class EuCaptchaManager extends AbstractBotProtectionManager {
10
+ protected _waitForApi(): Promise<void>;
11
+ protected _renderWidget(container: HTMLElement, action?: string): string;
12
+ protected _executeChallenge(widgetId: string, action?: string): Promise<string | null>;
13
+ protected _destroyWidget(widgetId: string): void;
14
+ }
15
+ //# sourceMappingURL=eucaptcha-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eucaptcha-manager.d.ts","sourceRoot":"","sources":["../../../src/core/bot-protection/eucaptcha-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE,qBAAa,gBAAiB,SAAQ,4BAA4B;IAChE,SAAS,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtC,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAYxE,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAqCtF,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAKjD"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * EuCaptchaManager — EU CAPTCHA (Myra Security) bot protection provider.
3
+ *
4
+ * Default provider — GDPR by design, EU-hosted (Germany), privacy-first.
5
+ * Implements BotProtectionTokenProvider via AbstractBotProtectionManager.
6
+ * Invisible behavioral analysis, zero user interaction.
7
+ */
8
+ /// <reference path="./types/eucaptcha.d.ts" />
9
+ import { AbstractBotProtectionManager } from './abstract-manager';
10
+ export class EuCaptchaManager extends AbstractBotProtectionManager {
11
+ _waitForApi() {
12
+ if (typeof window !== 'undefined' && window.eucaptcha) {
13
+ return Promise.resolve();
14
+ }
15
+ return new Promise((resolve) => {
16
+ const check = setInterval(() => {
17
+ if (typeof window !== 'undefined' && window.eucaptcha) {
18
+ clearInterval(check);
19
+ resolve();
20
+ }
21
+ }, 50);
22
+ // Safety timeout
23
+ setTimeout(() => {
24
+ clearInterval(check);
25
+ resolve();
26
+ }, 15000);
27
+ });
28
+ }
29
+ _renderWidget(container, action) {
30
+ if (!window.eucaptcha) {
31
+ throw new Error('EU CAPTCHA API not loaded');
32
+ }
33
+ return window.eucaptcha.render(container, {
34
+ sitekey: this.siteKey,
35
+ size: 'invisible',
36
+ action,
37
+ });
38
+ }
39
+ _executeChallenge(widgetId, action) {
40
+ return new Promise((resolve) => {
41
+ if (!window.eucaptcha) {
42
+ resolve(null);
43
+ return;
44
+ }
45
+ // Reset for fresh token
46
+ window.eucaptcha.reset(widgetId);
47
+ // Remove old widget and re-render with callback
48
+ if (!this.container) {
49
+ resolve(null);
50
+ return;
51
+ }
52
+ // Re-render with callback to capture token
53
+ this.widgetId = window.eucaptcha.render(this.container, {
54
+ sitekey: this.siteKey,
55
+ size: 'invisible',
56
+ action,
57
+ callback: (token) => {
58
+ resolve(token);
59
+ },
60
+ 'error-callback': () => {
61
+ resolve(null);
62
+ },
63
+ 'expired-callback': () => {
64
+ resolve(null);
65
+ },
66
+ });
67
+ // Trigger execution
68
+ window.eucaptcha.execute(this.widgetId);
69
+ });
70
+ }
71
+ _destroyWidget(widgetId) {
72
+ if (window.eucaptcha) {
73
+ window.eucaptcha.reset(widgetId);
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * FallbackBotProtectionManager — runtime fallback chain.
3
+ *
4
+ * Tries primary provider, falls back to secondary, ultimately returns null (fail-open).
5
+ * RULE: NEVER block the customer — fail-open is the ultimate fallback.
6
+ */
7
+ import type { BotProtectionTokenProvider } from '../middleware/bot-protection';
8
+ export declare class FallbackBotProtectionManager implements BotProtectionTokenProvider {
9
+ private readonly primary;
10
+ private readonly fallback;
11
+ constructor(primary: BotProtectionTokenProvider, fallback: BotProtectionTokenProvider | null);
12
+ execute(options?: {
13
+ action?: string;
14
+ timeoutMs?: number;
15
+ }): Promise<string | null>;
16
+ destroy(): void;
17
+ }
18
+ //# sourceMappingURL=fallback-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback-manager.d.ts","sourceRoot":"","sources":["../../../src/core/bot-protection/fallback-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,qBAAa,4BAA6B,YAAW,0BAA0B;IAE3E,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,OAAO,EAAE,0BAA0B,EACnC,QAAQ,EAAE,0BAA0B,GAAG,IAAI;IAGxD,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuBxF,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * FallbackBotProtectionManager — runtime fallback chain.
3
+ *
4
+ * Tries primary provider, falls back to secondary, ultimately returns null (fail-open).
5
+ * RULE: NEVER block the customer — fail-open is the ultimate fallback.
6
+ */
7
+ export class FallbackBotProtectionManager {
8
+ primary;
9
+ fallback;
10
+ constructor(primary, fallback) {
11
+ this.primary = primary;
12
+ this.fallback = fallback;
13
+ }
14
+ async execute(options) {
15
+ // 1. Try primary
16
+ try {
17
+ const token = await this.primary.execute(options);
18
+ if (token)
19
+ return token;
20
+ }
21
+ catch {
22
+ // Primary failed — try fallback
23
+ }
24
+ // 2. Try fallback
25
+ if (this.fallback) {
26
+ try {
27
+ const token = await this.fallback.execute(options);
28
+ if (token)
29
+ return token;
30
+ }
31
+ catch {
32
+ // Fallback also failed
33
+ }
34
+ }
35
+ // 3. Ultimate fail-open: return null -> middleware decides per-operation strategy
36
+ return null;
37
+ }
38
+ destroy() {
39
+ this.primary.destroy();
40
+ this.fallback?.destroy();
41
+ }
42
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * TurnstileManager — Cloudflare Turnstile bot protection provider.
3
+ *
4
+ * Implements BotProtectionTokenProvider via AbstractBotProtectionManager.
5
+ * Invisible widget, execution-mode challenge (no user interaction).
6
+ */
7
+ import { AbstractBotProtectionManager } from './abstract-manager';
8
+ export declare class TurnstileManager extends AbstractBotProtectionManager {
9
+ private callbackName;
10
+ protected _waitForApi(): Promise<void>;
11
+ protected _renderWidget(container: HTMLElement, action?: string): string;
12
+ protected _executeChallenge(widgetId: string, action?: string): Promise<string | null>;
13
+ protected _destroyWidget(widgetId: string): void;
14
+ }
15
+ //# sourceMappingURL=turnstile-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnstile-manager.d.ts","sourceRoot":"","sources":["../../../src/core/bot-protection/turnstile-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE,qBAAa,gBAAiB,SAAQ,4BAA4B;IAChE,OAAO,CAAC,YAAY,CAAoE;IAExF,SAAS,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtC,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAaxE,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuCtF,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAKjD"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * TurnstileManager — Cloudflare Turnstile bot protection provider.
3
+ *
4
+ * Implements BotProtectionTokenProvider via AbstractBotProtectionManager.
5
+ * Invisible widget, execution-mode challenge (no user interaction).
6
+ */
7
+ /// <reference path="./types/turnstile.d.ts" />
8
+ import { AbstractBotProtectionManager } from './abstract-manager';
9
+ export class TurnstileManager extends AbstractBotProtectionManager {
10
+ callbackName = `onloadTurnstileCallback_${Math.random().toString(36).slice(2)}`;
11
+ _waitForApi() {
12
+ if (typeof window !== 'undefined' && window.turnstile) {
13
+ return Promise.resolve();
14
+ }
15
+ return new Promise((resolve) => {
16
+ const check = setInterval(() => {
17
+ if (typeof window !== 'undefined' && window.turnstile) {
18
+ clearInterval(check);
19
+ resolve();
20
+ }
21
+ }, 50);
22
+ // Safety timeout — don't poll forever
23
+ setTimeout(() => {
24
+ clearInterval(check);
25
+ resolve(); // Resolve anyway — execute will fail gracefully
26
+ }, 15000);
27
+ });
28
+ }
29
+ _renderWidget(container, action) {
30
+ if (!window.turnstile) {
31
+ throw new Error('Turnstile API not loaded');
32
+ }
33
+ return window.turnstile.render(container, {
34
+ sitekey: this.siteKey,
35
+ size: 'invisible',
36
+ execution: 'execute',
37
+ action,
38
+ });
39
+ }
40
+ _executeChallenge(widgetId, action) {
41
+ return new Promise((resolve) => {
42
+ if (!window.turnstile) {
43
+ resolve(null);
44
+ return;
45
+ }
46
+ // Reset to get a fresh token (tokens are single-use)
47
+ window.turnstile.reset(widgetId);
48
+ // Remove old widget and re-render with callback
49
+ window.turnstile.remove(widgetId);
50
+ if (!this.container) {
51
+ resolve(null);
52
+ return;
53
+ }
54
+ this.widgetId = window.turnstile.render(this.container, {
55
+ sitekey: this.siteKey,
56
+ size: 'invisible',
57
+ execution: 'execute',
58
+ action,
59
+ callback: (token) => {
60
+ resolve(token);
61
+ },
62
+ 'error-callback': () => {
63
+ resolve(null);
64
+ },
65
+ 'expired-callback': () => {
66
+ resolve(null);
67
+ },
68
+ });
69
+ // Trigger execution
70
+ window.turnstile.execute(this.widgetId, { action });
71
+ });
72
+ }
73
+ _destroyWidget(widgetId) {
74
+ if (window.turnstile) {
75
+ window.turnstile.remove(widgetId);
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cart cookie configuration — platform contract.
3
+ *
4
+ * Used by:
5
+ * - SDK cart store (client-side cookie read/write for cartId)
6
+ * - Server-side cart prefetching (SSR cart badge, middleware)
7
+ * - proxy.ts (edge cart ID detection)
8
+ *
9
+ * Single cookie for cart ID persistence. Value is a plain cart ID string
10
+ * (not JSON) — server can read it directly via cookies().get('cart-id').
11
+ */
12
+ export declare const CART_COOKIE_NAME = "cart-id";
13
+ export declare const CART_COOKIE_MAX_AGE: number;
14
+ //# sourceMappingURL=cookie-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-config.d.ts","sourceRoot":"","sources":["../../../src/core/cart/cookie-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,mBAAmB,QAAoB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Cart cookie configuration — platform contract.
3
+ *
4
+ * Used by:
5
+ * - SDK cart store (client-side cookie read/write for cartId)
6
+ * - Server-side cart prefetching (SSR cart badge, middleware)
7
+ * - proxy.ts (edge cart ID detection)
8
+ *
9
+ * Single cookie for cart ID persistence. Value is a plain cart ID string
10
+ * (not JSON) — server can read it directly via cookies().get('cart-id').
11
+ */
12
+ export const CART_COOKIE_NAME = 'cart-id';
13
+ export const CART_COOKIE_MAX_AGE = 30 * 24 * 60 * 60; // 30 days
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Currency configuration constants — platform contract.
3
+ *
4
+ * Used by:
5
+ * - SDK currency store (client-side cookie read/write)
6
+ * - SDK currency middleware (X-Preferred-Currency header)
7
+ * - Server-side currency detection (SSR helpers)
8
+ *
9
+ * Single cookie for preferred currency persistence.
10
+ */
11
+ export declare const CURRENCY_COOKIE_NAME = "preferred-currency";
12
+ export declare const CURRENCY_COOKIE_MAX_AGE: number;
13
+ export declare const CURRENCY_HEADER_NAME = "X-Preferred-Currency";
14
+ //# sourceMappingURL=cookie-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-config.d.ts","sourceRoot":"","sources":["../../../src/core/currency/cookie-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AACzD,eAAO,MAAM,uBAAuB,QAAqB,CAAC;AAC1D,eAAO,MAAM,oBAAoB,yBAAyB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Currency configuration constants — platform contract.
3
+ *
4
+ * Used by:
5
+ * - SDK currency store (client-side cookie read/write)
6
+ * - SDK currency middleware (X-Preferred-Currency header)
7
+ * - Server-side currency detection (SSR helpers)
8
+ *
9
+ * Single cookie for preferred currency persistence.
10
+ */
11
+ export const CURRENCY_COOKIE_NAME = 'preferred-currency';
12
+ export const CURRENCY_COOKIE_MAX_AGE = 365 * 24 * 60 * 60; // 1 year
13
+ export const CURRENCY_HEADER_NAME = 'X-Preferred-Currency';