@doswiftly/storefront-sdk 4.0.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 (206) hide show
  1. package/README.md +430 -0
  2. package/dist/__tests__/unit/test-helpers.d.ts +46 -0
  3. package/dist/__tests__/unit/test-helpers.d.ts.map +1 -0
  4. package/dist/__tests__/unit/test-helpers.js +72 -0
  5. package/dist/core/auth/auth-client.d.ts +46 -0
  6. package/dist/core/auth/auth-client.d.ts.map +1 -0
  7. package/dist/core/auth/auth-client.js +82 -0
  8. package/dist/core/auth/cookie-config.d.ts +18 -0
  9. package/dist/core/auth/cookie-config.d.ts.map +1 -0
  10. package/dist/core/auth/cookie-config.js +18 -0
  11. package/dist/core/auth/handlers.d.ts +32 -0
  12. package/dist/core/auth/handlers.d.ts.map +1 -0
  13. package/dist/core/auth/handlers.js +127 -0
  14. package/dist/core/auth/routes.d.ts +21 -0
  15. package/dist/core/auth/routes.d.ts.map +1 -0
  16. package/dist/core/auth/routes.js +14 -0
  17. package/dist/core/auth/token-client.d.ts +26 -0
  18. package/dist/core/auth/token-client.d.ts.map +1 -0
  19. package/dist/core/auth/token-client.js +42 -0
  20. package/dist/core/auth/types.d.ts +53 -0
  21. package/dist/core/auth/types.d.ts.map +1 -0
  22. package/dist/core/auth/types.js +4 -0
  23. package/dist/core/cache.d.ts +54 -0
  24. package/dist/core/cache.d.ts.map +1 -0
  25. package/dist/core/cache.js +82 -0
  26. package/dist/core/cart/cart-client.d.ts +57 -0
  27. package/dist/core/cart/cart-client.d.ts.map +1 -0
  28. package/dist/core/cart/cart-client.js +89 -0
  29. package/dist/core/cart/types.d.ts +110 -0
  30. package/dist/core/cart/types.d.ts.map +1 -0
  31. package/dist/core/cart/types.js +6 -0
  32. package/dist/core/client/compose.d.ts +9 -0
  33. package/dist/core/client/compose.d.ts.map +1 -0
  34. package/dist/core/client/compose.js +9 -0
  35. package/dist/core/client/create-client.d.ts +15 -0
  36. package/dist/core/client/create-client.d.ts.map +1 -0
  37. package/dist/core/client/create-client.js +85 -0
  38. package/dist/core/client/dedupe.d.ts +7 -0
  39. package/dist/core/client/dedupe.d.ts.map +1 -0
  40. package/dist/core/client/dedupe.js +16 -0
  41. package/dist/core/client/execute.d.ts +20 -0
  42. package/dist/core/client/execute.d.ts.map +1 -0
  43. package/dist/core/client/execute.js +48 -0
  44. package/dist/core/client/hash.d.ts +7 -0
  45. package/dist/core/client/hash.d.ts.map +1 -0
  46. package/dist/core/client/hash.js +21 -0
  47. package/dist/core/client/operation-name.d.ts +7 -0
  48. package/dist/core/client/operation-name.d.ts.map +1 -0
  49. package/dist/core/client/operation-name.js +10 -0
  50. package/dist/core/client/types.d.ts +126 -0
  51. package/dist/core/client/types.d.ts.map +1 -0
  52. package/dist/core/client/types.js +26 -0
  53. package/dist/core/errors.d.ts +43 -0
  54. package/dist/core/errors.d.ts.map +1 -0
  55. package/dist/core/errors.js +43 -0
  56. package/dist/core/format.d.ts +92 -0
  57. package/dist/core/format.d.ts.map +1 -0
  58. package/dist/core/format.js +216 -0
  59. package/dist/core/helpers/assert-no-user-errors.d.ts +10 -0
  60. package/dist/core/helpers/assert-no-user-errors.d.ts.map +1 -0
  61. package/dist/core/helpers/assert-no-user-errors.js +16 -0
  62. package/dist/core/helpers/normalize-connection.d.ts +36 -0
  63. package/dist/core/helpers/normalize-connection.d.ts.map +1 -0
  64. package/dist/core/helpers/normalize-connection.js +21 -0
  65. package/dist/core/helpers/sanitize-html.d.ts +8 -0
  66. package/dist/core/helpers/sanitize-html.d.ts.map +1 -0
  67. package/dist/core/helpers/sanitize-html.js +35 -0
  68. package/dist/core/index.d.ts +59 -0
  69. package/dist/core/index.d.ts.map +1 -0
  70. package/dist/core/index.js +68 -0
  71. package/dist/core/middleware/auth.d.ts +16 -0
  72. package/dist/core/middleware/auth.d.ts.map +1 -0
  73. package/dist/core/middleware/auth.js +22 -0
  74. package/dist/core/middleware/currency.d.ts +15 -0
  75. package/dist/core/middleware/currency.d.ts.map +1 -0
  76. package/dist/core/middleware/currency.js +21 -0
  77. package/dist/core/middleware/errors.d.ts +24 -0
  78. package/dist/core/middleware/errors.d.ts.map +1 -0
  79. package/dist/core/middleware/errors.js +77 -0
  80. package/dist/core/middleware/retry.d.ts +22 -0
  81. package/dist/core/middleware/retry.d.ts.map +1 -0
  82. package/dist/core/middleware/retry.js +58 -0
  83. package/dist/core/middleware/timeout.d.ts +19 -0
  84. package/dist/core/middleware/timeout.d.ts.map +1 -0
  85. package/dist/core/middleware/timeout.js +51 -0
  86. package/dist/core/operations/auth.d.ts +11 -0
  87. package/dist/core/operations/auth.d.ts.map +1 -0
  88. package/dist/core/operations/auth.js +112 -0
  89. package/dist/core/operations/cart.d.ts +15 -0
  90. package/dist/core/operations/cart.d.ts.map +1 -0
  91. package/dist/core/operations/cart.js +169 -0
  92. package/dist/index.d.ts +24 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.js +24 -0
  95. package/dist/react/cookies.d.ts +28 -0
  96. package/dist/react/cookies.d.ts.map +1 -0
  97. package/dist/react/cookies.js +49 -0
  98. package/dist/react/helpers/create-store-context.d.ts +37 -0
  99. package/dist/react/helpers/create-store-context.d.ts.map +1 -0
  100. package/dist/react/helpers/create-store-context.js +47 -0
  101. package/dist/react/hooks/use-auth.d.ts +65 -0
  102. package/dist/react/hooks/use-auth.d.ts.map +1 -0
  103. package/dist/react/hooks/use-auth.js +168 -0
  104. package/dist/react/hooks/use-cart-manager.d.ts +30 -0
  105. package/dist/react/hooks/use-cart-manager.d.ts.map +1 -0
  106. package/dist/react/hooks/use-cart-manager.js +223 -0
  107. package/dist/react/hooks/use-currency.d.ts +11 -0
  108. package/dist/react/hooks/use-currency.d.ts.map +1 -0
  109. package/dist/react/hooks/use-currency.js +19 -0
  110. package/dist/react/hooks/use-debounced-value.d.ts +15 -0
  111. package/dist/react/hooks/use-debounced-value.d.ts.map +1 -0
  112. package/dist/react/hooks/use-debounced-value.js +25 -0
  113. package/dist/react/hooks/use-hydrated.d.ts +9 -0
  114. package/dist/react/hooks/use-hydrated.d.ts.map +1 -0
  115. package/dist/react/hooks/use-hydrated.js +14 -0
  116. package/dist/react/hooks/use-storefront-client.d.ts +6 -0
  117. package/dist/react/hooks/use-storefront-client.d.ts.map +1 -0
  118. package/dist/react/hooks/use-storefront-client.js +8 -0
  119. package/dist/react/index.d.ts +30 -0
  120. package/dist/react/index.d.ts.map +1 -0
  121. package/dist/react/index.js +34 -0
  122. package/dist/react/providers/currency-provider.d.ts +14 -0
  123. package/dist/react/providers/currency-provider.d.ts.map +1 -0
  124. package/dist/react/providers/currency-provider.js +20 -0
  125. package/dist/react/providers/storefront-client-provider.d.ts +33 -0
  126. package/dist/react/providers/storefront-client-provider.d.ts.map +1 -0
  127. package/dist/react/providers/storefront-client-provider.js +57 -0
  128. package/dist/react/providers/storefront-provider.d.ts +42 -0
  129. package/dist/react/providers/storefront-provider.d.ts.map +1 -0
  130. package/dist/react/providers/storefront-provider.js +40 -0
  131. package/dist/react/server/get-storefront-client.d.ts +42 -0
  132. package/dist/react/server/get-storefront-client.d.ts.map +1 -0
  133. package/dist/react/server/get-storefront-client.js +44 -0
  134. package/dist/react/server/index.d.ts +2 -0
  135. package/dist/react/server/index.d.ts.map +1 -0
  136. package/dist/react/server/index.js +1 -0
  137. package/dist/react/stores/auth.store.d.ts +48 -0
  138. package/dist/react/stores/auth.store.d.ts.map +1 -0
  139. package/dist/react/stores/auth.store.js +67 -0
  140. package/dist/react/stores/currency.store.d.ts +29 -0
  141. package/dist/react/stores/currency.store.d.ts.map +1 -0
  142. package/dist/react/stores/currency.store.js +76 -0
  143. package/dist/react/stores/index.d.ts +8 -0
  144. package/dist/react/stores/index.d.ts.map +1 -0
  145. package/dist/react/stores/index.js +10 -0
  146. package/dist/react/stores/store-context.d.ts +27 -0
  147. package/dist/react/stores/store-context.d.ts.map +1 -0
  148. package/dist/react/stores/store-context.js +62 -0
  149. package/package.json +71 -0
  150. package/src/__tests__/contract/storefront-api.contract.test.ts +450 -0
  151. package/src/__tests__/unit/auth-client.test.ts +210 -0
  152. package/src/__tests__/unit/cart-client.test.ts +233 -0
  153. package/src/__tests__/unit/create-client.test.ts +356 -0
  154. package/src/__tests__/unit/helpers.test.ts +377 -0
  155. package/src/__tests__/unit/middleware.test.ts +374 -0
  156. package/src/__tests__/unit/test-helpers.ts +103 -0
  157. package/src/core/auth/auth-client.ts +123 -0
  158. package/src/core/auth/cookie-config.ts +23 -0
  159. package/src/core/auth/handlers.ts +168 -0
  160. package/src/core/auth/routes.ts +26 -0
  161. package/src/core/auth/token-client.ts +51 -0
  162. package/src/core/auth/types.ts +54 -0
  163. package/src/core/cache.ts +102 -0
  164. package/src/core/cart/cart-client.ts +150 -0
  165. package/src/core/cart/types.ts +104 -0
  166. package/src/core/client/compose.ts +15 -0
  167. package/src/core/client/create-client.ts +129 -0
  168. package/src/core/client/dedupe.ts +19 -0
  169. package/src/core/client/execute.ts +70 -0
  170. package/src/core/client/hash.ts +21 -0
  171. package/src/core/client/operation-name.ts +12 -0
  172. package/src/core/client/types.ts +171 -0
  173. package/src/core/errors.ts +67 -0
  174. package/src/core/format.ts +254 -0
  175. package/src/core/helpers/assert-no-user-errors.ts +21 -0
  176. package/src/core/helpers/normalize-connection.ts +48 -0
  177. package/src/core/helpers/sanitize-html.ts +42 -0
  178. package/src/core/index.ts +148 -0
  179. package/src/core/middleware/auth.ts +27 -0
  180. package/src/core/middleware/currency.ts +26 -0
  181. package/src/core/middleware/errors.ts +86 -0
  182. package/src/core/middleware/retry.ts +75 -0
  183. package/src/core/middleware/timeout.ts +61 -0
  184. package/src/core/operations/auth.ts +123 -0
  185. package/src/core/operations/cart.ts +185 -0
  186. package/src/index.ts +25 -0
  187. package/src/react/cookies.ts +54 -0
  188. package/src/react/helpers/create-store-context.ts +56 -0
  189. package/src/react/hooks/use-auth.ts +218 -0
  190. package/src/react/hooks/use-cart-manager.ts +236 -0
  191. package/src/react/hooks/use-currency.ts +23 -0
  192. package/src/react/hooks/use-debounced-value.ts +30 -0
  193. package/src/react/hooks/use-hydrated.ts +20 -0
  194. package/src/react/hooks/use-storefront-client.ts +12 -0
  195. package/src/react/index.ts +45 -0
  196. package/src/react/providers/currency-provider.tsx +30 -0
  197. package/src/react/providers/storefront-client-provider.tsx +90 -0
  198. package/src/react/providers/storefront-provider.tsx +71 -0
  199. package/src/react/server/get-storefront-client.ts +60 -0
  200. package/src/react/server/index.ts +1 -0
  201. package/src/react/stores/auth.store.ts +112 -0
  202. package/src/react/stores/currency.store.ts +113 -0
  203. package/src/react/stores/index.ts +17 -0
  204. package/src/react/stores/store-context.tsx +82 -0
  205. package/tsconfig.json +20 -0
  206. package/vitest.config.ts +14 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * StorefrontError — unified error class for all SDK errors.
3
+ *
4
+ * Normalizes GraphQL errors, network errors, user errors, and timeouts
5
+ * into a single throwable type with structured data.
6
+ */
7
+ import type { GraphQLErrorInfo, UserError } from './client/types';
8
+ export interface StorefrontErrorOptions {
9
+ /** Error code for programmatic handling */
10
+ code: string;
11
+ /** Human-readable message */
12
+ message: string;
13
+ /** HTTP status code (0 for network errors) */
14
+ status?: number;
15
+ /** GraphQL-level errors from the response */
16
+ graphqlErrors?: GraphQLErrorInfo[];
17
+ /** User errors from mutations (field-level validation) */
18
+ userErrors?: UserError[];
19
+ /** Original error (if wrapping) */
20
+ cause?: unknown;
21
+ }
22
+ export declare class StorefrontError extends Error {
23
+ readonly code: string;
24
+ readonly status: number;
25
+ readonly graphqlErrors: GraphQLErrorInfo[];
26
+ readonly userErrors: UserError[];
27
+ constructor(options: StorefrontErrorOptions);
28
+ /** True if this error contains user errors (field-level validation) */
29
+ get hasUserErrors(): boolean;
30
+ /** True if this is a network error (no HTTP response) */
31
+ get isNetworkError(): boolean;
32
+ /** True if the request timed out */
33
+ get isTimeout(): boolean;
34
+ }
35
+ export declare const ErrorCodes: {
36
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
37
+ readonly TIMEOUT: "TIMEOUT";
38
+ readonly HTTP_ERROR: "HTTP_ERROR";
39
+ readonly GRAPHQL_ERROR: "GRAPHQL_ERROR";
40
+ readonly USER_ERROR: "USER_ERROR";
41
+ readonly NO_DATA: "NO_DATA";
42
+ };
43
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,WAAW,sBAAsB;IACrC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACnC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;gBAErB,OAAO,EAAE,sBAAsB;IAS3C,uEAAuE;IACvE,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,yDAAyD;IACzD,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,oCAAoC;IACpC,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF;AAMD,eAAO,MAAM,UAAU;;;;;;;CAOb,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * StorefrontError — unified error class for all SDK errors.
3
+ *
4
+ * Normalizes GraphQL errors, network errors, user errors, and timeouts
5
+ * into a single throwable type with structured data.
6
+ */
7
+ export class StorefrontError extends Error {
8
+ code;
9
+ status;
10
+ graphqlErrors;
11
+ userErrors;
12
+ constructor(options) {
13
+ super(options.message, { cause: options.cause });
14
+ this.name = 'StorefrontError';
15
+ this.code = options.code;
16
+ this.status = options.status ?? 0;
17
+ this.graphqlErrors = options.graphqlErrors ?? [];
18
+ this.userErrors = options.userErrors ?? [];
19
+ }
20
+ /** True if this error contains user errors (field-level validation) */
21
+ get hasUserErrors() {
22
+ return this.userErrors.length > 0;
23
+ }
24
+ /** True if this is a network error (no HTTP response) */
25
+ get isNetworkError() {
26
+ return this.code === 'NETWORK_ERROR';
27
+ }
28
+ /** True if the request timed out */
29
+ get isTimeout() {
30
+ return this.code === 'TIMEOUT';
31
+ }
32
+ }
33
+ // ---------------------------------------------------------------------------
34
+ // Error codes
35
+ // ---------------------------------------------------------------------------
36
+ export const ErrorCodes = {
37
+ NETWORK_ERROR: 'NETWORK_ERROR',
38
+ TIMEOUT: 'TIMEOUT',
39
+ HTTP_ERROR: 'HTTP_ERROR',
40
+ GRAPHQL_ERROR: 'GRAPHQL_ERROR',
41
+ USER_ERROR: 'USER_ERROR',
42
+ NO_DATA: 'NO_DATA',
43
+ };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Formatting Utilities
3
+ *
4
+ * Pure functions for formatting prices, dates, numbers.
5
+ * 0 runtime dependencies — works in Node.js, Edge, Deno, Bun.
6
+ */
7
+ export interface PriceMoney {
8
+ amount: string;
9
+ currencyCode: string;
10
+ }
11
+ /** Currency symbols mapping */
12
+ export declare const CURRENCY_SYMBOLS: Record<string, string>;
13
+ /** Currency locale mapping for proper formatting */
14
+ export declare const CURRENCY_LOCALES: Record<string, string>;
15
+ /**
16
+ * Get currency symbol
17
+ */
18
+ export declare function getCurrencySymbol(code: string): string;
19
+ /**
20
+ * Format price with currency symbol
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * formatPrice({ amount: "99.99", currencyCode: "USD" })
25
+ * // => "$99.99"
26
+ * ```
27
+ */
28
+ export declare function formatPrice(price: PriceMoney | null | undefined): string;
29
+ /**
30
+ * Format price range
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * formatPriceRange(
35
+ * { amount: "10.00", currencyCode: "USD" },
36
+ * { amount: "50.00", currencyCode: "USD" }
37
+ * )
38
+ * // => "$10.00 - $50.00"
39
+ * ```
40
+ */
41
+ export declare function formatPriceRange(minPrice: PriceMoney, maxPrice: PriceMoney): string;
42
+ /**
43
+ * Format amount with currency
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const formatted = formatAmount("115.20", "EUR");
48
+ * // => "115,20 €"
49
+ * ```
50
+ */
51
+ export declare function formatAmount(amount: string | number, currencyCode: string): string;
52
+ /**
53
+ * Format date to locale string
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * formatDate(new Date())
58
+ * // => "Dec 9, 2025"
59
+ * ```
60
+ */
61
+ export declare function formatDate(date: Date | string): string;
62
+ /**
63
+ * Format date with time
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * formatDateTime(new Date())
68
+ * // => "Dec 9, 2025, 10:30 PM"
69
+ * ```
70
+ */
71
+ export declare function formatDateTime(date: Date | string): string;
72
+ /**
73
+ * Format number with thousands separator
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * formatNumber(1234567)
78
+ * // => "1,234,567"
79
+ * ```
80
+ */
81
+ export declare function formatNumber(num: number): string;
82
+ /**
83
+ * Format percentage
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * formatPercentage(0.15)
88
+ * // => "15%"
89
+ * ```
90
+ */
91
+ export declare function formatPercentage(value: number): string;
92
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/core/format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAMD,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAcnD,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAcnD,CAAC;AA+CF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAaxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAMR;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB,MAAM,CAUR;AAMD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAQtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAU1D;AAMD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Formatting Utilities
3
+ *
4
+ * Pure functions for formatting prices, dates, numbers.
5
+ * 0 runtime dependencies — works in Node.js, Edge, Deno, Bun.
6
+ */
7
+ // ============================================================================
8
+ // CONSTANTS
9
+ // ============================================================================
10
+ /** Currency symbols mapping */
11
+ export const CURRENCY_SYMBOLS = {
12
+ PLN: 'zł',
13
+ EUR: '€',
14
+ USD: '$',
15
+ GBP: '£',
16
+ CHF: 'CHF',
17
+ CZK: 'Kč',
18
+ SEK: 'kr',
19
+ NOK: 'kr',
20
+ DKK: 'kr',
21
+ JPY: '¥',
22
+ CNY: '¥',
23
+ AUD: 'A$',
24
+ CAD: 'C$',
25
+ };
26
+ /** Currency locale mapping for proper formatting */
27
+ export const CURRENCY_LOCALES = {
28
+ PLN: 'pl-PL',
29
+ EUR: 'de-DE',
30
+ USD: 'en-US',
31
+ GBP: 'en-GB',
32
+ CHF: 'de-CH',
33
+ CZK: 'cs-CZ',
34
+ SEK: 'sv-SE',
35
+ NOK: 'nb-NO',
36
+ DKK: 'da-DK',
37
+ JPY: 'ja-JP',
38
+ CNY: 'zh-CN',
39
+ AUD: 'en-AU',
40
+ CAD: 'en-CA',
41
+ };
42
+ // ============================================================================
43
+ // FORMATTER CACHE (avoids re-creating Intl objects on every call)
44
+ // ============================================================================
45
+ const numberFormatCache = new Map();
46
+ const dateFormatCache = new Map();
47
+ function getCurrencyFormatter(locale, currency) {
48
+ const key = `${locale}:${currency}`;
49
+ let fmt = numberFormatCache.get(key);
50
+ if (!fmt) {
51
+ fmt = new Intl.NumberFormat(locale, {
52
+ style: 'currency',
53
+ currency,
54
+ minimumFractionDigits: 2,
55
+ maximumFractionDigits: 2,
56
+ });
57
+ numberFormatCache.set(key, fmt);
58
+ }
59
+ return fmt;
60
+ }
61
+ function getNumberFormatter(locale) {
62
+ let fmt = numberFormatCache.get(locale);
63
+ if (!fmt) {
64
+ fmt = new Intl.NumberFormat(locale);
65
+ numberFormatCache.set(locale, fmt);
66
+ }
67
+ return fmt;
68
+ }
69
+ function getDateFormatter(locale, options) {
70
+ const key = `${locale}:${JSON.stringify(options)}`;
71
+ let fmt = dateFormatCache.get(key);
72
+ if (!fmt) {
73
+ fmt = new Intl.DateTimeFormat(locale, options);
74
+ dateFormatCache.set(key, fmt);
75
+ }
76
+ return fmt;
77
+ }
78
+ // ============================================================================
79
+ // UTILITY FUNCTIONS
80
+ // ============================================================================
81
+ /**
82
+ * Get currency symbol
83
+ */
84
+ export function getCurrencySymbol(code) {
85
+ return CURRENCY_SYMBOLS[code] || code;
86
+ }
87
+ // ============================================================================
88
+ // PRICE FORMATTING
89
+ // ============================================================================
90
+ /**
91
+ * Format price with currency symbol
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * formatPrice({ amount: "99.99", currencyCode: "USD" })
96
+ * // => "$99.99"
97
+ * ```
98
+ */
99
+ export function formatPrice(price) {
100
+ if (!price)
101
+ return '';
102
+ const amount = parseFloat(price.amount);
103
+ const code = price.currencyCode;
104
+ const locale = CURRENCY_LOCALES[code] || 'en-US';
105
+ try {
106
+ return getCurrencyFormatter(locale, code).format(amount);
107
+ }
108
+ catch {
109
+ const symbol = CURRENCY_SYMBOLS[code] || code;
110
+ return `${amount.toFixed(2)} ${symbol}`;
111
+ }
112
+ }
113
+ /**
114
+ * Format price range
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * formatPriceRange(
119
+ * { amount: "10.00", currencyCode: "USD" },
120
+ * { amount: "50.00", currencyCode: "USD" }
121
+ * )
122
+ * // => "$10.00 - $50.00"
123
+ * ```
124
+ */
125
+ export function formatPriceRange(minPrice, maxPrice) {
126
+ if (minPrice.amount === maxPrice.amount) {
127
+ return formatPrice(minPrice);
128
+ }
129
+ return `${formatPrice(minPrice)} - ${formatPrice(maxPrice)}`;
130
+ }
131
+ /**
132
+ * Format amount with currency
133
+ *
134
+ * @example
135
+ * ```tsx
136
+ * const formatted = formatAmount("115.20", "EUR");
137
+ * // => "115,20 €"
138
+ * ```
139
+ */
140
+ export function formatAmount(amount, currencyCode) {
141
+ const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
142
+ const locale = CURRENCY_LOCALES[currencyCode] || 'en-US';
143
+ try {
144
+ return getCurrencyFormatter(locale, currencyCode).format(numAmount);
145
+ }
146
+ catch {
147
+ const symbol = CURRENCY_SYMBOLS[currencyCode] || currencyCode;
148
+ return `${numAmount.toFixed(2)} ${symbol}`;
149
+ }
150
+ }
151
+ // ============================================================================
152
+ // DATE FORMATTING
153
+ // ============================================================================
154
+ /**
155
+ * Format date to locale string
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * formatDate(new Date())
160
+ * // => "Dec 9, 2025"
161
+ * ```
162
+ */
163
+ export function formatDate(date) {
164
+ const d = typeof date === 'string' ? new Date(date) : date;
165
+ return getDateFormatter('en-US', {
166
+ year: 'numeric',
167
+ month: 'short',
168
+ day: 'numeric',
169
+ }).format(d);
170
+ }
171
+ /**
172
+ * Format date with time
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * formatDateTime(new Date())
177
+ * // => "Dec 9, 2025, 10:30 PM"
178
+ * ```
179
+ */
180
+ export function formatDateTime(date) {
181
+ const d = typeof date === 'string' ? new Date(date) : date;
182
+ return getDateFormatter('en-US', {
183
+ year: 'numeric',
184
+ month: 'short',
185
+ day: 'numeric',
186
+ hour: 'numeric',
187
+ minute: '2-digit',
188
+ }).format(d);
189
+ }
190
+ // ============================================================================
191
+ // NUMBER FORMATTING
192
+ // ============================================================================
193
+ /**
194
+ * Format number with thousands separator
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * formatNumber(1234567)
199
+ * // => "1,234,567"
200
+ * ```
201
+ */
202
+ export function formatNumber(num) {
203
+ return getNumberFormatter('en-US').format(num);
204
+ }
205
+ /**
206
+ * Format percentage
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * formatPercentage(0.15)
211
+ * // => "15%"
212
+ * ```
213
+ */
214
+ export function formatPercentage(value) {
215
+ return `${Math.round(value * 100)}%`;
216
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Auto-throw on userErrors — used internally by CartClient and AuthClient.
3
+ *
4
+ * Frontend code doesn't need to manually check `if (userErrors.length)`.
5
+ */
6
+ import type { UserError } from '../client/types';
7
+ export declare function assertNoUserErrors(result: {
8
+ userErrors?: UserError[] | null;
9
+ }): void;
10
+ //# sourceMappingURL=assert-no-user-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-no-user-errors.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/assert-no-user-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;CAAE,GAC1C,IAAI,CASN"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Auto-throw on userErrors — used internally by CartClient and AuthClient.
3
+ *
4
+ * Frontend code doesn't need to manually check `if (userErrors.length)`.
5
+ */
6
+ import { StorefrontError, ErrorCodes } from '../errors';
7
+ export function assertNoUserErrors(result) {
8
+ if (result.userErrors && result.userErrors.length > 0) {
9
+ const firstError = result.userErrors[0];
10
+ throw new StorefrontError({
11
+ code: ErrorCodes.USER_ERROR,
12
+ message: firstError.message,
13
+ userErrors: result.userErrors,
14
+ });
15
+ }
16
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Relay-style GraphQL connection normalizer.
3
+ *
4
+ * Converts `{ edges: [{ node }], pageInfo, totalCount }` → flat array.
5
+ * Pure function, 0 deps, works everywhere.
6
+ */
7
+ export interface ConnectionEdge<T> {
8
+ node: T;
9
+ cursor: string;
10
+ }
11
+ export interface ConnectionPageInfo {
12
+ hasNextPage: boolean;
13
+ hasPreviousPage: boolean;
14
+ startCursor?: string | null;
15
+ endCursor?: string | null;
16
+ }
17
+ export interface Connection<T> {
18
+ edges: ConnectionEdge<T>[];
19
+ pageInfo: ConnectionPageInfo;
20
+ totalCount?: number;
21
+ }
22
+ export interface NormalizedConnection<T> {
23
+ items: T[];
24
+ pageInfo: ConnectionPageInfo;
25
+ totalCount?: number;
26
+ }
27
+ /**
28
+ * Normalize a GraphQL Relay connection to a flat array.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const { items, pageInfo, totalCount } = normalizeConnection(data.products);
33
+ * ```
34
+ */
35
+ export declare function normalizeConnection<T>(connection: Connection<T>): NormalizedConnection<T>;
36
+ //# sourceMappingURL=normalize-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-connection.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/normalize-connection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GACxB,oBAAoB,CAAC,CAAC,CAAC,CAMzB"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Relay-style GraphQL connection normalizer.
3
+ *
4
+ * Converts `{ edges: [{ node }], pageInfo, totalCount }` → flat array.
5
+ * Pure function, 0 deps, works everywhere.
6
+ */
7
+ /**
8
+ * Normalize a GraphQL Relay connection to a flat array.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const { items, pageInfo, totalCount } = normalizeConnection(data.products);
13
+ * ```
14
+ */
15
+ export function normalizeConnection(connection) {
16
+ return {
17
+ items: connection.edges.map((edge) => edge.node),
18
+ pageInfo: connection.pageInfo,
19
+ totalCount: connection.totalCount,
20
+ };
21
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Lightweight HTML sanitizer for defense-in-depth.
3
+ * Primary sanitization happens on the backend (sanitize-html library).
4
+ * This strips dangerous tags/attributes as an extra safety layer.
5
+ * Works in both Node.js and Edge runtimes (no external dependencies).
6
+ */
7
+ export declare function sanitizeHtml(html: string): string;
8
+ //# sourceMappingURL=sanitize-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-html.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAajD"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Lightweight HTML sanitizer for defense-in-depth.
3
+ * Primary sanitization happens on the backend (sanitize-html library).
4
+ * This strips dangerous tags/attributes as an extra safety layer.
5
+ * Works in both Node.js and Edge runtimes (no external dependencies).
6
+ */
7
+ const DANGEROUS_TAG_PATTERNS = [
8
+ // Tags with content that must be fully removed
9
+ /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script\s*>/gi,
10
+ /<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe\s*>/gi,
11
+ /<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object\s*>/gi,
12
+ /<form\b[^<]*(?:(?!<\/form>)<[^<]*)*<\/form\s*>/gi,
13
+ /<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style\s*>/gi,
14
+ // Self-closing / void dangerous tags
15
+ /<embed\b[^>]*\/?>/gi,
16
+ /<link\b[^>]*\/?>/gi,
17
+ /<meta\b[^>]*\/?>/gi,
18
+ /<base\b[^>]*\/?>/gi,
19
+ /<applet\b[^<]*(?:(?!<\/applet>)<[^<]*)*<\/applet\s*>/gi,
20
+ ];
21
+ // Event handler attributes (onclick, onerror, onload, etc.)
22
+ const EVENT_HANDLER_PATTERN = /\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi;
23
+ // javascript: protocol in href/src/action attributes
24
+ const JS_PROTOCOL_PATTERN = /(href|src|action)\s*=\s*["']\s*javascript\s*:/gi;
25
+ export function sanitizeHtml(html) {
26
+ if (!html)
27
+ return html;
28
+ let result = html;
29
+ for (const pattern of DANGEROUS_TAG_PATTERNS) {
30
+ result = result.replace(pattern, '');
31
+ }
32
+ result = result.replace(EVENT_HANDLER_PATTERN, '');
33
+ result = result.replace(JS_PROTOCOL_PATTERN, '$1="');
34
+ return result;
35
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @doswiftly/storefront-sdk — Core (framework-agnostic)
3
+ *
4
+ * 100% framework-agnostic, 0 runtime dependencies.
5
+ * Works in Node.js, Edge Workers, Deno, Bun, CLI scripts — without React.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import {
10
+ * createStorefrontClient,
11
+ * authMiddleware,
12
+ * currencyMiddleware,
13
+ * retryMiddleware,
14
+ * timeoutMiddleware,
15
+ * errorMiddleware,
16
+ * CartClient,
17
+ * AuthClient,
18
+ * } from '@doswiftly/storefront-sdk';
19
+ *
20
+ * const client = createStorefrontClient({
21
+ * apiUrl: 'https://api.doswiftly.pl',
22
+ * shopSlug: 'my-shop',
23
+ * middleware: [
24
+ * authMiddleware(() => getToken()),
25
+ * currencyMiddleware(() => getCurrency()),
26
+ * retryMiddleware({ maxRetries: 2 }),
27
+ * timeoutMiddleware({ timeout: 5000 }),
28
+ * errorMiddleware(),
29
+ * ],
30
+ * });
31
+ *
32
+ * const cartClient = new CartClient(client);
33
+ * const cart = await cartClient.create();
34
+ * ```
35
+ */
36
+ export { createStorefrontClient } from './client/create-client';
37
+ export type { StorefrontClient, StorefrontClientConfig, Middleware, ExecuteFn, GraphQLRequest, GraphQLResponse, GraphQLErrorInfo, UserError, CacheStrategy, CacheOptions, TypedDocumentString, } from './client/types';
38
+ export { authMiddleware } from './middleware/auth';
39
+ export { currencyMiddleware } from './middleware/currency';
40
+ export { retryMiddleware, type RetryOptions } from './middleware/retry';
41
+ export { timeoutMiddleware, type TimeoutOptions } from './middleware/timeout';
42
+ export { errorMiddleware } from './middleware/errors';
43
+ export { StorefrontError, ErrorCodes, type StorefrontErrorOptions } from './errors';
44
+ export { cacheNone, cacheShort, cacheLong, cachePrivate, cacheCustom, generateCacheControlHeader, type CacheOverrides, } from './cache';
45
+ export { CartClient } from './cart/cart-client';
46
+ export type { Cart, CartLine, CartLineMerchandise, CartLineCost, CartCost, CartBuyerIdentity, CartDiscountCode, CartDiscountAllocation, CartLineInput, CartLineUpdateInput, CartCreateInput, CartBuyerIdentityInput, Money, } from './cart/types';
47
+ export { AuthClient } from './auth/auth-client';
48
+ export type { Customer, CustomerAccessToken, MailingAddress, AuthResult, CustomerCreateInput, } from './auth/types';
49
+ export { assertNoUserErrors } from './helpers/assert-no-user-errors';
50
+ export { sanitizeHtml } from './helpers/sanitize-html';
51
+ export { normalizeConnection, type Connection, type ConnectionEdge, type ConnectionPageInfo, type NormalizedConnection, } from './helpers/normalize-connection';
52
+ export { formatPrice, formatPriceRange, formatAmount, formatDate, formatDateTime, formatNumber, formatPercentage, getCurrencySymbol, CURRENCY_SYMBOLS, CURRENCY_LOCALES, type PriceMoney, } from './format';
53
+ export { AUTH_COOKIE_NAME, AUTH_COOKIE_DEFAULTS, type AuthCookieConfig, } from './auth/cookie-config';
54
+ export { matchesRoute, type RouteProtectionConfig } from './auth/routes';
55
+ export { createSetTokenHandler, createClearTokenHandler } from './auth/handlers';
56
+ export { createAuthTokenClient, type AuthTokenClient } from './auth/token-client';
57
+ export { getOperationName } from './client/operation-name';
58
+ export { hashQuery } from './client/hash';
59
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,UAAU,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,KAAK,cAAc,GACpB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EACV,IAAI,EACJ,QAAQ,EACR,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,KAAK,GACN,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,UAAU,GAChB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,gBAAgB,GACtB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGzE,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAGjF,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGlF,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}