oneentry 1.0.175 → 1.0.177

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 (197) hide show
  1. package/README.md +12 -5
  2. package/changelog.md +140 -0
  3. package/dist/admins/adminsApi.js +2 -9
  4. package/dist/admins/adminsInterfaces.d.ts +5 -5
  5. package/dist/admins/adminsSchemas.d.ts +4 -4
  6. package/dist/admins/adminsSchemas.js +2 -2
  7. package/dist/attribute-sets/attributeSetsApi.d.ts +1 -1
  8. package/dist/attribute-sets/attributeSetsApi.js +4 -4
  9. package/dist/attribute-sets/attributeSetsInterfaces.d.ts +65 -14
  10. package/dist/attribute-sets/attributeSetsSchemas.d.ts +8 -6
  11. package/dist/attribute-sets/attributeSetsSchemas.js +6 -9
  12. package/dist/auth-provider/authProviderApi.d.ts +4 -4
  13. package/dist/auth-provider/authProviderApi.js +96 -29
  14. package/dist/auth-provider/authProviderSchemas.d.ts +1 -0
  15. package/dist/auth-provider/authProviderSchemas.js +1 -0
  16. package/dist/auth-provider/authProvidersInterfaces.d.ts +8 -6
  17. package/dist/base/asyncModules.d.ts +73 -1
  18. package/dist/base/asyncModules.js +233 -37
  19. package/dist/base/stateModule.d.ts +2 -0
  20. package/dist/base/stateModule.js +22 -12
  21. package/dist/base/syncModules.d.ts +18 -10
  22. package/dist/base/syncModules.js +100 -29
  23. package/dist/base/utils.d.ts +26 -21
  24. package/dist/base/validation.d.ts +3 -3
  25. package/dist/base/validation.js +6 -7
  26. package/dist/blocks/blocksApi.d.ts +20 -17
  27. package/dist/blocks/blocksApi.js +101 -74
  28. package/dist/blocks/blocksInterfaces.d.ts +8 -8
  29. package/dist/discounts/discountsApi.d.ts +9 -7
  30. package/dist/discounts/discountsApi.js +18 -14
  31. package/dist/discounts/discountsInterfaces.d.ts +14 -10
  32. package/dist/events/eventsApi.d.ts +3 -3
  33. package/dist/events/eventsApi.js +7 -7
  34. package/dist/events/eventsInterfaces.d.ts +10 -14
  35. package/dist/file-uploading/fileUploadingApi.d.ts +4 -4
  36. package/dist/file-uploading/fileUploadingApi.js +13 -5
  37. package/dist/file-uploading/fileUploadingInterfaces.d.ts +5 -6
  38. package/dist/filters/filtersApi.js +2 -2
  39. package/dist/forms/formsApi.js +2 -2
  40. package/dist/forms/formsInterfaces.d.ts +1 -3
  41. package/dist/forms/formsSchemas.d.ts +3 -6
  42. package/dist/forms/formsSchemas.js +2 -4
  43. package/dist/forms-data/formsDataApi.d.ts +26 -8
  44. package/dist/forms-data/formsDataApi.js +45 -14
  45. package/dist/forms-data/formsDataInterfaces.d.ts +91 -66
  46. package/dist/general-types/generalTypesInterfaces.d.ts +1 -1
  47. package/dist/index.d.ts +7 -6
  48. package/dist/index.js +50 -7
  49. package/dist/integration-collections/integrationCollectionsApi.d.ts +15 -4
  50. package/dist/integration-collections/integrationCollectionsApi.js +42 -14
  51. package/dist/integration-collections/integrationCollectionsInterfaces.d.ts +8 -9
  52. package/dist/integration-collections/integrationCollectionsSchemas.d.ts +0 -2
  53. package/dist/integration-collections/integrationCollectionsSchemas.js +0 -1
  54. package/dist/menus/menusApi.js +1 -1
  55. package/dist/orders/ordersApi.d.ts +1 -13
  56. package/dist/orders/ordersApi.js +24 -44
  57. package/dist/orders/ordersInterfaces.d.ts +21 -14
  58. package/dist/pages/pagesApi.d.ts +6 -5
  59. package/dist/pages/pagesApi.js +44 -31
  60. package/dist/pages/pagesInterfaces.d.ts +18 -15
  61. package/dist/pages/pagesSchemas.d.ts +0 -3
  62. package/dist/pages/pagesSchemas.js +0 -1
  63. package/dist/payments/paymentsApi.d.ts +10 -11
  64. package/dist/payments/paymentsApi.js +22 -18
  65. package/dist/payments/paymentsInterfaces.d.ts +12 -14
  66. package/dist/payments/paymentsSchemas.d.ts +21 -20
  67. package/dist/payments/paymentsSchemas.js +5 -8
  68. package/dist/product-statuses/productStatusesApi.d.ts +1 -1
  69. package/dist/product-statuses/productStatusesApi.js +4 -4
  70. package/dist/product-statuses/productStatusesInterfaces.d.ts +1 -4
  71. package/dist/products/productsApi.d.ts +38 -58
  72. package/dist/products/productsApi.js +59 -72
  73. package/dist/products/productsInterfaces.d.ts +48 -85
  74. package/dist/search/searchApi.d.ts +1 -1
  75. package/dist/search/searchApi.js +4 -3
  76. package/dist/sitemap/sitemapInterfaces.d.ts +10 -6
  77. package/dist/subscriptions/subscriptionsApi.d.ts +1 -1
  78. package/dist/subscriptions/subscriptionsApi.js +1 -1
  79. package/dist/subscriptions/subscriptionsInterfaces.d.ts +1 -1
  80. package/dist/system/systemApi.d.ts +2 -0
  81. package/dist/system/systemApi.js +2 -0
  82. package/dist/system/systemInterfaces.d.ts +2 -0
  83. package/dist/templates/templatesApi.d.ts +2 -2
  84. package/dist/templates/templatesApi.js +12 -11
  85. package/dist/templates/templatesInterfaces.d.ts +2 -2
  86. package/dist/templates-preview/templatesPreviewApi.js +2 -2
  87. package/dist/templates-preview/templatesPreviewInterfaces.d.ts +23 -13
  88. package/dist/templates-preview/templatesPreviewSchemas.d.ts +7 -0
  89. package/dist/templates-preview/templatesPreviewSchemas.js +2 -0
  90. package/dist/user-groups/userGroupsApi.js +5 -5
  91. package/dist/user-groups/userGroupsSchemas.d.ts +4 -4
  92. package/dist/users/usersApi.d.ts +1 -1
  93. package/dist/users/usersApi.js +28 -15
  94. package/dist/users/usersInterfaces.d.ts +2 -9
  95. package/dist/web-socket/lazySocket.d.ts +6 -5
  96. package/dist/web-socket/lazySocket.js +212 -15
  97. package/dist/web-socket/wsApi.d.ts +7 -4
  98. package/dist/web-socket/wsApi.js +49 -12
  99. package/dist/web-socket/wsInterfaces.d.ts +41 -4
  100. package/esm/admins/adminsApi.js +2 -9
  101. package/esm/admins/adminsInterfaces.d.ts +5 -5
  102. package/esm/admins/adminsSchemas.d.ts +4 -4
  103. package/esm/admins/adminsSchemas.js +2 -2
  104. package/esm/attribute-sets/attributeSetsApi.d.ts +1 -1
  105. package/esm/attribute-sets/attributeSetsApi.js +4 -4
  106. package/esm/attribute-sets/attributeSetsInterfaces.d.ts +65 -14
  107. package/esm/attribute-sets/attributeSetsSchemas.d.ts +8 -6
  108. package/esm/attribute-sets/attributeSetsSchemas.js +6 -9
  109. package/esm/auth-provider/authProviderApi.d.ts +4 -4
  110. package/esm/auth-provider/authProviderApi.js +96 -29
  111. package/esm/auth-provider/authProviderSchemas.d.ts +1 -0
  112. package/esm/auth-provider/authProviderSchemas.js +1 -0
  113. package/esm/auth-provider/authProvidersInterfaces.d.ts +8 -6
  114. package/esm/base/asyncModules.d.ts +73 -1
  115. package/esm/base/asyncModules.js +233 -37
  116. package/esm/base/stateModule.d.ts +2 -0
  117. package/esm/base/stateModule.js +22 -12
  118. package/esm/base/syncModules.d.ts +18 -10
  119. package/esm/base/syncModules.js +99 -29
  120. package/esm/base/utils.d.ts +26 -21
  121. package/esm/base/validation.d.ts +3 -3
  122. package/esm/base/validation.js +6 -7
  123. package/esm/blocks/blocksApi.d.ts +20 -17
  124. package/esm/blocks/blocksApi.js +101 -74
  125. package/esm/blocks/blocksInterfaces.d.ts +8 -8
  126. package/esm/discounts/discountsApi.d.ts +9 -7
  127. package/esm/discounts/discountsApi.js +18 -14
  128. package/esm/discounts/discountsInterfaces.d.ts +14 -10
  129. package/esm/events/eventsApi.d.ts +3 -3
  130. package/esm/events/eventsApi.js +7 -7
  131. package/esm/events/eventsInterfaces.d.ts +10 -14
  132. package/esm/file-uploading/fileUploadingApi.d.ts +4 -4
  133. package/esm/file-uploading/fileUploadingApi.js +13 -5
  134. package/esm/file-uploading/fileUploadingInterfaces.d.ts +5 -6
  135. package/esm/filters/filtersApi.js +2 -2
  136. package/esm/forms/formsApi.js +2 -2
  137. package/esm/forms/formsInterfaces.d.ts +1 -3
  138. package/esm/forms/formsSchemas.d.ts +3 -6
  139. package/esm/forms/formsSchemas.js +2 -4
  140. package/esm/forms-data/formsDataApi.d.ts +26 -8
  141. package/esm/forms-data/formsDataApi.js +45 -14
  142. package/esm/forms-data/formsDataInterfaces.d.ts +91 -66
  143. package/esm/general-types/generalTypesInterfaces.d.ts +1 -1
  144. package/esm/index.d.ts +7 -6
  145. package/esm/index.js +50 -7
  146. package/esm/integration-collections/integrationCollectionsApi.d.ts +15 -4
  147. package/esm/integration-collections/integrationCollectionsApi.js +42 -14
  148. package/esm/integration-collections/integrationCollectionsInterfaces.d.ts +8 -9
  149. package/esm/integration-collections/integrationCollectionsSchemas.d.ts +0 -2
  150. package/esm/integration-collections/integrationCollectionsSchemas.js +0 -1
  151. package/esm/menus/menusApi.js +1 -1
  152. package/esm/orders/ordersApi.d.ts +1 -13
  153. package/esm/orders/ordersApi.js +24 -44
  154. package/esm/orders/ordersInterfaces.d.ts +21 -14
  155. package/esm/pages/pagesApi.d.ts +6 -5
  156. package/esm/pages/pagesApi.js +44 -31
  157. package/esm/pages/pagesInterfaces.d.ts +18 -15
  158. package/esm/pages/pagesSchemas.d.ts +0 -3
  159. package/esm/pages/pagesSchemas.js +0 -1
  160. package/esm/payments/paymentsApi.d.ts +10 -11
  161. package/esm/payments/paymentsApi.js +22 -18
  162. package/esm/payments/paymentsInterfaces.d.ts +12 -14
  163. package/esm/payments/paymentsSchemas.d.ts +21 -20
  164. package/esm/payments/paymentsSchemas.js +5 -8
  165. package/esm/product-statuses/productStatusesApi.d.ts +1 -1
  166. package/esm/product-statuses/productStatusesApi.js +4 -4
  167. package/esm/product-statuses/productStatusesInterfaces.d.ts +1 -4
  168. package/esm/products/productsApi.d.ts +38 -58
  169. package/esm/products/productsApi.js +59 -72
  170. package/esm/products/productsInterfaces.d.ts +48 -85
  171. package/esm/search/searchApi.d.ts +1 -1
  172. package/esm/search/searchApi.js +4 -3
  173. package/esm/sitemap/sitemapInterfaces.d.ts +10 -6
  174. package/esm/subscriptions/subscriptionsApi.d.ts +1 -1
  175. package/esm/subscriptions/subscriptionsApi.js +1 -1
  176. package/esm/subscriptions/subscriptionsInterfaces.d.ts +1 -1
  177. package/esm/system/systemApi.d.ts +2 -0
  178. package/esm/system/systemApi.js +2 -0
  179. package/esm/system/systemInterfaces.d.ts +2 -0
  180. package/esm/templates/templatesApi.d.ts +2 -2
  181. package/esm/templates/templatesApi.js +11 -10
  182. package/esm/templates/templatesInterfaces.d.ts +2 -2
  183. package/esm/templates-preview/templatesPreviewApi.js +2 -2
  184. package/esm/templates-preview/templatesPreviewInterfaces.d.ts +23 -13
  185. package/esm/templates-preview/templatesPreviewSchemas.d.ts +7 -0
  186. package/esm/templates-preview/templatesPreviewSchemas.js +2 -0
  187. package/esm/user-groups/userGroupsApi.js +5 -5
  188. package/esm/user-groups/userGroupsSchemas.d.ts +4 -4
  189. package/esm/users/usersApi.d.ts +1 -1
  190. package/esm/users/usersApi.js +28 -15
  191. package/esm/users/usersInterfaces.d.ts +2 -9
  192. package/esm/web-socket/lazySocket.d.ts +6 -5
  193. package/esm/web-socket/lazySocket.js +212 -15
  194. package/esm/web-socket/wsApi.d.ts +7 -4
  195. package/esm/web-socket/wsApi.js +49 -12
  196. package/esm/web-socket/wsInterfaces.d.ts +41 -4
  197. package/package.json +2 -2
@@ -22,7 +22,7 @@ export default abstract class AsyncModules extends SyncModules {
22
22
  * body — and a caught exception — instead of throwing, so a failed request
23
23
  * is indistinguishable from a successful one by control flow alone.
24
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.
25
+ * @returns {boolean} True when the value is an API error (statusCode >= 400), the shell error of a request that got no answer (statusCode 0) or a thrown error object.
26
26
  * @description Recognizes both the OneEntry error body and errors caught by browserResponse (e.g. a network failure).
27
27
  */
28
28
  protected _isErrorResponse(value: unknown): value is IError;
@@ -36,6 +36,78 @@ export default abstract class AsyncModules extends SyncModules {
36
36
  * validation disabled (the default) never pulls Zod into its bundle.
37
37
  */
38
38
  protected _validateResponse<T>(data: unknown, loadSchema?: () => Promise<z.ZodSchema<T>>): Promise<T | IError>;
39
+ /**
40
+ * A view of this module for sign-in and sign-up requests.
41
+ * @returns {this} An object that shares the module's state but sends the request without the current session.
42
+ * @description A sign-in with a wrong password answers `401`, the status of an expired token:
43
+ * with a session open the SDK used to refresh that session and send the same wrong password
44
+ * again — two failed attempts for one, and a rotated refresh token. Such a request carries
45
+ * no `Authorization` header and never triggers a token refresh.
46
+ */
47
+ protected _asSignIn(): this;
48
+ /**
49
+ * Set on the view `_asSignIn` returns: the request is a sign-in or sign-up.
50
+ */
51
+ protected _signIn: boolean;
52
+ /**
53
+ * A view of this module for requests the SDK makes on its own behalf.
54
+ * @returns {this} An object that shares the module's state but does not call `errors.customErrors`.
55
+ * @description The products of page blocks and the templates of pages are loaded by the SDK
56
+ * itself, and a failure there leaves an empty value. A `customErrors` handler (a Next.js
57
+ * `notFound()`) used to fire for them as if the page itself had failed.
58
+ */
59
+ protected _asSubRequest(): this;
60
+ /**
61
+ * Set on the view `_asSubRequest` returns.
62
+ */
63
+ protected _subRequest: boolean;
64
+ /**
65
+ * `_asSubRequest` for another module the SDK calls on its own behalf.
66
+ * @param {T} module - A module created by the SDK for a nested request.
67
+ * @returns {T} Its view that does not call `errors.customErrors`.
68
+ */
69
+ protected static _subRequestOf<T extends AsyncModules>(module: T): T;
70
+ /**
71
+ * Reads the answer of a call that returns `true` on success.
72
+ * @param {T} result - What the request returned.
73
+ * @returns {T | true} `true` for an empty 2xx body (read as `{}`), the value otherwise.
74
+ */
75
+ protected _asBoolean<T>(result: T): T | true;
76
+ /**
77
+ * Whether a refresh may be attempted now.
78
+ * @returns {boolean} False while the device metadata is the one the platform rejected as malformed.
79
+ */
80
+ protected _canRefresh(): boolean;
81
+ /**
82
+ * A view of this module whose requests go to another base URL.
83
+ * @param {string} url - The base URL for the view's requests.
84
+ * @returns {this} An object that shares the module's state and methods but has its own `_url`.
85
+ * @description For the few endpoints that live outside the module's base path. The base URL
86
+ * used to be swapped on the module itself for the duration of the call; two calls in flight
87
+ * at once (`Promise.all`) then sent one of them to the other base path, and the second
88
+ * `finally` restored the swapped URL — every later call of the instance went there too.
89
+ */
90
+ protected _withBaseUrl(url: string): this;
91
+ /**
92
+ * Prepares a caller value (a marker) to be one segment of a request path.
93
+ * @param {string} value - The value to put into the path.
94
+ * @returns {string} The value encoded as a single path segment.
95
+ * @description `encodeURIComponent` keeps `?`, `#` and `/` from cutting the query or
96
+ * adding segments, but leaves `.` alone, and `URL` resolves a `.` or `..` segment
97
+ * (`%2E` included) — `form-data/marker/..` turned a read into `POST /form-data/`,
98
+ * the create endpoint. A dot-only value is sent with its `%` escaped instead, so the
99
+ * API gets a marker it rejects as invalid rather than another route.
100
+ */
101
+ protected _pathSegment(value: string): string;
102
+ /**
103
+ * Prepares a caller path (a page URL) for a request path, keeping its `/`.
104
+ * @param {string} value - The path to put into the request path.
105
+ * @returns {string} Each `/`-separated part encoded by `_pathSegment`.
106
+ * @description A page URL may hold `/`, so it cannot be one segment; each part is
107
+ * encoded instead. `getProductsByPageUrl('../../all')` resolved to
108
+ * `POST /products/all` — the whole catalogue instead of one page.
109
+ */
110
+ protected _pathSegments(value: string): string;
39
111
  /**
40
112
  * Performs an HTTP GET request.
41
113
  * @param {string} path - The path to append to the base URL.
@@ -1,4 +1,8 @@
1
1
  import SyncModules from './syncModules.js';
2
+ /**
3
+ * A refresh that does not answer within this time (ms) counts as failed.
4
+ */
5
+ const REFRESH_TIMEOUT_MS = 30000;
2
6
  /**
3
7
  * Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
4
8
  * @description Abstract class AsyncModules extends SyncModules to provide asynchronous HTTP request functionalities.
@@ -11,6 +15,14 @@ export default class AsyncModules extends SyncModules {
11
15
  */
12
16
  constructor(state) {
13
17
  super(state);
18
+ /**
19
+ * Set on the view `_asSignIn` returns: the request is a sign-in or sign-up.
20
+ */
21
+ this._signIn = false;
22
+ /**
23
+ * Set on the view `_asSubRequest` returns.
24
+ */
25
+ this._subRequest = false;
14
26
  this.state = state;
15
27
  this._url = this.state.url;
16
28
  }
@@ -21,7 +33,7 @@ export default class AsyncModules extends SyncModules {
21
33
  * body — and a caught exception — instead of throwing, so a failed request
22
34
  * is indistinguishable from a successful one by control flow alone.
23
35
  * @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.
36
+ * @returns {boolean} True when the value is an API error (statusCode >= 400), the shell error of a request that got no answer (statusCode 0) or a thrown error object.
25
37
  * @description Recognizes both the OneEntry error body and errors caught by browserResponse (e.g. a network failure).
26
38
  */
27
39
  _isErrorResponse(value) {
@@ -32,7 +44,10 @@ export default class AsyncModules extends SyncModules {
32
44
  typeof value === 'object' &&
33
45
  'statusCode' in value &&
34
46
  typeof value.statusCode === 'number' &&
35
- value.statusCode >= 400);
47
+ // `0` is the shell error of a request that never got an answer (`_toShellError`):
48
+ // a dropped connection used to make `_fetchBoolean` report success
49
+ (value.statusCode >= 400 ||
50
+ (value.statusCode === 0 && 'pageData' in value)));
36
51
  }
37
52
  /**
38
53
  * Validates API response against a Zod schema (optional)
@@ -72,13 +87,110 @@ export default class AsyncModules extends SyncModules {
72
87
  validationErrors: result.error.issues,
73
88
  };
74
89
  }
75
- return result.data;
90
+ // Return the original data: the parsed copy lacks keys the schema does not describe
91
+ return data;
76
92
  }
77
93
  else {
78
94
  // Non-strict mode: log errors but return original data
79
95
  return validateResponseSafe(schema, data, this.state.validationLogErrors);
80
96
  }
81
97
  }
98
+ /**
99
+ * A view of this module for sign-in and sign-up requests.
100
+ * @returns {this} An object that shares the module's state but sends the request without the current session.
101
+ * @description A sign-in with a wrong password answers `401`, the status of an expired token:
102
+ * with a session open the SDK used to refresh that session and send the same wrong password
103
+ * again — two failed attempts for one, and a rotated refresh token. Such a request carries
104
+ * no `Authorization` header and never triggers a token refresh.
105
+ */
106
+ _asSignIn() {
107
+ const view = Object.create(this);
108
+ view._signIn = true;
109
+ return view;
110
+ }
111
+ /**
112
+ * A view of this module for requests the SDK makes on its own behalf.
113
+ * @returns {this} An object that shares the module's state but does not call `errors.customErrors`.
114
+ * @description The products of page blocks and the templates of pages are loaded by the SDK
115
+ * itself, and a failure there leaves an empty value. A `customErrors` handler (a Next.js
116
+ * `notFound()`) used to fire for them as if the page itself had failed.
117
+ */
118
+ _asSubRequest() {
119
+ const view = Object.create(this);
120
+ view._subRequest = true;
121
+ return view;
122
+ }
123
+ /**
124
+ * `_asSubRequest` for another module the SDK calls on its own behalf.
125
+ * @param {T} module - A module created by the SDK for a nested request.
126
+ * @returns {T} Its view that does not call `errors.customErrors`.
127
+ */
128
+ static _subRequestOf(module) {
129
+ return module._asSubRequest();
130
+ }
131
+ /**
132
+ * Reads the answer of a call that returns `true` on success.
133
+ * @param {T} result - What the request returned.
134
+ * @returns {T | true} `true` for an empty 2xx body (read as `{}`), the value otherwise.
135
+ */
136
+ _asBoolean(result) {
137
+ return result &&
138
+ typeof result === 'object' &&
139
+ !this._isErrorResponse(result) &&
140
+ Object.keys(result).length === 0
141
+ ? true
142
+ : result;
143
+ }
144
+ /**
145
+ * Whether a refresh may be attempted now.
146
+ * @returns {boolean} False while the device metadata is the one the platform rejected as malformed.
147
+ */
148
+ _canRefresh() {
149
+ return (!!this.state.refreshToken &&
150
+ this.state._rejectedMetadata !== this._getDeviceMetadata());
151
+ }
152
+ /**
153
+ * A view of this module whose requests go to another base URL.
154
+ * @param {string} url - The base URL for the view's requests.
155
+ * @returns {this} An object that shares the module's state and methods but has its own `_url`.
156
+ * @description For the few endpoints that live outside the module's base path. The base URL
157
+ * used to be swapped on the module itself for the duration of the call; two calls in flight
158
+ * at once (`Promise.all`) then sent one of them to the other base path, and the second
159
+ * `finally` restored the swapped URL — every later call of the instance went there too.
160
+ */
161
+ _withBaseUrl(url) {
162
+ const view = Object.create(this);
163
+ view._url = url;
164
+ return view;
165
+ }
166
+ /**
167
+ * Prepares a caller value (a marker) to be one segment of a request path.
168
+ * @param {string} value - The value to put into the path.
169
+ * @returns {string} The value encoded as a single path segment.
170
+ * @description `encodeURIComponent` keeps `?`, `#` and `/` from cutting the query or
171
+ * adding segments, but leaves `.` alone, and `URL` resolves a `.` or `..` segment
172
+ * (`%2E` included) — `form-data/marker/..` turned a read into `POST /form-data/`,
173
+ * the create endpoint. A dot-only value is sent with its `%` escaped instead, so the
174
+ * API gets a marker it rejects as invalid rather than another route.
175
+ */
176
+ _pathSegment(value) {
177
+ const encoded = encodeURIComponent(value);
178
+ return /^\.{1,2}$/.test(value) ? encoded.replace(/\./g, '%252E') : encoded;
179
+ }
180
+ /**
181
+ * Prepares a caller path (a page URL) for a request path, keeping its `/`.
182
+ * @param {string} value - The path to put into the request path.
183
+ * @returns {string} Each `/`-separated part encoded by `_pathSegment`.
184
+ * @description A page URL may hold `/`, so it cannot be one segment; each part is
185
+ * encoded instead. `getProductsByPageUrl('../../all')` resolved to
186
+ * `POST /products/all` — the whole catalogue instead of one page.
187
+ */
188
+ _pathSegments(value) {
189
+ return String(value)
190
+ .split('/')
191
+ .map((part) => this._pathSegment(part))
192
+ .join('/');
193
+ }
82
194
  /**
83
195
  * Performs an HTTP GET request.
84
196
  * @param {string} path - The path to append to the base URL.
@@ -181,6 +293,7 @@ export default class AsyncModules extends SyncModules {
181
293
  * @description Sends POST /users/refresh and, on success, stores the rotated access/refresh tokens and calls saveFunction.
182
294
  */
183
295
  async _performRefresh() {
296
+ var _a, _b;
184
297
  const url = this.state.url +
185
298
  `/api/content/users-auth-providers/marker/` +
186
299
  this.state.providerMarker +
@@ -193,20 +306,45 @@ export default class AsyncModules extends SyncModules {
193
306
  * @param {object} options.headers - Set the necessary headers for the request
194
307
  * @param {object} options.body - Send the current refresh token in the request body as a JSON string
195
308
  */
196
- const response = await fetch(url, {
197
- method: 'POST',
198
- headers: {
199
- // Indicate that the request body is in JSON format
200
- 'Content-Type': 'application/json',
201
- // Include the application token from the state
202
- 'x-app-token': this.state.token,
203
- // Include the device fingerprint
204
- 'x-device-metadata': this._getDeviceMetadata(),
205
- // x-guest-id is intentionally omitted: refresh is an auth-only call
206
- // (a pure guest has no refresh token), so guest scoping does not apply.
207
- },
208
- body: JSON.stringify({ refreshToken: this.state.refreshToken }),
209
- });
309
+ // `AbortSignal.timeout` is missing in older runtimes (Safari < 16, Node < 17.3)
310
+ let signal;
311
+ if (typeof AbortSignal !== 'undefined' &&
312
+ typeof AbortSignal.timeout === 'function') {
313
+ signal = AbortSignal.timeout(REFRESH_TIMEOUT_MS);
314
+ }
315
+ else if (typeof AbortController !== 'undefined') {
316
+ const controller = new AbortController();
317
+ // eslint-disable-next-line no-undef
318
+ const timer = setTimeout(() => controller.abort(), REFRESH_TIMEOUT_MS);
319
+ // Not cleared when the headers arrive: the body is read under the same signal.
320
+ // Must not keep a Node process alive for the timeout.
321
+ (_a = timer === null || timer === void 0 ? void 0 : timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
322
+ signal = controller.signal;
323
+ }
324
+ let response;
325
+ try {
326
+ response = await fetch(url, {
327
+ method: 'POST',
328
+ headers: {
329
+ // Indicate that the request body is in JSON format
330
+ 'Content-Type': 'application/json',
331
+ // Include the application token from the state
332
+ 'x-app-token': this.state.token,
333
+ // Include the device fingerprint
334
+ 'x-device-metadata': this._getDeviceMetadata(),
335
+ // x-guest-id is intentionally omitted: refresh is an auth-only call
336
+ // (a pure guest has no refresh token), so guest scoping does not apply.
337
+ },
338
+ body: JSON.stringify({ refreshToken: this.state.refreshToken }),
339
+ // Every request of the client waits on this one refresh (`_refreshPromise`):
340
+ // a refresh that never answered froze the whole client
341
+ ...(signal ? { signal } : {}),
342
+ });
343
+ }
344
+ catch {
345
+ // No answer (network, timeout): the token may still be valid, keep it
346
+ return false;
347
+ }
210
348
  // Check if the response status is OK (status code 200-299)
211
349
  if (response.ok) {
212
350
  // Parsed through the shared helper rather than `response.json()`: a `200` whose body is
@@ -218,6 +356,7 @@ export default class AsyncModules extends SyncModules {
218
356
  return false;
219
357
  }
220
358
  // Update the state's refreshToken and accessToken with the new tokens from the response
359
+ this.state._rejectedMetadata = undefined;
221
360
  this.state.refreshToken = result.refreshToken;
222
361
  this.state.accessToken = result.accessToken;
223
362
  // If a save function is defined in the state, call it with the new refresh token
@@ -228,6 +367,21 @@ export default class AsyncModules extends SyncModules {
228
367
  return true;
229
368
  }
230
369
  else {
370
+ // The platform rejected the token itself (`400 Provided token is incorrect`: expired,
371
+ // revoked, another device): drop it from this client, or every following request fired
372
+ // the same doomed refresh first. A 400 about the request (`Invalid x-device-metadata
373
+ // format`, `Missing x-device-metadata header`) says nothing about the token — keep it.
374
+ // `saveFunction` is not called: on another device the stored token is still valid.
375
+ if (response.status === 400) {
376
+ const body = await this._parseJson(response);
377
+ if (!/x-device-metadata/i.test(String((_b = body === null || body === void 0 ? void 0 : body.message) !== null && _b !== void 0 ? _b : ''))) {
378
+ this.state.refreshToken = undefined;
379
+ }
380
+ else {
381
+ // Kept, but not retried with the same metadata before every request
382
+ this.state._rejectedMetadata = this._getDeviceMetadata();
383
+ }
384
+ }
231
385
  // Return false to indicate that the token refresh failed
232
386
  return false;
233
387
  }
@@ -265,7 +419,10 @@ export default class AsyncModules extends SyncModules {
265
419
  };
266
420
  }
267
421
  // Check if 'data' is an instance of FormData or Blob
268
- if (data instanceof FormData || data instanceof Blob) {
422
+ // Runtimes without FormData/Blob (older Node, some workers): `instanceof` on an
423
+ // undefined global threw on every request, a GET included
424
+ if ((typeof FormData !== 'undefined' && data instanceof FormData) ||
425
+ (typeof Blob !== 'undefined' && data instanceof Blob)) {
269
426
  // Remove the 'Content-Type' header from options.headers
270
427
  delete options.headers['Content-Type'];
271
428
  // Set the 'accept' header to 'application/json', while preserving existing headers
@@ -282,7 +439,7 @@ export default class AsyncModules extends SyncModules {
282
439
  options.body = JSON.stringify(data);
283
440
  }
284
441
  // Check if there is an access token available in the state
285
- if (this.state.accessToken) {
442
+ if (this.state.accessToken && !this._signIn) {
286
443
  // Add an 'Authorization' header with the Bearer token to options.headers
287
444
  options.headers['Authorization'] = 'Bearer ' + this.state.accessToken;
288
445
  }
@@ -329,10 +486,13 @@ export default class AsyncModules extends SyncModules {
329
486
  * @description Define an asynchronous method 'browserResponse' that takes a path and options as parameters
330
487
  */
331
488
  async browserResponse(path, options) {
489
+ var _a;
332
490
  // Set when a proactive refresh ran and failed (dead/expired refresh token):
333
491
  // used below to skip the reactive refresh so we don't fire a second,
334
492
  // equally-doomed refresh on the 401 that the request is about to return.
335
493
  let proactiveRefreshFailed = false;
494
+ let status = 0;
495
+ let failure;
336
496
  try {
337
497
  // Proactive (eager) refresh: a session restored from storage has a refresh
338
498
  // token but no access token yet. Sending the first authenticated request
@@ -342,8 +502,9 @@ export default class AsyncModules extends SyncModules {
342
502
  // Fires at most once per session (skipped once accessToken is set), and is
343
503
  // off for custom-auth callers who manage tokens themselves.
344
504
  if (!this.state.accessToken &&
345
- this.state.refreshToken &&
346
- !this.state.customAuth) {
505
+ this._canRefresh() &&
506
+ !this.state.customAuth &&
507
+ !this._signIn) {
347
508
  const refreshed = await this.refreshToken();
348
509
  if (refreshed) {
349
510
  // Authenticated now — attach the bearer and drop the guest scoping
@@ -366,7 +527,11 @@ export default class AsyncModules extends SyncModules {
366
527
  if (!response.ok &&
367
528
  response.status === 401 &&
368
529
  !this.state.customAuth &&
369
- !proactiveRefreshFailed) {
530
+ !proactiveRefreshFailed &&
531
+ !this._signIn &&
532
+ // Without a refresh token there is nothing to refresh: the call went out
533
+ // as `{}` and every 401 of a guest or a wrong app token cost two requests
534
+ this._canRefresh()) {
370
535
  const refresh = await this.refreshToken();
371
536
  if (refresh) {
372
537
  // Update the Authorization header with the new access token and retry.
@@ -391,19 +556,33 @@ export default class AsyncModules extends SyncModules {
391
556
  }
392
557
  }
393
558
  // Handle non-OK responses (applies to the first response and to a failed retry).
394
- const status = response.status;
395
- const res = await this._parseJson(response);
396
- const statusKey = status;
397
- if (this.state.errorsFunctions && this.state.errorsFunctions[statusKey]) {
398
- this.state.errorsFunctions[statusKey](res);
399
- }
400
- // Determine whether to return or throw the response based on 'isShell' state
401
- if (this.state.isShell) {
402
- return res;
403
- }
404
- else {
405
- throw res;
406
- }
559
+ status = response.status;
560
+ const body = await this._parseJson(response);
561
+ // A failing answer whose body is not the platform's error (`{"error":…}`, `[]`,
562
+ // `null` from a gateway) used to be returned as data — `_fetchBoolean` read a 503 as `true`
563
+ const hasMessage = (value) => typeof (value === null || value === void 0 ? void 0 : value.message) === 'string' && value.message.trim() !== '';
564
+ failure =
565
+ body &&
566
+ typeof body === 'object' &&
567
+ typeof body.statusCode === 'number'
568
+ ? // The platform's own error: keep it, with a message to show
569
+ hasMessage(body)
570
+ ? body
571
+ : { ...body, message: `HTTP ${status}` }
572
+ : {
573
+ ...(body && typeof body === 'object' && !Array.isArray(body)
574
+ ? body
575
+ : {}),
576
+ statusCode: status,
577
+ // The text the server sent wins over the bare status
578
+ message: typeof body === 'string' && body
579
+ ? body
580
+ : hasMessage(body)
581
+ ? body.message
582
+ : `HTTP ${status}`,
583
+ pageData: null,
584
+ timestamp: new Date().toISOString(),
585
+ };
407
586
  }
408
587
  catch (e) {
409
588
  // Handle any errors that occur during the fetch process
@@ -411,10 +590,27 @@ export default class AsyncModules extends SyncModules {
411
590
  if (this.state.isShell) {
412
591
  return this._toShellError(e);
413
592
  }
414
- else {
415
- throw e;
593
+ // `@throws {IError}`: a dropped connection used to escape as a raw TypeError
594
+ const error = this._toShellError(e);
595
+ if (error !== e) {
596
+ error.cause = e;
416
597
  }
598
+ throw error;
599
+ }
600
+ // Called outside the try block: an exception from the handler (Next.js `redirect()`,
601
+ // `notFound()`) has to reach the caller, not turn into a `statusCode: 0` error
602
+ const statusKey = status;
603
+ const handler = this._subRequest
604
+ ? undefined
605
+ : (_a = this.state.errorsFunctions) === null || _a === void 0 ? void 0 : _a[statusKey];
606
+ if (handler) {
607
+ await handler(failure);
608
+ }
609
+ // Determine whether to return or throw the response based on 'isShell' state
610
+ if (this.state.isShell) {
611
+ return failure;
417
612
  }
613
+ throw failure;
418
614
  }
419
615
  /**
420
616
  * Describes a response whose body is not the JSON the API is supposed to send.
@@ -11,10 +11,12 @@ export default class StateModule {
11
11
  token: string | undefined;
12
12
  guestId: string | undefined;
13
13
  deviceMetadata: string | undefined;
14
+ nodeDeviceId: string | undefined;
14
15
  accessToken: string | undefined;
15
16
  traficLimit: boolean;
16
17
  refreshToken: string | undefined;
17
18
  _refreshPromise: Promise<boolean> | null;
19
+ _rejectedMetadata: string | undefined;
18
20
  providerMarker: string;
19
21
  customAuth: boolean;
20
22
  isShell: boolean;
@@ -1,3 +1,5 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { _warnGuestId } from './syncModules.js';
1
3
  // HTTP status codes for which a custom error handler may be configured.
2
4
  const ERROR_STATUS_CODES = [
3
5
  400, 401, 403, 404, 429, 500, 502, 503, 504,
@@ -14,32 +16,40 @@ export default class StateModule {
14
16
  * @description Constructor for StateModule.
15
17
  */
16
18
  constructor(url, config) {
17
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
18
20
  // In-flight token refresh, shared across all module instances (they share this
19
21
  // state object). De-duplicates concurrent refreshes so the single-use refresh
20
22
  // token is not burned by parallel requests. Null when no refresh is running.
21
23
  this._refreshPromise = null;
22
24
  this.url = url;
23
- this.lang = (_a = config.langCode) !== null && _a !== void 0 ? _a : 'en_US';
25
+ // `''` is not a language: it went out as `?langCode=` and every call answered 400
26
+ this.lang =
27
+ (typeof config.langCode === 'string' && config.langCode.trim()) ||
28
+ 'en_US';
24
29
  this.token = config.token;
25
30
  // Normalize empty string to undefined: an explicit '' must not masquerade
26
31
  // as a set guest id (it would otherwise suppress id resolution).
32
+ _warnGuestId(config.guestId);
27
33
  this.guestId = config.guestId || undefined;
28
34
  // Same normalization as guestId: an explicit '' must not suppress the
29
35
  // environment-derived fingerprint.
30
36
  this.deviceMetadata = config.deviceMetadata || undefined;
31
37
  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;
38
+ this.validationEnabled = (_b = (_a = config.validation) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : false;
39
+ this.validationStrictMode = (_d = (_c = config.validation) === null || _c === void 0 ? void 0 : _c.strictMode) !== null && _d !== void 0 ? _d : false;
40
+ this.validationLogErrors = (_f = (_e = config.validation) === null || _e === void 0 ? void 0 : _e.logErrors) !== null && _f !== void 0 ? _f : true;
41
+ if (this.validationStrictMode && !this.validationEnabled) {
42
+ // eslint-disable-next-line no-undef, no-console
43
+ console.warn('OneEntry SDK: validation.strictMode has no effect without validation.enabled: true');
44
+ }
45
+ this.rawData = (_g = config.rawData) !== null && _g !== void 0 ? _g : false;
46
+ this.refreshToken = (_j = (_h = config.auth) === null || _h === void 0 ? void 0 : _h.refreshToken) !== null && _j !== void 0 ? _j : undefined;
47
+ this.providerMarker = (_l = (_k = config.auth) === null || _k === void 0 ? void 0 : _k.providerMarker) !== null && _l !== void 0 ? _l : 'email';
48
+ this.customAuth = (_o = (_m = config.auth) === null || _m === void 0 ? void 0 : _m.customAuth) !== null && _o !== void 0 ? _o : false;
39
49
  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;
50
+ this.saveFunction = (_q = (_p = config.auth) === null || _p === void 0 ? void 0 : _p.saveFunction) !== null && _q !== void 0 ? _q : null;
51
+ this.isShell = (_s = (_r = config.errors) === null || _r === void 0 ? void 0 : _r.isShell) !== null && _s !== void 0 ? _s : true;
52
+ const customErrors = (_t = config.errors) === null || _t === void 0 ? void 0 : _t.customErrors;
43
53
  if (customErrors) {
44
54
  for (const code of ERROR_STATUS_CODES) {
45
55
  if (customErrors[code]) {
@@ -1,6 +1,11 @@
1
1
  import type { IUploadingQuery } from '../file-uploading/fileUploadingInterfaces.js';
2
2
  import type { IProductsQuery } from '../products/productsInterfaces.js';
3
3
  import type StateModule from './stateModule.js';
4
+ /**
5
+ * Warns about a caller's guest id the platform will not keep.
6
+ * @param {string | undefined} guestId - The id passed in config or to `setGuestId`.
7
+ */
8
+ export declare function _warnGuestId(guestId: string | undefined): void;
4
9
  /**
5
10
  * Abstract class representing synchronization modules.
6
11
  */
@@ -8,7 +13,6 @@ export default abstract class SyncModules {
8
13
  /** Protected properties for state and URL */
9
14
  protected state: StateModule;
10
15
  protected _url: string;
11
- private readonly _nodeDeviceId;
12
16
  /**
13
17
  * Constructor to initialize state and URL.
14
18
  * @param {StateModule} state - StateModule instance.
@@ -109,7 +113,11 @@ export default abstract class SyncModules {
109
113
  * numeric branch already produced.
110
114
  * 3. **Numbers** (`integer`, `float`, `real`) — cast to a JS number; anything
111
115
  * that is not a number (including an empty value) becomes `null`.
116
+ * 4. **Empty strings** of non-text types (`image`, `groupOfImages`, `file`,
117
+ * `timeInterval`, `date`, `dateTime`, `time`) — the API sends an unset value as
118
+ * `""`; it is replaced with `null`. For text types `""` is a real value and stays.
112
119
  * @param {any} attr - The attribute object to normalize in place.
120
+ * @param {boolean} [isEntityValue] - The attribute is a value of an entity (`attributeValues`): one without a `value` key is unset and gets `null`. Form fields and attribute-set schemas describe a field and get no key.
113
121
  */
114
122
  private _normalizeAttrValue;
115
123
  /**
@@ -172,15 +180,15 @@ export default abstract class SyncModules {
172
180
  /**
173
181
  * Sets the access token in the state.
174
182
  * @param {string} accessToken - The access token to set.
175
- * @returns {any} The instance of SyncModules for chaining.
183
+ * @returns {this} The same module, for chaining.
176
184
  */
177
- setAccessToken(accessToken: string): any;
185
+ setAccessToken(accessToken: string): this;
178
186
  /**
179
187
  * Sets the refresh token in the state.
180
188
  * @param {string} refreshToken - The refresh token to set.
181
- * @returns {any} The instance of SyncModules for chaining.
189
+ * @returns {this} The same module, for chaining.
182
190
  */
183
- setRefreshToken(refreshToken: string): any;
191
+ setRefreshToken(refreshToken: string): this;
184
192
  /**
185
193
  * Sets the guest identifier in the state.
186
194
  *
@@ -189,9 +197,9 @@ export default abstract class SyncModules {
189
197
  * (the SDK then falls back to the localStorage-backed id in the browser, or to
190
198
  * no guest id at all on the server).
191
199
  * @param {string} guestId - The guest identifier to set (empty string clears it).
192
- * @returns {any} The instance of SyncModules for chaining.
200
+ * @returns {this} The same module, for chaining.
193
201
  */
194
- setGuestId(guestId: string): any;
202
+ setGuestId(guestId: string): this;
195
203
  /**
196
204
  * Sets the device-metadata override in the state.
197
205
  *
@@ -202,9 +210,9 @@ export default abstract class SyncModules {
202
210
  * browser's string (obtained there via `getDeviceMetadata`). Pass an empty
203
211
  * string to clear the override and fall back to the computed fingerprint.
204
212
  * @param {string} deviceMetadata - The metadata string to send (empty string clears the override).
205
- * @returns {any} The instance of SyncModules for chaining.
213
+ * @returns {this} The same module, for chaining.
206
214
  */
207
- setDeviceMetadata(deviceMetadata: string): any;
215
+ setDeviceMetadata(deviceMetadata: string): this;
208
216
  /**
209
217
  * Returns the device-metadata string the SDK sends as the `x-device-metadata` header.
210
218
  *
@@ -238,7 +246,7 @@ export default abstract class SyncModules {
238
246
  *
239
247
  * **instanceId strategy:**
240
248
  * - Browser: `_getPersistentBrowserId('oneentry_device_id')` — read from localStorage, stable across sessions.
241
- * - Node.js / no localStorage: `_nodeDeviceId` — generated at instance creation,
249
+ * - Node.js / no localStorage: `state.nodeDeviceId` — generated once per client (shared by its modules),
242
250
  * lives until the process restarts.
243
251
  *
244
252
  * In a Node.js environment (no `window`) returns a simplified object without screen/navigator.