oneentry 1.0.159 → 1.0.161

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 (222) hide show
  1. package/README.md +2 -0
  2. package/changelog.md +56 -1
  3. package/dist/admins/adminsApi.d.ts +15 -1
  4. package/dist/admins/adminsApi.js +29 -0
  5. package/dist/admins/adminsInterfaces.d.ts +37 -1
  6. package/dist/base/lazySchema.d.ts +15 -0
  7. package/dist/base/lazySchema.js +20 -0
  8. package/dist/discounts/discountsApi.d.ts +14 -1
  9. package/dist/discounts/discountsApi.js +21 -0
  10. package/dist/discounts/discountsInterfaces.d.ts +27 -1
  11. package/dist/filters/filtersInterfaces.d.ts +2 -2
  12. package/dist/filters/filtersSchemas.d.ts +1 -1
  13. package/dist/filters/filtersSchemas.js +4 -1
  14. package/dist/forms-data/formsDataApi.d.ts +14 -1
  15. package/dist/forms-data/formsDataApi.js +21 -0
  16. package/dist/forms-data/formsDataInterfaces.d.ts +74 -1
  17. package/dist/index.d.ts +4 -0
  18. package/dist/index.js +3 -0
  19. package/dist/orders/ordersApi.d.ts +15 -1
  20. package/dist/orders/ordersApi.js +22 -0
  21. package/dist/orders/ordersInterfaces.d.ts +27 -1
  22. package/dist/pages/pagesApi.d.ts +14 -1
  23. package/dist/pages/pagesApi.js +21 -0
  24. package/dist/pages/pagesInterfaces.d.ts +38 -1
  25. package/dist/payments/paymentsInterfaces.d.ts +2 -2
  26. package/dist/products/productsInterfaces.d.ts +1 -1
  27. package/dist/search/searchApi.d.ts +35 -0
  28. package/dist/search/searchApi.js +86 -0
  29. package/dist/search/searchInterfaces.d.ts +94 -0
  30. package/dist/search/searchInterfaces.js +2 -0
  31. package/dist/search/searchSchemas.d.ts +73 -0
  32. package/dist/search/searchSchemas.js +44 -0
  33. package/dist/templates-preview/templatesPreviewInterfaces.d.ts +0 -2
  34. package/dist/templates-preview/templatesPreviewSchemas.d.ts +0 -2
  35. package/dist/templates-preview/templatesPreviewSchemas.js +0 -1
  36. package/dist/types.d.ts +35 -0
  37. package/dist/types.js +2 -0
  38. package/dist/users/usersApi.d.ts +15 -1
  39. package/dist/users/usersApi.js +22 -0
  40. package/dist/users/usersInterfaces.d.ts +39 -1
  41. package/dist/web-socket/lazySocket.d.ts +18 -0
  42. package/dist/web-socket/lazySocket.js +70 -0
  43. package/esm/admins/adminsApi.d.ts +66 -0
  44. package/esm/admins/adminsApi.js +90 -0
  45. package/esm/admins/adminsInterfaces.d.ts +137 -0
  46. package/esm/admins/adminsInterfaces.js +1 -0
  47. package/esm/admins/adminsSchemas.d.ts +48 -0
  48. package/esm/admins/adminsSchemas.js +31 -0
  49. package/esm/attribute-sets/attributeSetsApi.d.ts +67 -0
  50. package/esm/attribute-sets/attributeSetsApi.js +97 -0
  51. package/esm/attribute-sets/attributeSetsInterfaces.d.ts +285 -0
  52. package/esm/attribute-sets/attributeSetsInterfaces.js +1 -0
  53. package/esm/attribute-sets/attributeSetsSchemas.d.ts +84 -0
  54. package/esm/attribute-sets/attributeSetsSchemas.js +66 -0
  55. package/esm/auth-provider/authProviderApi.d.ts +262 -0
  56. package/esm/auth-provider/authProviderApi.js +362 -0
  57. package/esm/auth-provider/authProviderSchemas.d.ts +124 -0
  58. package/esm/auth-provider/authProviderSchemas.js +92 -0
  59. package/esm/auth-provider/authProvidersInterfaces.d.ts +430 -0
  60. package/esm/auth-provider/authProvidersInterfaces.js +1 -0
  61. package/esm/base/asyncModules.d.ts +123 -0
  62. package/esm/base/asyncModules.js +382 -0
  63. package/esm/base/lazySchema.d.ts +15 -0
  64. package/esm/base/lazySchema.js +17 -0
  65. package/esm/base/stateModule.d.ts +35 -0
  66. package/esm/base/stateModule.js +51 -0
  67. package/esm/base/syncModules.d.ts +245 -0
  68. package/esm/base/syncModules.js +555 -0
  69. package/esm/base/timeIntervals.d.ts +95 -0
  70. package/esm/base/timeIntervals.js +317 -0
  71. package/esm/base/utils.d.ts +354 -0
  72. package/esm/base/utils.js +1 -0
  73. package/esm/base/validation.d.ts +98 -0
  74. package/esm/base/validation.js +118 -0
  75. package/esm/blocks/blocksApi.d.ts +252 -0
  76. package/esm/blocks/blocksApi.js +394 -0
  77. package/esm/blocks/blocksInterfaces.d.ts +361 -0
  78. package/esm/blocks/blocksInterfaces.js +1 -0
  79. package/esm/blocks/blocksSchemas.d.ts +213 -0
  80. package/esm/blocks/blocksSchemas.js +40 -0
  81. package/esm/discounts/discountsApi.d.ts +94 -0
  82. package/esm/discounts/discountsApi.js +136 -0
  83. package/esm/discounts/discountsInterfaces.d.ts +293 -0
  84. package/esm/discounts/discountsInterfaces.js +1 -0
  85. package/esm/events/eventsApi.d.ts +108 -0
  86. package/esm/events/eventsApi.js +141 -0
  87. package/esm/events/eventsInterfaces.d.ts +176 -0
  88. package/esm/events/eventsInterfaces.js +1 -0
  89. package/esm/file-uploading/fileUploadingApi.d.ts +91 -0
  90. package/esm/file-uploading/fileUploadingApi.js +127 -0
  91. package/esm/file-uploading/fileUploadingInterfaces.d.ts +116 -0
  92. package/esm/file-uploading/fileUploadingInterfaces.js +1 -0
  93. package/esm/file-uploading/fileUploadingSchemas.d.ts +24 -0
  94. package/esm/file-uploading/fileUploadingSchemas.js +19 -0
  95. package/esm/filters/filtersApi.d.ts +32 -0
  96. package/esm/filters/filtersApi.js +36 -0
  97. package/esm/filters/filtersInterfaces.d.ts +56 -0
  98. package/esm/filters/filtersInterfaces.js +1 -0
  99. package/esm/filters/filtersSchemas.d.ts +32 -0
  100. package/esm/filters/filtersSchemas.js +29 -0
  101. package/esm/forms/formsApi.d.ts +44 -0
  102. package/esm/forms/formsApi.js +54 -0
  103. package/esm/forms/formsInterfaces.d.ts +237 -0
  104. package/esm/forms/formsInterfaces.js +1 -0
  105. package/esm/forms/formsSchemas.d.ts +56 -0
  106. package/esm/forms/formsSchemas.js +32 -0
  107. package/esm/forms-data/formsDataApi.d.ts +124 -0
  108. package/esm/forms-data/formsDataApi.js +210 -0
  109. package/esm/forms-data/formsDataInterfaces.d.ts +670 -0
  110. package/esm/forms-data/formsDataInterfaces.js +1 -0
  111. package/esm/forms-data/formsDataSchemas.d.ts +107 -0
  112. package/esm/forms-data/formsDataSchemas.js +83 -0
  113. package/esm/general-types/generalTypesApi.d.ts +29 -0
  114. package/esm/general-types/generalTypesApi.js +34 -0
  115. package/esm/general-types/generalTypesInterfaces.d.ts +29 -0
  116. package/esm/general-types/generalTypesInterfaces.js +1 -0
  117. package/esm/general-types/generalTypesSchemas.d.ts +68 -0
  118. package/esm/general-types/generalTypesSchemas.js +42 -0
  119. package/esm/index.d.ts +143 -0
  120. package/esm/index.js +124 -0
  121. package/esm/integration-collections/integrationCollectionsApi.d.ts +172 -0
  122. package/esm/integration-collections/integrationCollectionsApi.js +224 -0
  123. package/esm/integration-collections/integrationCollectionsInterfaces.d.ts +317 -0
  124. package/esm/integration-collections/integrationCollectionsInterfaces.js +1 -0
  125. package/esm/integration-collections/integrationCollectionsSchemas.d.ts +84 -0
  126. package/esm/integration-collections/integrationCollectionsSchemas.js +60 -0
  127. package/esm/locales/localesApi.d.ts +28 -0
  128. package/esm/locales/localesApi.js +33 -0
  129. package/esm/locales/localesInterfaces.d.ts +40 -0
  130. package/esm/locales/localesInterfaces.js +1 -0
  131. package/esm/locales/localesSchemas.d.ts +32 -0
  132. package/esm/locales/localesSchemas.js +23 -0
  133. package/esm/menus/menusApi.d.ts +30 -0
  134. package/esm/menus/menusApi.js +35 -0
  135. package/esm/menus/menusInterfaces.d.ts +87 -0
  136. package/esm/menus/menusInterfaces.js +2 -0
  137. package/esm/menus/menusSchemas.d.ts +16 -0
  138. package/esm/menus/menusSchemas.js +25 -0
  139. package/esm/orders/ordersApi.d.ts +213 -0
  140. package/esm/orders/ordersApi.js +288 -0
  141. package/esm/orders/ordersInterfaces.d.ts +763 -0
  142. package/esm/orders/ordersInterfaces.js +1 -0
  143. package/esm/orders/ordersSchemas.d.ts +312 -0
  144. package/esm/orders/ordersSchemas.js +171 -0
  145. package/esm/package.json +4 -0
  146. package/esm/pages/pagesApi.d.ts +173 -0
  147. package/esm/pages/pagesApi.js +414 -0
  148. package/esm/pages/pagesInterfaces.d.ts +344 -0
  149. package/esm/pages/pagesInterfaces.js +1 -0
  150. package/esm/pages/pagesSchemas.d.ts +121 -0
  151. package/esm/pages/pagesSchemas.js +60 -0
  152. package/esm/payments/paymentsApi.d.ts +88 -0
  153. package/esm/payments/paymentsApi.js +122 -0
  154. package/esm/payments/paymentsInterfaces.d.ts +189 -0
  155. package/esm/payments/paymentsInterfaces.js +1 -0
  156. package/esm/payments/paymentsSchemas.d.ts +94 -0
  157. package/esm/payments/paymentsSchemas.js +53 -0
  158. package/esm/product-statuses/productStatusesApi.d.ts +50 -0
  159. package/esm/product-statuses/productStatusesApi.js +68 -0
  160. package/esm/product-statuses/productStatusesInterfaces.d.ts +62 -0
  161. package/esm/product-statuses/productStatusesInterfaces.js +1 -0
  162. package/esm/product-statuses/productStatusesSchemas.d.ts +34 -0
  163. package/esm/product-statuses/productStatusesSchemas.js +27 -0
  164. package/esm/products/productsApi.d.ts +366 -0
  165. package/esm/products/productsApi.js +468 -0
  166. package/esm/products/productsInterfaces.d.ts +723 -0
  167. package/esm/products/productsInterfaces.js +1 -0
  168. package/esm/products/productsSchemas.d.ts +234 -0
  169. package/esm/products/productsSchemas.js +121 -0
  170. package/esm/search/searchApi.d.ts +35 -0
  171. package/esm/search/searchApi.js +47 -0
  172. package/esm/search/searchInterfaces.d.ts +94 -0
  173. package/esm/search/searchInterfaces.js +1 -0
  174. package/esm/search/searchSchemas.d.ts +73 -0
  175. package/esm/search/searchSchemas.js +41 -0
  176. package/esm/sitemap/sitemapApi.d.ts +37 -0
  177. package/esm/sitemap/sitemapApi.js +41 -0
  178. package/esm/sitemap/sitemapInterfaces.d.ts +51 -0
  179. package/esm/sitemap/sitemapInterfaces.js +1 -0
  180. package/esm/subscriptions/subscriptionsApi.d.ts +74 -0
  181. package/esm/subscriptions/subscriptionsApi.js +90 -0
  182. package/esm/subscriptions/subscriptionsInterfaces.d.ts +111 -0
  183. package/esm/subscriptions/subscriptionsInterfaces.js +1 -0
  184. package/esm/subscriptions/subscriptionsSchemas.d.ts +46 -0
  185. package/esm/subscriptions/subscriptionsSchemas.js +38 -0
  186. package/esm/system/systemApi.d.ts +46 -0
  187. package/esm/system/systemApi.js +53 -0
  188. package/esm/system/systemInterfaces.d.ts +29 -0
  189. package/esm/system/systemInterfaces.js +1 -0
  190. package/esm/templates/templatesApi.d.ts +53 -0
  191. package/esm/templates/templatesApi.js +78 -0
  192. package/esm/templates/templatesInterfaces.d.ts +68 -0
  193. package/esm/templates/templatesInterfaces.js +1 -0
  194. package/esm/templates/templatesSchemas.d.ts +48 -0
  195. package/esm/templates/templatesSchemas.js +28 -0
  196. package/esm/templates-preview/templatesPreviewApi.d.ts +40 -0
  197. package/esm/templates-preview/templatesPreviewApi.js +50 -0
  198. package/esm/templates-preview/templatesPreviewInterfaces.d.ts +129 -0
  199. package/esm/templates-preview/templatesPreviewInterfaces.js +1 -0
  200. package/esm/templates-preview/templatesPreviewSchemas.d.ts +79 -0
  201. package/esm/templates-preview/templatesPreviewSchemas.js +43 -0
  202. package/esm/types.d.ts +35 -0
  203. package/esm/types.js +1 -0
  204. package/esm/user-activity/userActivityApi.d.ts +31 -0
  205. package/esm/user-activity/userActivityApi.js +37 -0
  206. package/esm/user-activity/userActivityInterfaces.d.ts +42 -0
  207. package/esm/user-activity/userActivityInterfaces.js +1 -0
  208. package/esm/users/usersApi.d.ts +249 -0
  209. package/esm/users/usersApi.js +312 -0
  210. package/esm/users/usersInterfaces.d.ts +419 -0
  211. package/esm/users/usersInterfaces.js +1 -0
  212. package/esm/users/usersSchemas.d.ts +72 -0
  213. package/esm/users/usersSchemas.js +55 -0
  214. package/esm/web-socket/lazySocket.d.ts +18 -0
  215. package/esm/web-socket/lazySocket.js +67 -0
  216. package/esm/web-socket/wsApi.d.ts +27 -0
  217. package/esm/web-socket/wsApi.js +43 -0
  218. package/esm/web-socket/wsInterfaces.d.ts +16 -0
  219. package/esm/web-socket/wsInterfaces.js +1 -0
  220. package/package.json +47 -2
  221. package/types.d.ts +1 -0
  222. package/types.js +1 -0
@@ -0,0 +1,123 @@
1
+ import type { z } from 'zod';
2
+ import type StateModule from './stateModule.js';
3
+ import SyncModules from './syncModules.js';
4
+ import type { IError } from './utils.js';
5
+ /**
6
+ * Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
7
+ * @description Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
8
+ */
9
+ export default abstract class AsyncModules extends SyncModules {
10
+ protected state: StateModule;
11
+ protected _url: string;
12
+ /**
13
+ * Constructor initializes the AsyncModules with a given state.
14
+ * @param {StateModule} state - Instance of StateModule containing configuration and state data.
15
+ * @description Constructor initializes the AsyncModules with a given state.
16
+ */
17
+ protected constructor(state: StateModule);
18
+ /**
19
+ * Detects an API error returned as a value instead of being thrown.
20
+ *
21
+ * With `isShell` enabled (the default) `browserResponse` returns the error
22
+ * body — and a caught exception — instead of throwing, so a failed request
23
+ * is indistinguishable from a successful one by control flow alone.
24
+ * @param {unknown} value - Value returned by a request.
25
+ * @returns {boolean} True when the value is an API error (statusCode >= 400) or a thrown error object.
26
+ * @description Recognizes both the OneEntry error body and errors caught by browserResponse (e.g. a network failure).
27
+ */
28
+ protected _isErrorResponse(value: unknown): value is IError;
29
+ /**
30
+ * Validates API response against a Zod schema (optional)
31
+ * @param {unknown} data - The data to validate
32
+ * @param {() => Promise<z.ZodSchema<T>>} [loadSchema] - Optional loader resolving to the Zod schema for validation
33
+ * @returns {Promise<T | IError>} Validated data or error object
34
+ * @description Validates response data if validation is enabled in config.
35
+ * The schema — and Zod itself — are imported on demand, so a project that leaves
36
+ * validation disabled (the default) never pulls Zod into its bundle.
37
+ */
38
+ protected _validateResponse<T>(data: unknown, loadSchema?: () => Promise<z.ZodSchema<T>>): Promise<T | IError>;
39
+ /**
40
+ * Performs an HTTP GET request.
41
+ * @param {string} path - The path to append to the base URL.
42
+ * @returns {Promise<T>} A promise resolving to the response data.
43
+ * @description Define a protected asynchronous method '_fetchGet' that performs a GET request
44
+ */
45
+ protected _fetchGet<T = unknown>(path: string): Promise<T>;
46
+ /**
47
+ * Performs an HTTP POST request.
48
+ * @param {string} path - The path to append to the base URL.
49
+ * @param {unknown} [data] - The data to send in the request body.
50
+ * @returns {Promise<T>} A promise resolving to the response data.
51
+ * @description Define a protected asynchronous method '_fetchPost' that performs a POST request
52
+ */
53
+ protected _fetchPost<T = unknown>(path: string, data?: unknown): Promise<T>;
54
+ /**
55
+ * Performs an HTTP PUT request.
56
+ * @param {string} path - The path to append to the base URL.
57
+ * @param {unknown} body - The data to send in the request body.
58
+ * @returns {Promise<T>} A promise resolving to the response data.
59
+ * @description Define a protected asynchronous method '_fetchPut' that performs a PUT request
60
+ */
61
+ protected _fetchPut<T = unknown>(path: string, body: unknown): Promise<T>;
62
+ /**
63
+ * Performs an HTTP DELETE request.
64
+ * @param {string} path - The path to append to the base URL.
65
+ * @param {unknown} body - The body of the request.
66
+ * @returns {Promise<T>} A promise resolving to the response data.
67
+ * @description Define a protected asynchronous method '_fetchDelete' that performs a DELETE request
68
+ */
69
+ protected _fetchDelete<T = unknown>(path: string, body?: unknown): Promise<T>;
70
+ /**
71
+ * Wraps a fetch call whose only meaningful outcome is success or failure.
72
+ *
73
+ * Several endpoints (cancel/recover subscription, subscribe/unsubscribe to
74
+ * events) return no useful body — callers only care whether the request
75
+ * succeeded. This helper resolves to `true` on success and to the error
76
+ * (as IError) on failure, centralizing the repeated try/catch.
77
+ *
78
+ * The returned value has to be inspected as well: with `isShell` enabled
79
+ * (the default) browserResponse returns the API error instead of throwing
80
+ * it, so relying on the catch alone would report every failed call — a 404
81
+ * from cancelSubscription, a 403 from recoverSubscriptions — as a success.
82
+ * @param {() => Promise<unknown>} request - Thunk performing the fetch call.
83
+ * @returns {Promise<boolean | IError>} `true` on success, IError on failure.
84
+ */
85
+ protected _fetchBoolean(request: () => Promise<unknown>): Promise<boolean | IError>;
86
+ /**
87
+ * Refreshes the authentication token (single-flight).
88
+ * @returns {Promise<boolean>} A promise resolving to a boolean indicating success or failure.
89
+ * @description De-duplicates concurrent refreshes — the refresh token is single-use, so parallel requests must share one refresh call instead of each burning a rotated token.
90
+ */
91
+ protected refreshToken(): Promise<boolean>;
92
+ /**
93
+ * Performs the actual token refresh request (without de-duplication).
94
+ * @returns {Promise<boolean>} A promise resolving to a boolean indicating success or failure.
95
+ * @description Sends POST /users/refresh and, on success, stores the rotated access/refresh tokens and calls saveFunction.
96
+ */
97
+ private _performRefresh;
98
+ /**
99
+ * Creates options for HTTP requests.
100
+ * @param {string} method - The HTTP method (GET, POST, PUT, DELETE, etc.).
101
+ * @param {unknown} data - Optional data to include in the request body.
102
+ * @returns {IHttpOptions} An object representing the request options.
103
+ */
104
+ private makeOptions;
105
+ /**
106
+ * Reads a response body as JSON, tolerating an empty body.
107
+ *
108
+ * `Response.json()` throws on an empty body (e.g. 204 or an empty error
109
+ * payload); this helper mirrors the OK-path guard (`text ? JSON.parse : {}`)
110
+ * so both the success and the error branches handle empty bodies the same way.
111
+ * @param {Response} response - The fetch Response to read.
112
+ * @returns {Promise<unknown>} Parsed JSON, or an empty object when the body is empty/unparsable.
113
+ */
114
+ private _parseJson;
115
+ /**
116
+ * Handles responses from the browser's fetch API.
117
+ * @param {string} path - The path to append to the base URL.
118
+ * @param {IHttpOptions} options - The options for the fetch request.
119
+ * @returns {Promise<T>} A promise resolving to the response data.
120
+ * @description Define an asynchronous method 'browserResponse' that takes a path and options as parameters
121
+ */
122
+ private browserResponse;
123
+ }
@@ -0,0 +1,382 @@
1
+ import SyncModules from './syncModules.js';
2
+ /**
3
+ * Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
4
+ * @description Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
5
+ */
6
+ export default class AsyncModules extends SyncModules {
7
+ /**
8
+ * Constructor initializes the AsyncModules with a given state.
9
+ * @param {StateModule} state - Instance of StateModule containing configuration and state data.
10
+ * @description Constructor initializes the AsyncModules with a given state.
11
+ */
12
+ constructor(state) {
13
+ super(state);
14
+ this.state = state;
15
+ this._url = this.state.url;
16
+ }
17
+ /**
18
+ * Detects an API error returned as a value instead of being thrown.
19
+ *
20
+ * With `isShell` enabled (the default) `browserResponse` returns the error
21
+ * body — and a caught exception — instead of throwing, so a failed request
22
+ * is indistinguishable from a successful one by control flow alone.
23
+ * @param {unknown} value - Value returned by a request.
24
+ * @returns {boolean} True when the value is an API error (statusCode >= 400) or a thrown error object.
25
+ * @description Recognizes both the OneEntry error body and errors caught by browserResponse (e.g. a network failure).
26
+ */
27
+ _isErrorResponse(value) {
28
+ if (value instanceof Error) {
29
+ return true;
30
+ }
31
+ return (value !== null &&
32
+ typeof value === 'object' &&
33
+ 'statusCode' in value &&
34
+ typeof value.statusCode === 'number' &&
35
+ value.statusCode >= 400);
36
+ }
37
+ /**
38
+ * Validates API response against a Zod schema (optional)
39
+ * @param {unknown} data - The data to validate
40
+ * @param {() => Promise<z.ZodSchema<T>>} [loadSchema] - Optional loader resolving to the Zod schema for validation
41
+ * @returns {Promise<T | IError>} Validated data or error object
42
+ * @description Validates response data if validation is enabled in config.
43
+ * The schema — and Zod itself — are imported on demand, so a project that leaves
44
+ * validation disabled (the default) never pulls Zod into its bundle.
45
+ */
46
+ async _validateResponse(data, loadSchema) {
47
+ // Skip validation if not enabled or no schema provided
48
+ if (!this.state.validationEnabled || !loadSchema) {
49
+ return data;
50
+ }
51
+ // Skip validation for error responses (statusCode indicates API error)
52
+ if (this._isErrorResponse(data)) {
53
+ return data;
54
+ }
55
+ // Pull the schema and the Zod-backed validators only now that they are needed
56
+ const [schema, { validateResponse, validateResponseSafe }] = await Promise.all([loadSchema(), import('./validation.js')]);
57
+ // Use strict or safe validation based on config
58
+ if (this.state.validationStrictMode) {
59
+ const result = validateResponse(schema, data, {
60
+ logErrors: this.state.validationLogErrors,
61
+ });
62
+ if (!result.success) {
63
+ // Return error object compatible with IError interface
64
+ return {
65
+ statusCode: 422,
66
+ message: 'Response validation failed',
67
+ pageData: null,
68
+ timestamp: new Date().toISOString(),
69
+ localizeMessage: result.error.issues
70
+ .map((e) => `${e.path.join('.')}: ${e.message}`)
71
+ .join(', '),
72
+ validationErrors: result.error.issues,
73
+ };
74
+ }
75
+ return result.data;
76
+ }
77
+ else {
78
+ // Non-strict mode: log errors but return original data
79
+ return validateResponseSafe(schema, data, this.state.validationLogErrors);
80
+ }
81
+ }
82
+ /**
83
+ * Performs an HTTP GET request.
84
+ * @param {string} path - The path to append to the base URL.
85
+ * @returns {Promise<T>} A promise resolving to the response data.
86
+ * @description Define a protected asynchronous method '_fetchGet' that performs a GET request
87
+ */
88
+ async _fetchGet(path) {
89
+ return this.browserResponse(path, this.makeOptions('GET'));
90
+ }
91
+ /**
92
+ * Performs an HTTP POST request.
93
+ * @param {string} path - The path to append to the base URL.
94
+ * @param {unknown} [data] - The data to send in the request body.
95
+ * @returns {Promise<T>} A promise resolving to the response data.
96
+ * @description Define a protected asynchronous method '_fetchPost' that performs a POST request
97
+ */
98
+ async _fetchPost(path, data) {
99
+ return this.browserResponse(path, this.makeOptions('POST', data));
100
+ }
101
+ /**
102
+ * Performs an HTTP PUT request.
103
+ * @param {string} path - The path to append to the base URL.
104
+ * @param {unknown} body - The data to send in the request body.
105
+ * @returns {Promise<T>} A promise resolving to the response data.
106
+ * @description Define a protected asynchronous method '_fetchPut' that performs a PUT request
107
+ */
108
+ async _fetchPut(path, body) {
109
+ return this.browserResponse(path, this.makeOptions('PUT', body));
110
+ }
111
+ /**
112
+ * Performs an HTTP DELETE request.
113
+ * @param {string} path - The path to append to the base URL.
114
+ * @param {unknown} body - The body of the request.
115
+ * @returns {Promise<T>} A promise resolving to the response data.
116
+ * @description Define a protected asynchronous method '_fetchDelete' that performs a DELETE request
117
+ */
118
+ async _fetchDelete(path, body) {
119
+ return this.browserResponse(path, this.makeOptions('DELETE', body));
120
+ }
121
+ /**
122
+ * Wraps a fetch call whose only meaningful outcome is success or failure.
123
+ *
124
+ * Several endpoints (cancel/recover subscription, subscribe/unsubscribe to
125
+ * events) return no useful body — callers only care whether the request
126
+ * succeeded. This helper resolves to `true` on success and to the error
127
+ * (as IError) on failure, centralizing the repeated try/catch.
128
+ *
129
+ * The returned value has to be inspected as well: with `isShell` enabled
130
+ * (the default) browserResponse returns the API error instead of throwing
131
+ * it, so relying on the catch alone would report every failed call — a 404
132
+ * from cancelSubscription, a 403 from recoverSubscriptions — as a success.
133
+ * @param {() => Promise<unknown>} request - Thunk performing the fetch call.
134
+ * @returns {Promise<boolean | IError>} `true` on success, IError on failure.
135
+ */
136
+ async _fetchBoolean(request) {
137
+ try {
138
+ const result = await request();
139
+ if (this._isErrorResponse(result)) {
140
+ return result;
141
+ }
142
+ return true;
143
+ }
144
+ catch (e) {
145
+ return e;
146
+ }
147
+ }
148
+ /**
149
+ * Refreshes the authentication token (single-flight).
150
+ * @returns {Promise<boolean>} A promise resolving to a boolean indicating success or failure.
151
+ * @description De-duplicates concurrent refreshes — the refresh token is single-use, so parallel requests must share one refresh call instead of each burning a rotated token.
152
+ */
153
+ async refreshToken() {
154
+ // Reuse an in-flight refresh if one is already running (shared via state
155
+ // across all module instances). Prevents parallel requests from each firing
156
+ // their own refresh and invalidating the single-use refresh token.
157
+ if (this.state._refreshPromise) {
158
+ return this.state._refreshPromise;
159
+ }
160
+ const promise = this._performRefresh();
161
+ this.state._refreshPromise = promise;
162
+ try {
163
+ return await promise;
164
+ }
165
+ finally {
166
+ // Clear so the next genuine 401 (e.g. mid-session expiry) can refresh again.
167
+ this.state._refreshPromise = null;
168
+ }
169
+ }
170
+ /**
171
+ * Performs the actual token refresh request (without de-duplication).
172
+ * @returns {Promise<boolean>} A promise resolving to a boolean indicating success or failure.
173
+ * @description Sends POST /users/refresh and, on success, stores the rotated access/refresh tokens and calls saveFunction.
174
+ */
175
+ async _performRefresh() {
176
+ const url = this.state.url +
177
+ `/api/content/users-auth-providers/marker/` +
178
+ this.state.providerMarker +
179
+ `/users/refresh`;
180
+ /**
181
+ * Perform a fetch request to the specified URL to refresh the token
182
+ * @param {string} url - The URL to which the request will be sent
183
+ * @param {object} options - The options for the fetch request
184
+ * @param {string} options.method - The HTTP method to use for the request (default: 'POST')
185
+ * @param {object} options.headers - Set the necessary headers for the request
186
+ * @param {object} options.body - Send the current refresh token in the request body as a JSON string
187
+ */
188
+ const response = await fetch(url, {
189
+ method: 'POST',
190
+ headers: {
191
+ // Indicate that the request body is in JSON format
192
+ 'Content-Type': 'application/json',
193
+ // Include the application token from the state
194
+ 'x-app-token': this.state.token,
195
+ // Include the device fingerprint
196
+ 'x-device-metadata': this._getDeviceMetadata(),
197
+ // x-guest-id is intentionally omitted: refresh is an auth-only call
198
+ // (a pure guest has no refresh token), so guest scoping does not apply.
199
+ },
200
+ body: JSON.stringify({ refreshToken: this.state.refreshToken }),
201
+ });
202
+ // Check if the response status is OK (status code 200-299)
203
+ if (response.ok) {
204
+ // Parse the response body as JSON and store the result
205
+ const result = await response.json();
206
+ // Update the state's refreshToken and accessToken with the new tokens from the response
207
+ this.state.refreshToken = result.refreshToken;
208
+ this.state.accessToken = result.accessToken;
209
+ // If a save function is defined in the state, call it with the new refresh token
210
+ if (this.state.saveFunction) {
211
+ this.state.saveFunction(result.refreshToken);
212
+ }
213
+ // Return true to indicate that the token refresh was successful
214
+ return true;
215
+ }
216
+ else {
217
+ // Return false to indicate that the token refresh failed
218
+ return false;
219
+ }
220
+ }
221
+ /**
222
+ * Creates options for HTTP requests.
223
+ * @param {string} method - The HTTP method (GET, POST, PUT, DELETE, etc.).
224
+ * @param {unknown} data - Optional data to include in the request body.
225
+ * @returns {IHttpOptions} An object representing the request options.
226
+ */
227
+ makeOptions(method, data) {
228
+ const options = {
229
+ method: method,
230
+ headers: {
231
+ 'Content-Type': 'application/json',
232
+ 'x-app-token': this.state.token,
233
+ },
234
+ };
235
+ // Guest identifier — enables guest cart/wishlist/activity flows.
236
+ // Only sent for unauthenticated requests: once a user is logged in their
237
+ // own identity scopes the data, and sending the guest id would link the
238
+ // anonymous trail to the account. Omitted entirely when no id is available
239
+ // (e.g. server-side without an explicit guestId — see _getGuestId).
240
+ if (!this.state.accessToken) {
241
+ const guestId = this._getGuestId();
242
+ if (guestId) {
243
+ options.headers['x-guest-id'] = guestId;
244
+ }
245
+ }
246
+ // if method = 'POST' add x-device-metadata
247
+ if (method === 'POST') {
248
+ options.headers = {
249
+ ...options.headers,
250
+ 'x-device-metadata': this._getDeviceMetadata(),
251
+ };
252
+ }
253
+ // Check if 'data' is an instance of FormData or Blob
254
+ if (data instanceof FormData || data instanceof Blob) {
255
+ // Remove the 'Content-Type' header from options.headers
256
+ delete options.headers['Content-Type'];
257
+ // Set the 'accept' header to 'application/json', while preserving existing headers
258
+ options.headers = {
259
+ ...options.headers,
260
+ accept: 'application/json',
261
+ };
262
+ // Assign 'data' to options.body for sending as request payload
263
+ options.body = data;
264
+ }
265
+ else if (data) {
266
+ // If 'data' exists and is not FormData or Blob, convert it to a JSON string
267
+ // and assign it to options.body
268
+ options.body = JSON.stringify(data);
269
+ }
270
+ // Check if there is an access token available in the state
271
+ if (this.state.accessToken) {
272
+ // Add an 'Authorization' header with the Bearer token to options.headers
273
+ options.headers['Authorization'] = 'Bearer ' + this.state.accessToken;
274
+ }
275
+ return options;
276
+ }
277
+ /**
278
+ * Reads a response body as JSON, tolerating an empty body.
279
+ *
280
+ * `Response.json()` throws on an empty body (e.g. 204 or an empty error
281
+ * payload); this helper mirrors the OK-path guard (`text ? JSON.parse : {}`)
282
+ * so both the success and the error branches handle empty bodies the same way.
283
+ * @param {Response} response - The fetch Response to read.
284
+ * @returns {Promise<unknown>} Parsed JSON, or an empty object when the body is empty/unparsable.
285
+ */
286
+ async _parseJson(response) {
287
+ try {
288
+ const text = await response.text();
289
+ return text ? JSON.parse(text) : {};
290
+ }
291
+ catch {
292
+ return {};
293
+ }
294
+ }
295
+ /**
296
+ * Handles responses from the browser's fetch API.
297
+ * @param {string} path - The path to append to the base URL.
298
+ * @param {IHttpOptions} options - The options for the fetch request.
299
+ * @returns {Promise<T>} A promise resolving to the response data.
300
+ * @description Define an asynchronous method 'browserResponse' that takes a path and options as parameters
301
+ */
302
+ async browserResponse(path, options) {
303
+ // Set when a proactive refresh ran and failed (dead/expired refresh token):
304
+ // used below to skip the reactive refresh so we don't fire a second,
305
+ // equally-doomed refresh on the 401 that the request is about to return.
306
+ let proactiveRefreshFailed = false;
307
+ try {
308
+ // Proactive (eager) refresh: a session restored from storage has a refresh
309
+ // token but no access token yet. Sending the first authenticated request
310
+ // without an access token GUARANTEES a 401 (then a reactive refresh + retry)
311
+ // — a spurious 401 logged on every page load even for a perfectly valid
312
+ // session. Obtaining the access token up-front turns that into a clean 200.
313
+ // Fires at most once per session (skipped once accessToken is set), and is
314
+ // off for custom-auth callers who manage tokens themselves.
315
+ if (!this.state.accessToken &&
316
+ this.state.refreshToken &&
317
+ !this.state.customAuth) {
318
+ const refreshed = await this.refreshToken();
319
+ if (refreshed) {
320
+ // Authenticated now — attach the bearer and drop the guest scoping
321
+ // that makeOptions added while no access token was present.
322
+ options.headers['Authorization'] = 'Bearer ' + this.state.accessToken;
323
+ delete options.headers['x-guest-id'];
324
+ }
325
+ else {
326
+ proactiveRefreshFailed = true;
327
+ }
328
+ }
329
+ // Perform a fetch request using the full URL obtained from '_getFullPath' and the provided options
330
+ let response = await fetch(this._getFullPath(path), options);
331
+ // Reactive refresh for mid-session expiry: access token was present but
332
+ // the server rejected it. Skipped when a proactive refresh already ran
333
+ // and failed (the refresh token is dead — retrying would 400 again).
334
+ // On success the request is retried once; the retry response then flows
335
+ // through the SAME ok / error handling below (status check, errorsFunctions,
336
+ // isShell) instead of being returned blindly.
337
+ if (!response.ok &&
338
+ response.status === 401 &&
339
+ !this.state.customAuth &&
340
+ !proactiveRefreshFailed) {
341
+ const refresh = await this.refreshToken();
342
+ if (refresh) {
343
+ // Update the Authorization header with the new access token and retry.
344
+ options.headers['Authorization'] = 'Bearer ' + this.state.accessToken;
345
+ response = await fetch(this._getFullPath(path), options);
346
+ }
347
+ }
348
+ // Check if the response status is OK (status code 200-299)
349
+ if (response.ok) {
350
+ // Read the body as text; if it is empty return an empty object,
351
+ // otherwise parse it as JSON. A parse failure propagates to the
352
+ // catch below and is handled according to isShell.
353
+ const text = await response.text();
354
+ return (text ? JSON.parse(text) : {});
355
+ }
356
+ // Handle non-OK responses (applies to the first response and to a failed retry).
357
+ const status = response.status;
358
+ const res = await this._parseJson(response);
359
+ const statusKey = status;
360
+ if (this.state.errorsFunctions && this.state.errorsFunctions[statusKey]) {
361
+ this.state.errorsFunctions[statusKey](res);
362
+ }
363
+ // Determine whether to return or throw the response based on 'isShell' state
364
+ if (this.state.isShell) {
365
+ return res;
366
+ }
367
+ else {
368
+ throw res;
369
+ }
370
+ }
371
+ catch (e) {
372
+ // Handle any errors that occur during the fetch process
373
+ // Determine whether to return or throw the error based on 'isShell' state
374
+ if (this.state.isShell) {
375
+ return e;
376
+ }
377
+ else {
378
+ throw e;
379
+ }
380
+ }
381
+ }
382
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Creates a lazy schema loader bound to a module of Zod schemas.
3
+ *
4
+ * Validation is opt-in (`config.validation.enabled`, `false` by default), yet a static
5
+ * `import { PageEntitySchema } from './pagesSchemas'` would put Zod into the import graph
6
+ * of every consumer regardless. Binding the module behind a dynamic `import()` keeps it —
7
+ * and Zod — out of the bundle until a request actually needs to be validated.
8
+ * @param {() => Promise<TSchemas>} importSchemas - Dynamic import of the module holding the schemas.
9
+ * @returns {(name: keyof TSchemas) => () => Promise<TSchemas[keyof TSchemas]>} Function that takes
10
+ * a schema name and returns a loader for that schema.
11
+ * @description Usage: `const schema = createSchemaLoader(() => import('./pagesSchemas'))`,
12
+ * then `this._validateResponse(data, schema('PageEntitySchema'))`. The schema name is
13
+ * checked against the module's exports, so a typo is a compile-time error.
14
+ */
15
+ export default function createSchemaLoader<TSchemas>(importSchemas: () => Promise<TSchemas>): <TName extends keyof TSchemas>(name: TName) => () => Promise<TSchemas[TName]>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Creates a lazy schema loader bound to a module of Zod schemas.
3
+ *
4
+ * Validation is opt-in (`config.validation.enabled`, `false` by default), yet a static
5
+ * `import { PageEntitySchema } from './pagesSchemas'` would put Zod into the import graph
6
+ * of every consumer regardless. Binding the module behind a dynamic `import()` keeps it —
7
+ * and Zod — out of the bundle until a request actually needs to be validated.
8
+ * @param {() => Promise<TSchemas>} importSchemas - Dynamic import of the module holding the schemas.
9
+ * @returns {(name: keyof TSchemas) => () => Promise<TSchemas[keyof TSchemas]>} Function that takes
10
+ * a schema name and returns a loader for that schema.
11
+ * @description Usage: `const schema = createSchemaLoader(() => import('./pagesSchemas'))`,
12
+ * then `this._validateResponse(data, schema('PageEntitySchema'))`. The schema name is
13
+ * checked against the module's exports, so a typo is a compile-time error.
14
+ */
15
+ export default function createSchemaLoader(importSchemas) {
16
+ return (name) => () => importSchemas().then((schemas) => schemas[name]);
17
+ }
@@ -0,0 +1,35 @@
1
+ import type { IConfig, IError } from './utils.js';
2
+ declare const ERROR_STATUS_CODES: readonly [400, 401, 403, 404, 429, 500, 502, 503, 504];
3
+ type ErrorStatusCode = (typeof ERROR_STATUS_CODES)[number];
4
+ /**
5
+ * State module for managing application state and configuration.
6
+ * @description State module for managing application state and configuration.
7
+ */
8
+ export default class StateModule {
9
+ url: string | undefined;
10
+ lang: string | undefined;
11
+ token: string | undefined;
12
+ guestId: string | undefined;
13
+ deviceMetadata: string | undefined;
14
+ accessToken: string | undefined;
15
+ traficLimit: boolean;
16
+ refreshToken: string | undefined;
17
+ _refreshPromise: Promise<boolean> | null;
18
+ providerMarker: string;
19
+ customAuth: boolean;
20
+ isShell: boolean;
21
+ validationEnabled: boolean;
22
+ validationStrictMode: boolean;
23
+ validationLogErrors: boolean;
24
+ rawData: boolean;
25
+ errorsFunctions: Partial<Record<ErrorStatusCode, (data: IError) => any>>;
26
+ saveFunction: (param: string) => void | null;
27
+ /**
28
+ * Constructor for StateModule
29
+ * @param {string} url - Base URL for API requests.
30
+ * @param {IConfig} config - Configuration object.
31
+ * @description Constructor for StateModule.
32
+ */
33
+ constructor(url: string, config: IConfig);
34
+ }
35
+ export {};
@@ -0,0 +1,51 @@
1
+ // HTTP status codes for which a custom error handler may be configured.
2
+ const ERROR_STATUS_CODES = [
3
+ 400, 401, 403, 404, 429, 500, 502, 503, 504,
4
+ ];
5
+ /**
6
+ * State module for managing application state and configuration.
7
+ * @description State module for managing application state and configuration.
8
+ */
9
+ export default class StateModule {
10
+ /**
11
+ * Constructor for StateModule
12
+ * @param {string} url - Base URL for API requests.
13
+ * @param {IConfig} config - Configuration object.
14
+ * @description Constructor for StateModule.
15
+ */
16
+ constructor(url, config) {
17
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
18
+ // In-flight token refresh, shared across all module instances (they share this
19
+ // state object). De-duplicates concurrent refreshes so the single-use refresh
20
+ // token is not burned by parallel requests. Null when no refresh is running.
21
+ this._refreshPromise = null;
22
+ this.url = url;
23
+ this.lang = (_a = config.langCode) !== null && _a !== void 0 ? _a : 'en_US';
24
+ this.token = config.token;
25
+ // Normalize empty string to undefined: an explicit '' must not masquerade
26
+ // as a set guest id (it would otherwise suppress id resolution).
27
+ this.guestId = config.guestId || undefined;
28
+ // Same normalization as guestId: an explicit '' must not suppress the
29
+ // environment-derived fingerprint.
30
+ this.deviceMetadata = config.deviceMetadata || undefined;
31
+ this.traficLimit = config.traficLimit || false;
32
+ this.validationEnabled = (_c = (_b = config.validation) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : false;
33
+ this.validationStrictMode = (_e = (_d = config.validation) === null || _d === void 0 ? void 0 : _d.strictMode) !== null && _e !== void 0 ? _e : false;
34
+ this.validationLogErrors = (_g = (_f = config.validation) === null || _f === void 0 ? void 0 : _f.logErrors) !== null && _g !== void 0 ? _g : true;
35
+ this.rawData = (_h = config.rawData) !== null && _h !== void 0 ? _h : false;
36
+ this.refreshToken = (_k = (_j = config.auth) === null || _j === void 0 ? void 0 : _j.refreshToken) !== null && _k !== void 0 ? _k : undefined;
37
+ this.providerMarker = (_m = (_l = config.auth) === null || _l === void 0 ? void 0 : _l.providerMarker) !== null && _m !== void 0 ? _m : 'email';
38
+ this.customAuth = (_p = (_o = config.auth) === null || _o === void 0 ? void 0 : _o.customAuth) !== null && _p !== void 0 ? _p : false;
39
+ this.errorsFunctions = {};
40
+ this.saveFunction = (_r = (_q = config.auth) === null || _q === void 0 ? void 0 : _q.saveFunction) !== null && _r !== void 0 ? _r : null;
41
+ this.isShell = (_t = (_s = config.errors) === null || _s === void 0 ? void 0 : _s.isShell) !== null && _t !== void 0 ? _t : true;
42
+ const customErrors = (_u = config.errors) === null || _u === void 0 ? void 0 : _u.customErrors;
43
+ if (customErrors) {
44
+ for (const code of ERROR_STATUS_CODES) {
45
+ if (customErrors[code]) {
46
+ this.errorsFunctions[code] = customErrors[code];
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }