oneentry 1.0.153 → 1.0.155
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.
- package/README.md +2 -0
- package/changelog.md +58 -0
- package/dist/attribute-sets/attributeSetsInterfaces.d.ts +0 -9
- package/dist/attribute-sets/attributeSetsSchemas.d.ts +0 -4
- package/dist/attribute-sets/attributeSetsSchemas.js +0 -2
- package/dist/base/asyncModules.d.ts +10 -2
- package/dist/base/asyncModules.js +57 -227
- package/dist/base/stateModule.d.ts +5 -13
- package/dist/base/stateModule.js +15 -96
- package/dist/base/syncModules.d.ts +32 -0
- package/dist/base/syncModules.js +42 -1
- package/dist/base/utils.d.ts +2 -0
- package/dist/blocks/blocksApi.d.ts +20 -10
- package/dist/blocks/blocksApi.js +32 -12
- package/dist/blocks/blocksInterfaces.d.ts +18 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +13 -0
- package/dist/orders/ordersInterfaces.d.ts +1 -0
- package/dist/pages/pagesApi.js +13 -1
- package/dist/products/productsApi.d.ts +25 -64
- package/dist/products/productsApi.js +19 -61
- package/dist/products/productsInterfaces.d.ts +74 -70
- package/dist/templates-preview/templatesPreviewInterfaces.d.ts +1 -3
- package/dist/templates-preview/templatesPreviewSchemas.d.ts +0 -2
- package/dist/templates-preview/templatesPreviewSchemas.js +0 -1
- package/package.json +4 -1
- package/dist/base/result.d.ts +0 -39
- package/dist/base/result.js +0 -154
package/README.md
CHANGED
|
@@ -90,6 +90,8 @@ The second parameter of the constructor takes the 'config'. It contains the foll
|
|
|
90
90
|
|
|
91
91
|
- 'guestId' - Optional guest identifier sent as the "x-guest-id" header on unauthenticated requests. It enables guest cart / wishlist / activity flows. In the browser, if you omit it, the SDK generates a stable id and persists it in localStorage. On the server you must pass a per-visitor "guestId" (or call "setGuestId"): the SDK never auto-generates a server id, to avoid sharing one guest across visitors. The header is omitted once a user is authenticated.
|
|
92
92
|
|
|
93
|
+
- 'deviceMetadata' - Optional device-metadata string sent as the "x-device-metadata" header instead of the fingerprint the SDK computes from the current environment. The API binds refresh tokens to this header, so a server that issues tokens on behalf of a browser (for example, an OAuth code exchange keeping the client secret server-side) must pass the browser's string here — otherwise the issued refresh token is bound to the server's fingerprint and cannot be refreshed from the browser. Obtain the string in the browser via "getDeviceMetadata()" and set/clear it at runtime via "setDeviceMetadata".
|
|
94
|
+
|
|
93
95
|
- 'traficLimit' - Some methods use more than one request to the CMS so that the data you receive is complete and easy to work with. Pass the value "true" for this parameter to save traffic and decide for yourself what data you need. The default value "false".
|
|
94
96
|
|
|
95
97
|
- 'auth' - An object with authorization settings. By default, the SDK is configured to work with tokens inside the user's session and does not require any additional work from you. At the same time, the SDK does not store the session state between sessions. If you are satisfied with such settings, do not pass the variable 'auth' at all.
|
package/changelog.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# SDK Change Log
|
|
2
2
|
|
|
3
|
+
## v.1.0.155
|
|
4
|
+
|
|
5
|
+
### What's New
|
|
6
|
+
|
|
7
|
+
- Config > `deviceMetadata` — new optional config parameter that overrides the `x-device-metadata` header (sent on POST requests and token refresh) instead of the fingerprint computed from the current environment. The API binds refresh tokens to this header, so a server issuing tokens on behalf of a browser (e.g. an OAuth code exchange that keeps the client secret server-side) can now stamp the browser's fingerprint and the issued refresh token stays refreshable from that browser. Previously this required bypassing the SDK with a raw `fetch`.
|
|
8
|
+
- `setDeviceMetadata(deviceMetadata)` — new public method on every module: sets the `x-device-metadata` override at runtime (empty string clears it and falls back to the computed fingerprint).
|
|
9
|
+
- `getDeviceMetadata()` — new public method on every module: returns the `x-device-metadata` string the SDK sends (the override when set, otherwise the environment-derived fingerprint). Use it in the browser to obtain the value that a server-side token-issuing flow must forward; previously this required reaching into the protected `_getDeviceMetadata`.
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- `Blocks.getBlocks` — error responses no longer crash block enrichment. On an API error (e.g. `403` without list permission, or `422`) the normalized value is an `IError` without an `items` array; the method previously called `.items.map(...)` unconditionally and threw a `TypeError`. Enrichment now runs only when `items` is an array, and the error response is returned as-is.
|
|
14
|
+
|
|
15
|
+
- `Pages.getRootPages`, `getPages`, `getChildPagesByParentUrl`, `searchPage` — error responses no longer crash template enrichment. The shared `addTemplateToPages` helper called `.filter(...)` / `.map(...)` on its input; on an API error (e.g. `403` / `422`) that input is an `IError` object, not an array, which threw a `TypeError`. The helper now returns the error response as-is when the input is not an array.
|
|
16
|
+
|
|
17
|
+
- `Blocks.getProductsByBlockMarker` (used internally by block enrichment) — on an API error the method read `result.items` (which is `undefined` for an `IError`) and returned `undefined` instead of the error. It now returns the normalized error response when there is no `items` array.
|
|
18
|
+
|
|
19
|
+
### What's Deleted
|
|
20
|
+
|
|
21
|
+
- AttributesSets > `IAttributeSetsEntity.typeId` and `IAttributeSetsEntity.properties` — removed: the API no longer returns these fields for `getAttributes` / `getAttributeSetByMarker`. The attribute set type is available via the `type` object (`type.id`, `type.type`). The Zod schema (`AttributeSetEntitySchema`) is updated accordingly. The `typeId` **query parameter** of `getAttributes` is unaffected.
|
|
22
|
+
- TemplatePreviews > `ITemplatesPreviewEntity.attributeValues` — removed: the API no longer returns this field for `getTemplatePreviews` / `getTemplatePreviewByMarker` (it was always an empty object). The Zod schema (`TemplatePreviewEntitySchema`) is updated accordingly.
|
|
23
|
+
|
|
24
|
+
## v.1.0.154
|
|
25
|
+
|
|
26
|
+
### What's New
|
|
27
|
+
|
|
28
|
+
- Products > per-method query types — the single `IProductsQuery` is split into focused query types so each method only accepts the parameters it actually supports:
|
|
29
|
+
- `IProductsQueryBase` — base query (`offset`, `limit`, `sortOrder`, `sortKey`, `signPrice`) used by `getProducts`, `getProductsEmptyPage`, `getProductsByPageId`, `getProductsByPageUrl`.
|
|
30
|
+
- `IProductsRelatedQuery` — base query plus `statusMarker` and `templateMarker`, used by `getRelatedProductsById`.
|
|
31
|
+
- `IProductsPriceQuery` — base query without `sortKey`, plus `statusMarker`, used by `getProductsPriceByPageUrl`.
|
|
32
|
+
- `IProductsByIdsQuery` — only `signPrice` (`ids` is a dedicated method argument), used by `getProductsByIds`.
|
|
33
|
+
- All four types are now exported.
|
|
34
|
+
|
|
35
|
+
- Orders > `IOrderProductData.signedPrice` — new optional `signedPrice` (`string`) field: the signed (fixed) product price obtained together with the product data when `signPrice` is set. Used to carry the fixed price into an order line item.
|
|
36
|
+
|
|
37
|
+
- Products > `IProductInfo.signedPrice` — new optional `signedPrice` (`string`) field on the price-list items returned by `getProductsPriceByPageUrl`; populated with the signed (fixed) price when `signPrice` is set (mirrors `IProductsEntity.signedPrice`).
|
|
38
|
+
|
|
39
|
+
### What's Changed
|
|
40
|
+
|
|
41
|
+
- Products > `getProducts`, `getProductsEmptyPage`, `getProductsByPageId`, `getProductsByPageUrl`, `getProductsPriceByPageUrl`, `getRelatedProductsById`, `getProductsByIds` — `userQuery` is now typed with the corresponding per-method query type above instead of the broad `IProductsQuery`. `IProductsQuery` is retained as a **deprecated** alias of `IProductsQueryBase` for backward compatibility.
|
|
42
|
+
|
|
43
|
+
- Products > `getProductsByIds` — now accepts only `signPrice` in `userQuery` (`IProductsByIdsQuery`); `limit`/`sort`/filter markers are no longer query parameters of this endpoint. As a result `searchProduct` (quick search) no longer forwards an explicit `limit` to the internal `/ids` request.
|
|
44
|
+
|
|
45
|
+
- Products / Blocks / Orders — JSDoc for `signPrice` / `signedPrice` clarified ("Order storage marker for price fixing…") with links to the "Fixing the price" / "Fixed product price" documentation. Orders > `previewOrder` description cleaned up (removed the stray `???`). No structural change.
|
|
46
|
+
|
|
47
|
+
- HTTP core — the legacy Node.js `< 18` request path was removed. The SDK previously detected old Node versions and routed requests through a dynamically imported `https` module (`_NO_FETCH` / `state._https`); that branch did **not** perform token refresh, response validation, `errorsFunctions` callbacks or `isShell` handling, so behavior silently degraded on old Node. All requests now go through the native `fetch` path (browser and Node 18+), which collapses four duplicated `_fetchGet` / `_fetchPost` / `_fetchPut` / `_fetchDelete` implementations into one and gives every environment the same auth/validation/error behavior. **The SDK now requires Node 18+** (declared via `engines.node >= 18`).
|
|
48
|
+
|
|
49
|
+
### Bug Fixes
|
|
50
|
+
|
|
51
|
+
- Query parameters and free-text search are now URL-encoded (`encodeURIComponent`). Previously values containing spaces, `&`, `=` or non-ASCII characters corrupted the query string — most visibly in the text search of `Products.searchProduct`, `Pages.searchPage` and `Blocks.searchBlock`.
|
|
52
|
+
- `Pages.searchPage` — fixed the `url` query part: when no `url` was passed the request string previously contained stray output (`undefined` / a leading `&`). It is now built correctly and omitted when absent.
|
|
53
|
+
- Auth — the `401 → refresh → retry` path now flows through the same response handling as the initial request. The retried response is checked for `ok`, tolerates an empty body, and runs `errorsFunctions` / honors `isShell`. Previously a failed retry returned the raw error body as if it were successful data, and an empty retry body could throw from `.json()`.
|
|
54
|
+
|
|
55
|
+
- `defineOneEntry` — initializing the SDK without a project URL or app token no longer crashes with a cryptic `TypeError: Cannot read properties of undefined (reading 'endsWith')`. The function now validates its inputs up front and throws a clear, actionable error instead: a missing/empty `url` (PROJECT_URL) and a missing/empty `config.token` (APP_TOKEN) each produce a descriptive message with a correct usage example. Empty / whitespace-only values (e.g. an unfilled `.env` variable) are treated as missing.
|
|
56
|
+
|
|
57
|
+
### What's Deleted
|
|
58
|
+
|
|
59
|
+
- Removed the unused `src/base/result.ts` (dead `Result` class — never imported, and containing a misplaced `await` and unreachable branches).
|
|
60
|
+
|
|
3
61
|
## v.1.0.153
|
|
4
62
|
|
|
5
63
|
### What's New
|
|
@@ -206,7 +206,6 @@ interface IAttributeValidators {
|
|
|
206
206
|
* @property {string} updatedDate - The date when the attribute set was last updated. Example: "2023-10-01T12:00:00Z".
|
|
207
207
|
* @property {number} version - The version number of the attribute set, used for tracking changes or updates. Example: 1.
|
|
208
208
|
* @property {string} identifier - A string that uniquely identifies the attribute set. Example: "attributeSet1".
|
|
209
|
-
* @property {number} typeId - The numerical identifier representing the type of the attribute set. Example: 1.
|
|
210
209
|
* @property {string} title - The title or name of the attribute set. Example: "Product Attributes".
|
|
211
210
|
* @property {Record<string, IAttributeSchemaItem>} schema - Schema fields keyed by marker.
|
|
212
211
|
* @example
|
|
@@ -223,12 +222,6 @@ interface IAttributeValidators {
|
|
|
223
222
|
}
|
|
224
223
|
}
|
|
225
224
|
* @property {boolean} isVisible - Indicates whether the attribute set is visible or not. Example: true.
|
|
226
|
-
* @property {Record<string, unknown>} properties - Additional properties associated with the attribute set; empty object when none.
|
|
227
|
-
* @example
|
|
228
|
-
{
|
|
229
|
-
"color": "red",
|
|
230
|
-
"size": "M"
|
|
231
|
-
}
|
|
232
225
|
* @property {string} type - The type of the attribute set, which could be a specific classification or category. Example: "product", "user", "etc".
|
|
233
226
|
* @property {number} position - The position number for sorting the attribute set. Example: 1.
|
|
234
227
|
* @description This interface defines the structure of an attribute set entity.
|
|
@@ -239,11 +232,9 @@ interface IAttributeSetsEntity {
|
|
|
239
232
|
updatedDate: string;
|
|
240
233
|
version: number;
|
|
241
234
|
identifier: string;
|
|
242
|
-
typeId: number;
|
|
243
235
|
title: string;
|
|
244
236
|
schema: Record<string, IAttributeSchemaItem>;
|
|
245
237
|
isVisible: boolean;
|
|
246
|
-
properties: Record<string, unknown>;
|
|
247
238
|
type: IAttributeSetTypeRef;
|
|
248
239
|
position: number;
|
|
249
240
|
}
|
|
@@ -38,11 +38,9 @@ export declare const AttributeSetEntitySchema: z.ZodObject<{
|
|
|
38
38
|
updatedDate: z.ZodString;
|
|
39
39
|
version: z.ZodNumber;
|
|
40
40
|
identifier: z.ZodString;
|
|
41
|
-
typeId: z.ZodNumber;
|
|
42
41
|
title: z.ZodString;
|
|
43
42
|
schema: z.ZodObject<{}, z.core.$loose>;
|
|
44
43
|
isVisible: z.ZodBoolean;
|
|
45
|
-
properties: z.ZodObject<{}, z.core.$loose>;
|
|
46
44
|
type: z.ZodObject<{
|
|
47
45
|
id: z.ZodNumber;
|
|
48
46
|
type: z.ZodString;
|
|
@@ -60,11 +58,9 @@ export declare const AttributeSetsResponseSchema: z.ZodObject<{
|
|
|
60
58
|
updatedDate: z.ZodString;
|
|
61
59
|
version: z.ZodNumber;
|
|
62
60
|
identifier: z.ZodString;
|
|
63
|
-
typeId: z.ZodNumber;
|
|
64
61
|
title: z.ZodString;
|
|
65
62
|
schema: z.ZodObject<{}, z.core.$loose>;
|
|
66
63
|
isVisible: z.ZodBoolean;
|
|
67
|
-
properties: z.ZodObject<{}, z.core.$loose>;
|
|
68
64
|
type: z.ZodObject<{
|
|
69
65
|
id: z.ZodNumber;
|
|
70
66
|
type: z.ZodString;
|
|
@@ -47,11 +47,9 @@ exports.AttributeSetEntitySchema = zod_1.z.object({
|
|
|
47
47
|
updatedDate: zod_1.z.string(),
|
|
48
48
|
version: zod_1.z.number(),
|
|
49
49
|
identifier: zod_1.z.string(),
|
|
50
|
-
typeId: zod_1.z.number(),
|
|
51
50
|
title: zod_1.z.string(),
|
|
52
51
|
schema: zod_1.z.object({}).passthrough(),
|
|
53
52
|
isVisible: zod_1.z.boolean(),
|
|
54
|
-
properties: zod_1.z.object({}).passthrough(),
|
|
55
53
|
type: zod_1.z.object({
|
|
56
54
|
id: zod_1.z.number(),
|
|
57
55
|
type: zod_1.z.string(),
|
|
@@ -8,8 +8,6 @@ import type { IError } from './utils';
|
|
|
8
8
|
*/
|
|
9
9
|
export default abstract class AsyncModules extends SyncModules {
|
|
10
10
|
protected state: StateModule;
|
|
11
|
-
protected _NO_FETCH: boolean;
|
|
12
|
-
protected _https: any;
|
|
13
11
|
protected _url: string;
|
|
14
12
|
/**
|
|
15
13
|
* Constructor initializes the AsyncModules with a given state.
|
|
@@ -86,6 +84,16 @@ export default abstract class AsyncModules extends SyncModules {
|
|
|
86
84
|
* @returns {IHttpOptions} An object representing the request options.
|
|
87
85
|
*/
|
|
88
86
|
private makeOptions;
|
|
87
|
+
/**
|
|
88
|
+
* Reads a response body as JSON, tolerating an empty body.
|
|
89
|
+
*
|
|
90
|
+
* `Response.json()` throws on an empty body (e.g. 204 or an empty error
|
|
91
|
+
* payload); this helper mirrors the OK-path guard (`text ? JSON.parse : {}`)
|
|
92
|
+
* so both the success and the error branches handle empty bodies the same way.
|
|
93
|
+
* @param {Response} response - The fetch Response to read.
|
|
94
|
+
* @returns {Promise<unknown>} Parsed JSON, or an empty object when the body is empty/unparsable.
|
|
95
|
+
*/
|
|
96
|
+
private _parseJson;
|
|
89
97
|
/**
|
|
90
98
|
* Handles responses from the browser's fetch API.
|
|
91
99
|
* @param {string} path - The path to append to the base URL.
|
|
@@ -3,9 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
/* eslint-disable jsdoc/no-undefined-types */
|
|
7
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8
|
-
const buffer_1 = require("buffer");
|
|
9
6
|
const syncModules_1 = __importDefault(require("./syncModules"));
|
|
10
7
|
const validation_1 = require("./validation");
|
|
11
8
|
/**
|
|
@@ -19,12 +16,9 @@ class AsyncModules extends syncModules_1.default {
|
|
|
19
16
|
* @description Constructor initializes the AsyncModules with a given state.
|
|
20
17
|
*/
|
|
21
18
|
constructor(state) {
|
|
22
|
-
var _a;
|
|
23
19
|
super(state);
|
|
24
20
|
this.state = state;
|
|
25
21
|
this._url = this.state.url;
|
|
26
|
-
this._NO_FETCH = state._NO_FETCH;
|
|
27
|
-
this._https = (_a = state._https) !== null && _a !== void 0 ? _a : null;
|
|
28
22
|
}
|
|
29
23
|
/**
|
|
30
24
|
* Validates API response against a Zod schema (optional)
|
|
@@ -78,47 +72,7 @@ class AsyncModules extends syncModules_1.default {
|
|
|
78
72
|
* @description Define a protected asynchronous method '_fetchGet' that performs a GET request
|
|
79
73
|
*/
|
|
80
74
|
async _fetchGet(path) {
|
|
81
|
-
|
|
82
|
-
const options = this.makeOptions('GET');
|
|
83
|
-
// Check if the fetch operation should be performed using the Fetch API or an alternative method
|
|
84
|
-
if (!this._NO_FETCH) {
|
|
85
|
-
// If Fetch API is allowed, use 'browserResponse' to perform the request and return the result
|
|
86
|
-
return await this.browserResponse(path, options);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
// If Fetch API is not allowed, perform the request using Node.js HTTPS module
|
|
90
|
-
// Return a new promise to handle the asynchronous nature of the HTTPS request
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
// Use the HTTPS module to send a GET request to the specified path with the given options
|
|
93
|
-
const req = this._https.get(this._getFullPath(path), // Get the full URL path for the request
|
|
94
|
-
options, // Pass the options for the request
|
|
95
|
-
(res) => {
|
|
96
|
-
// Handle the response from the server
|
|
97
|
-
let responseData = ''; // Initialize a variable to accumulate response data
|
|
98
|
-
// Listen for 'data' events to receive chunks of data from the response
|
|
99
|
-
res.on('data', (chunk) => {
|
|
100
|
-
responseData += chunk; // Append each chunk to the accumulated response data
|
|
101
|
-
});
|
|
102
|
-
// Listen for the 'end' event to know when the response has been fully received
|
|
103
|
-
res.on('end', () => {
|
|
104
|
-
try {
|
|
105
|
-
// Attempt to parse the accumulated response data as JSON and resolve the promise with it
|
|
106
|
-
resolve(JSON.parse(responseData));
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
// If parsing fails, resolve the promise with the raw response data
|
|
111
|
-
resolve(responseData);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
// Listen for 'error' events on the request to handle any errors that occur
|
|
116
|
-
req.on('error', (error) => {
|
|
117
|
-
// Reject the promise with the error
|
|
118
|
-
reject(error);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
75
|
+
return this.browserResponse(path, this.makeOptions('GET'));
|
|
122
76
|
}
|
|
123
77
|
/**
|
|
124
78
|
* Performs an HTTP POST request.
|
|
@@ -128,54 +82,7 @@ class AsyncModules extends syncModules_1.default {
|
|
|
128
82
|
* @description Define a protected asynchronous method '_fetchPost' that performs a POST request
|
|
129
83
|
*/
|
|
130
84
|
async _fetchPost(path, data) {
|
|
131
|
-
|
|
132
|
-
const options = this.makeOptions('POST', data);
|
|
133
|
-
// Check if the fetch operation should be performed using the Fetch API or an alternative method
|
|
134
|
-
if (!this._NO_FETCH) {
|
|
135
|
-
// If Fetch API is allowed, use 'browserResponse' to perform the request and return the result
|
|
136
|
-
return await this.browserResponse(path, options);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// If Fetch API is not allowed, perform the request using Node.js HTTPS module
|
|
140
|
-
// Return a new promise to handle the asynchronous nature of the HTTPS request
|
|
141
|
-
return new Promise((resolve, reject) => {
|
|
142
|
-
// Use the HTTPS module to send a POST request to the specified path with the given options
|
|
143
|
-
const req = this._https.request(this._getFullPath(path), // Get the full URL path for the request
|
|
144
|
-
options, // Pass the options for the request
|
|
145
|
-
(res) => {
|
|
146
|
-
// Handle the response from the server
|
|
147
|
-
// Accumulate response chunks in an array for efficient memory usage
|
|
148
|
-
const chunks = [];
|
|
149
|
-
// Listen for 'data' events to receive chunks of data from the response
|
|
150
|
-
res.on('data', (chunk) => {
|
|
151
|
-
chunks.push(buffer_1.Buffer.isBuffer(chunk) ? chunk : buffer_1.Buffer.from(chunk));
|
|
152
|
-
});
|
|
153
|
-
// Listen for the 'end' event to know when the response has been fully received
|
|
154
|
-
res.on('end', () => {
|
|
155
|
-
try {
|
|
156
|
-
// Concatenate all chunks efficiently and parse as JSON
|
|
157
|
-
const responseData = buffer_1.Buffer.concat(chunks).toString('utf8');
|
|
158
|
-
resolve(JSON.parse(responseData));
|
|
159
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
// If parsing fails, resolve the promise with the raw response data
|
|
163
|
-
const responseData = buffer_1.Buffer.concat(chunks).toString('utf8');
|
|
164
|
-
resolve(responseData);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
// Listen for 'error' events on the request to handle any errors that occur
|
|
169
|
-
req.on('error', (error) => {
|
|
170
|
-
// Reject the promise with the error
|
|
171
|
-
reject(error);
|
|
172
|
-
});
|
|
173
|
-
// Write the provided data to the request body in JSON format
|
|
174
|
-
req.write(JSON.stringify(data));
|
|
175
|
-
// End the request to signal that all data has been sent
|
|
176
|
-
req.end();
|
|
177
|
-
});
|
|
178
|
-
}
|
|
85
|
+
return this.browserResponse(path, this.makeOptions('POST', data));
|
|
179
86
|
}
|
|
180
87
|
/**
|
|
181
88
|
* Performs an HTTP PUT request.
|
|
@@ -185,51 +92,7 @@ class AsyncModules extends syncModules_1.default {
|
|
|
185
92
|
* @description Define a protected asynchronous method '_fetchPut' that performs a PUT request
|
|
186
93
|
*/
|
|
187
94
|
async _fetchPut(path, body) {
|
|
188
|
-
|
|
189
|
-
const options = this.makeOptions('PUT', body);
|
|
190
|
-
// Check if the fetch operation should be performed using the Fetch API or an alternative method
|
|
191
|
-
if (!this._NO_FETCH) {
|
|
192
|
-
// If Fetch API is allowed, use 'browserResponse' to perform the request and return the result
|
|
193
|
-
return await this.browserResponse(path, options);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
// If Fetch API is not allowed, perform the request using Node.js HTTPS module
|
|
197
|
-
// Return a new promise to handle the asynchronous nature of the HTTPS request
|
|
198
|
-
return new Promise((resolve, reject) => {
|
|
199
|
-
// Use the HTTPS module to send a PUT request to the specified path with the given options
|
|
200
|
-
const req = this._https.request(this._getFullPath(path), // Get the full URL path for the request
|
|
201
|
-
options, // Pass the options for the request
|
|
202
|
-
(res) => {
|
|
203
|
-
// Handle the response from the server
|
|
204
|
-
let responseData = ''; // Initialize a variable to accumulate response data
|
|
205
|
-
// Listen for 'data' events to receive chunks of data from the response
|
|
206
|
-
res.on('data', (chunk) => {
|
|
207
|
-
responseData += chunk; // Append each chunk to the accumulated response data
|
|
208
|
-
});
|
|
209
|
-
// Listen for the 'end' event to know when the response has been fully received
|
|
210
|
-
res.on('end', () => {
|
|
211
|
-
try {
|
|
212
|
-
// Attempt to parse the accumulated response data as JSON and resolve the promise with it
|
|
213
|
-
resolve(JSON.parse(responseData));
|
|
214
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
// If parsing fails, resolve the promise with the raw response data
|
|
218
|
-
resolve(responseData);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
// Listen for 'error' events on the request to handle any errors that occur
|
|
223
|
-
req.on('error', (error) => {
|
|
224
|
-
// Reject the promise with the error
|
|
225
|
-
reject(error);
|
|
226
|
-
});
|
|
227
|
-
// Write the provided data to the request body in JSON format
|
|
228
|
-
req.write(JSON.stringify(body));
|
|
229
|
-
// End the request to signal that all data has been sent
|
|
230
|
-
req.end();
|
|
231
|
-
});
|
|
232
|
-
}
|
|
95
|
+
return this.browserResponse(path, this.makeOptions('PUT', body));
|
|
233
96
|
}
|
|
234
97
|
/**
|
|
235
98
|
* Performs an HTTP DELETE request.
|
|
@@ -239,47 +102,7 @@ class AsyncModules extends syncModules_1.default {
|
|
|
239
102
|
* @description Define a protected asynchronous method '_fetchDelete' that performs a DELETE request
|
|
240
103
|
*/
|
|
241
104
|
async _fetchDelete(path, body) {
|
|
242
|
-
|
|
243
|
-
const options = this.makeOptions('DELETE', body);
|
|
244
|
-
// Check if the fetch operation should be performed using the Fetch API or an alternative method
|
|
245
|
-
if (!this._NO_FETCH) {
|
|
246
|
-
// If Fetch API is allowed, use 'browserResponse' to perform the request and return the result
|
|
247
|
-
return await this.browserResponse(path, options);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
// If Fetch API is not allowed, perform the request using Node.js HTTPS module
|
|
251
|
-
// Return a new promise to handle the asynchronous nature of the HTTPS request
|
|
252
|
-
return new Promise((resolve, reject) => {
|
|
253
|
-
// Use the HTTPS module to send a DELETE request to the specified path with the given options
|
|
254
|
-
const req = this._https.delete(this._getFullPath(path), // Get the full URL path for the request
|
|
255
|
-
options, // Pass the options for the request
|
|
256
|
-
(res) => {
|
|
257
|
-
// Handle the response from the server
|
|
258
|
-
let responseData = ''; // Initialize a variable to accumulate response data
|
|
259
|
-
// Listen for 'data' events to receive chunks of data from the response
|
|
260
|
-
res.on('data', (chunk) => {
|
|
261
|
-
responseData += chunk; // Append each chunk to the accumulated response data
|
|
262
|
-
});
|
|
263
|
-
// Listen for the 'end' event to know when the response has been fully received
|
|
264
|
-
res.on('end', () => {
|
|
265
|
-
try {
|
|
266
|
-
// Attempt to parse the accumulated response data as JSON and resolve the promise with it
|
|
267
|
-
resolve(JSON.parse(responseData));
|
|
268
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
269
|
-
}
|
|
270
|
-
catch (error) {
|
|
271
|
-
// If parsing fails, resolve the promise with the raw response data
|
|
272
|
-
resolve(responseData);
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
// Listen for 'error' events on the request to handle any errors that occur
|
|
277
|
-
req.on('error', (error) => {
|
|
278
|
-
// Reject the promise with the error
|
|
279
|
-
reject(error);
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
}
|
|
105
|
+
return this.browserResponse(path, this.makeOptions('DELETE', body));
|
|
283
106
|
}
|
|
284
107
|
/**
|
|
285
108
|
* Wraps a fetch call whose only meaningful outcome is success or failure.
|
|
@@ -429,6 +252,24 @@ class AsyncModules extends syncModules_1.default {
|
|
|
429
252
|
}
|
|
430
253
|
return options;
|
|
431
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Reads a response body as JSON, tolerating an empty body.
|
|
257
|
+
*
|
|
258
|
+
* `Response.json()` throws on an empty body (e.g. 204 or an empty error
|
|
259
|
+
* payload); this helper mirrors the OK-path guard (`text ? JSON.parse : {}`)
|
|
260
|
+
* so both the success and the error branches handle empty bodies the same way.
|
|
261
|
+
* @param {Response} response - The fetch Response to read.
|
|
262
|
+
* @returns {Promise<unknown>} Parsed JSON, or an empty object when the body is empty/unparsable.
|
|
263
|
+
*/
|
|
264
|
+
async _parseJson(response) {
|
|
265
|
+
try {
|
|
266
|
+
const text = await response.text();
|
|
267
|
+
return text ? JSON.parse(text) : {};
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return {};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
432
273
|
/**
|
|
433
274
|
* Handles responses from the browser's fetch API.
|
|
434
275
|
* @param {string} path - The path to append to the base URL.
|
|
@@ -464,56 +305,45 @@ class AsyncModules extends syncModules_1.default {
|
|
|
464
305
|
}
|
|
465
306
|
}
|
|
466
307
|
// Perform a fetch request using the full URL obtained from '_getFullPath' and the provided options
|
|
467
|
-
|
|
308
|
+
let response = await fetch(this._getFullPath(path), options);
|
|
309
|
+
// Reactive refresh for mid-session expiry: access token was present but
|
|
310
|
+
// the server rejected it. Skipped when a proactive refresh already ran
|
|
311
|
+
// and failed (the refresh token is dead — retrying would 400 again).
|
|
312
|
+
// On success the request is retried once; the retry response then flows
|
|
313
|
+
// through the SAME ok / error handling below (status check, errorsFunctions,
|
|
314
|
+
// isShell) instead of being returned blindly.
|
|
315
|
+
if (!response.ok &&
|
|
316
|
+
response.status === 401 &&
|
|
317
|
+
!this.state.customAuth &&
|
|
318
|
+
!proactiveRefreshFailed) {
|
|
319
|
+
const refresh = await this.refreshToken();
|
|
320
|
+
if (refresh) {
|
|
321
|
+
// Update the Authorization header with the new access token and retry.
|
|
322
|
+
options.headers['Authorization'] = 'Bearer ' + this.state.accessToken;
|
|
323
|
+
response = await fetch(this._getFullPath(path), options);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
468
326
|
// Check if the response status is OK (status code 200-299)
|
|
469
327
|
if (response.ok) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
328
|
+
// Read the body as text; if it is empty return an empty object,
|
|
329
|
+
// otherwise parse it as JSON. A parse failure propagates to the
|
|
330
|
+
// catch below and is handled according to isShell.
|
|
331
|
+
const text = await response.text();
|
|
332
|
+
return (text ? JSON.parse(text) : {});
|
|
333
|
+
}
|
|
334
|
+
// Handle non-OK responses (applies to the first response and to a failed retry).
|
|
335
|
+
const status = response.status;
|
|
336
|
+
const res = await this._parseJson(response);
|
|
337
|
+
const statusKey = status;
|
|
338
|
+
if (this.state.errorsFunctions && this.state.errorsFunctions[statusKey]) {
|
|
339
|
+
this.state.errorsFunctions[statusKey](res);
|
|
340
|
+
}
|
|
341
|
+
// Determine whether to return or throw the response based on 'isShell' state
|
|
342
|
+
if (this.state.isShell) {
|
|
343
|
+
return res;
|
|
481
344
|
}
|
|
482
345
|
else {
|
|
483
|
-
|
|
484
|
-
// Reactive refresh for mid-session expiry: access token was present but
|
|
485
|
-
// the server rejected it. Skipped when a proactive refresh already ran
|
|
486
|
-
// and failed (the refresh token is dead — retrying would 400 again).
|
|
487
|
-
if (response.status === 401 &&
|
|
488
|
-
!this.state.customAuth &&
|
|
489
|
-
!proactiveRefreshFailed) {
|
|
490
|
-
// Attempt to refresh the access token
|
|
491
|
-
const refresh = await this.refreshToken();
|
|
492
|
-
if (refresh) {
|
|
493
|
-
// Update the Authorization header with the new access token
|
|
494
|
-
options.headers['Authorization'] =
|
|
495
|
-
'Bearer ' + this.state.accessToken;
|
|
496
|
-
// Retry the fetch request with updated headers
|
|
497
|
-
const secondResponse = await fetch(this._getFullPath(path), options);
|
|
498
|
-
// Return the JSON-parsed response of the retry request
|
|
499
|
-
return (await secondResponse.json());
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
// Store the response status and parse the response body as JSON
|
|
503
|
-
const status = response.status;
|
|
504
|
-
const res = await response.json();
|
|
505
|
-
const statusKey = status;
|
|
506
|
-
if (this.state.errorsFunctions &&
|
|
507
|
-
this.state.errorsFunctions[statusKey]) {
|
|
508
|
-
this.state.errorsFunctions[statusKey](res);
|
|
509
|
-
}
|
|
510
|
-
// Determine whether to return or throw the response based on 'isShell' state
|
|
511
|
-
if (this.state.isShell) {
|
|
512
|
-
return res;
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
throw res;
|
|
516
|
-
}
|
|
346
|
+
throw res;
|
|
517
347
|
}
|
|
518
348
|
}
|
|
519
349
|
catch (e) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { IConfig, IError } from './utils';
|
|
2
|
+
declare const ERROR_STATUS_CODES: readonly [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
3
|
+
type ErrorStatusCode = (typeof ERROR_STATUS_CODES)[number];
|
|
2
4
|
/**
|
|
3
5
|
* State module for managing application state and configuration.
|
|
4
6
|
* @description State module for managing application state and configuration.
|
|
@@ -8,30 +10,19 @@ export default class StateModule {
|
|
|
8
10
|
lang: string | undefined;
|
|
9
11
|
token: string | undefined;
|
|
10
12
|
guestId: string | undefined;
|
|
13
|
+
deviceMetadata: string | undefined;
|
|
11
14
|
accessToken: string | undefined;
|
|
12
15
|
traficLimit: boolean;
|
|
13
16
|
refreshToken: string | undefined;
|
|
14
17
|
_refreshPromise: Promise<boolean> | null;
|
|
15
18
|
providerMarker: string;
|
|
16
19
|
customAuth: boolean;
|
|
17
|
-
_NO_FETCH: boolean;
|
|
18
|
-
_https: any;
|
|
19
20
|
isShell: boolean;
|
|
20
21
|
validationEnabled: boolean;
|
|
21
22
|
validationStrictMode: boolean;
|
|
22
23
|
validationLogErrors: boolean;
|
|
23
24
|
rawData: boolean;
|
|
24
|
-
errorsFunctions:
|
|
25
|
-
400?: (data: IError) => any | null;
|
|
26
|
-
401?: (data: IError) => any | null;
|
|
27
|
-
403?: (data: IError) => any | null;
|
|
28
|
-
404?: (data: IError) => any | null;
|
|
29
|
-
429?: (data: IError) => any | null;
|
|
30
|
-
500?: (data: IError) => any | null;
|
|
31
|
-
502?: (data: IError) => any | null;
|
|
32
|
-
503?: (data: IError) => any | null;
|
|
33
|
-
504?: (data: IError) => any | null;
|
|
34
|
-
};
|
|
25
|
+
errorsFunctions: Partial<Record<ErrorStatusCode, (data: IError) => any>>;
|
|
35
26
|
saveFunction: (param: string) => void | null;
|
|
36
27
|
/**
|
|
37
28
|
* Constructor for StateModule
|
|
@@ -41,3 +32,4 @@ export default class StateModule {
|
|
|
41
32
|
*/
|
|
42
33
|
constructor(url: string, config: IConfig);
|
|
43
34
|
}
|
|
35
|
+
export {};
|