oneentry 1.0.155 → 1.0.157
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 +19 -0
- package/changelog.md +154 -1
- package/dist/attribute-sets/attributeSetsApi.js +4 -4
- package/dist/attribute-sets/attributeSetsInterfaces.d.ts +1 -1
- package/dist/auth-provider/authProviderSchemas.d.ts +2 -0
- package/dist/auth-provider/authProviderSchemas.js +2 -0
- package/dist/auth-provider/authProvidersInterfaces.d.ts +4 -0
- package/dist/base/asyncModules.d.ts +18 -2
- package/dist/base/asyncModules.js +32 -8
- package/dist/base/syncModules.d.ts +41 -144
- package/dist/base/syncModules.js +67 -359
- package/dist/base/timeIntervals.d.ts +95 -0
- package/dist/base/timeIntervals.js +321 -0
- package/dist/base/utils.d.ts +65 -7
- package/dist/base/validation.js +0 -1
- package/dist/forms/formsApi.js +2 -2
- package/dist/forms/formsInterfaces.d.ts +3 -3
- package/dist/forms-data/formsDataApi.js +2 -2
- package/dist/forms-data/formsDataInterfaces.d.ts +4 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -0
- package/dist/integration-collections/integrationCollectionsApi.js +6 -6
- package/dist/integration-collections/integrationCollectionsInterfaces.d.ts +4 -0
- package/dist/integration-collections/integrationCollectionsSchemas.d.ts +4 -0
- package/dist/integration-collections/integrationCollectionsSchemas.js +2 -0
- package/dist/menus/menusApi.js +1 -1
- package/dist/orders/ordersInterfaces.d.ts +10 -0
- package/dist/orders/ordersSchemas.d.ts +10 -0
- package/dist/orders/ordersSchemas.js +12 -0
- package/dist/pages/pagesApi.d.ts +4 -4
- package/dist/pages/pagesApi.js +10 -9
- package/dist/pages/pagesInterfaces.d.ts +14 -4
- package/dist/pages/pagesSchemas.d.ts +15 -0
- package/dist/pages/pagesSchemas.js +13 -1
- package/dist/products/productsApi.d.ts +4 -4
- package/dist/products/productsApi.js +12 -10
- package/dist/products/productsInterfaces.d.ts +16 -4
- package/dist/products/productsSchemas.d.ts +17 -0
- package/dist/products/productsSchemas.js +14 -1
- package/dist/subscriptions/subscriptionsApi.d.ts +4 -4
- package/dist/subscriptions/subscriptionsApi.js +3 -3
- package/dist/subscriptions/subscriptionsInterfaces.d.ts +26 -5
- package/dist/subscriptions/subscriptionsSchemas.d.ts +27 -1
- package/dist/subscriptions/subscriptionsSchemas.js +20 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,6 +181,25 @@ const api = defineOneEntry('your-url', {
|
|
|
181
181
|
|
|
182
182
|
OneEntry SDK supports optional validation of API responses using Zod. This feature is disabled by default and can be enabled for development or critical operations.
|
|
183
183
|
|
|
184
|
+
### Time Intervals
|
|
185
|
+
|
|
186
|
+
Attributes of type `timeInterval` return a compact recurrence rule (an anchor date, daily time ranges and repeat flags), not a ready list of slots. The SDK does not expand it eagerly — a single attribute can materialize into megabytes of slots — so resolve it on demand with `expandAttributeTimeIntervals`, passing the window you actually render:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
import { defineOneEntry, expandAttributeTimeIntervals } from 'oneentry'
|
|
190
|
+
|
|
191
|
+
const { Pages } = defineOneEntry('your-url', { token: 'your-app-token' })
|
|
192
|
+
const page = await Pages.getPageByUrl('booking')
|
|
193
|
+
|
|
194
|
+
const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
|
|
195
|
+
from: '2025-04-01',
|
|
196
|
+
to: '2025-04-30',
|
|
197
|
+
})
|
|
198
|
+
// [['2025-04-14T09:00:00.000Z', '2025-04-14T10:00:00.000Z'], …]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Also exported: `expandTimeIntervals(schedule, window)` for a single schedule (e.g. a form's `localizeInfos.intervals`), and the `isTimeIntervalAttribute` type guard.
|
|
202
|
+
|
|
184
203
|
### Errors
|
|
185
204
|
|
|
186
205
|
If you want to escape errors inside the sc, leave the "errors" property by default.
|
package/changelog.md
CHANGED
|
@@ -1,5 +1,158 @@
|
|
|
1
1
|
# SDK Change Log
|
|
2
2
|
|
|
3
|
+
## v.1.0.157
|
|
4
|
+
|
|
5
|
+
### What's New
|
|
6
|
+
|
|
7
|
+
- Subscriptions > `ISubscriptionEntity` — new exported type describing an available subscription: `id`, `identifier`, `localizeInfos` (`ILocalizeInfo`), `productIds`, `periodInDays`, `paymentAccountId`, `isUsed`. It backs the corrected return type of `getAllSubscriptions` (see below) and has a matching Zod schema (`SubscriptionEntitySchema` / `SubscriptionsListSchema`).
|
|
8
|
+
|
|
9
|
+
- Orders > `IOrderByMarkerEntity` — four fields the API already returns are now declared: `fulfillmentStatusIdentifier`, `fulfillmentStatusLocalizeInfos`, `paymentStatusIdentifier`, `paymentStatusLocalizeInfos` (each `null` until the corresponding status is assigned). Response validation drops every key its schema does not describe, so with `validation.enabled` these four were silently stripped from `getOrderByMarkerAndId` and `getAllOrdersByMarker` before reaching the consumer:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
const order = await Orders.getOrderByMarkerAndId('my_order', 179);
|
|
13
|
+
order.paymentStatusIdentifier; // "inProgress-payment"
|
|
14
|
+
order.paymentStatusLocalizeInfos; // { title: "In progress" }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Orders > `IBaseOrdersEntity` — `statusLocalizeInfos` (localized name of the status assigned to the order) is now declared on the `createOrder` / `updateOrderByMarkerAndId` response, which returned it but had it stripped by validation.
|
|
18
|
+
|
|
19
|
+
- IntegrationCollections > `ICollectionRow` — `langCode` and `formIdentifier` are now declared. Both are returned by the create/update row endpoints (`formIdentifier` on update) and were stripped by validation.
|
|
20
|
+
|
|
21
|
+
- AuthProvider > `ISignUpEntity` — `attributeSetId` and `attributesSets` are now declared on the `signUp` response, which returned them but had them stripped by validation.
|
|
22
|
+
|
|
23
|
+
- Products > `IProductSearchResult` and Pages > `IPageSearchResult` — new exported types describing the short card the quick search endpoints return: `{ id, title, pageId }` for products and `{ id, title }` for pages. Both have matching Zod schemas (`ProductSearchResultSchema` / `ProductSearchResponseSchema`, `PageSearchResultSchema` / `PageSearchResponseSchema`), so the quick search response is validated like every other response.
|
|
24
|
+
|
|
25
|
+
### What's Changed
|
|
26
|
+
|
|
27
|
+
- **Breaking** — single-file `image` attributes are now unwrapped in **every** module, not only in the few that ran the extra post-processing step. When an `image` attribute holds exactly one file, its `value` is the file object itself (`[img]` → `img`); values with two or more files stay an array, as before.
|
|
28
|
+
|
|
29
|
+
Previously the unwrapping lived in `_clearArray`, which ran only after `_dataPostProcess` (products, menus, forms, forms-data, attribute-sets, integration-collections and `Pages.searchPage`) and only looked at the `attributeValues` key. Everywhere else — blocks, all other pages methods, `Products.getProductsEmptyPage`, `Products.getProductBlockById`, admins, discounts, templates, orders, users — the same attribute arrived as a one-element array, so consumers had to branch on the shape. Form `attributes`, form-data fields and nested `additionalFields` were never unwrapped at all.
|
|
30
|
+
|
|
31
|
+
The logic now lives in `_normalizeAttr`, which runs on every attribute of every response:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const block = await Blocks.getBlockByMarker('promo');
|
|
35
|
+
// before: block.attributeValues.img.value[0].downloadLink
|
|
36
|
+
// now: block.attributeValues.img.value.downloadLink
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Code that reads `value[0]` from products or menus is unaffected — those modules already returned the object. Code that reads `value[0]` from blocks, pages, users or orders must drop the index.
|
|
40
|
+
|
|
41
|
+
- **Breaking** — a single-file `file` attribute is unwrapped like `image`: `value` is the file object itself, and an array only when several files are attached. `groupOfImages` is a collection by definition and always stays an array. `IBodyTypeFile.value` is widened to `IFileValue | IFileValue[]` accordingly.
|
|
42
|
+
|
|
43
|
+
- **Breaking** — `real` attributes are cast to a number. `integer` and `float` were already normalized, `real` was not, so the same numeric field reached the consumer as `10` or as `"10"` depending on which of the three types it was declared with:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const page = await Pages.getPageByUrl('catalog');
|
|
47
|
+
// before: page.attributeValues.amount.value // "5"
|
|
48
|
+
// now: page.attributeValues.amount.value // 5
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **Breaking** — numeric normalization now also runs on form attributes and on form-data fields, which were skipped entirely. A `rating` field of an `integer` form attribute is a `number`, not a string. `IBodyTypeStringNumberFloat.value` is widened to `string | number | null` (send a string; responses come back normalized).
|
|
52
|
+
|
|
53
|
+
- **Breaking** — an attribute with no value is always `null`. The API returns an empty localization map (`{}`) for an unset value, and the SDK passed it through for text-like types while numeric types became `null` — the same "no value" state had three representations. As a side effect, an unset `integer`/`float` no longer becomes `0`: `Number(null)` is `0`, so an explicit `null` from the API used to be reported as a real zero.
|
|
54
|
+
|
|
55
|
+
- **Breaking** — form `attributes` are sorted by `position`, the way `attributeValues` always were. The API returns form fields unordered (a field with `position: 10` could arrive after `position: 14`), so rendering a form in CMS order required sorting on the consumer side.
|
|
56
|
+
|
|
57
|
+
- **Breaking** — Subscriptions > `getAllSubscriptions` returns `ISubscriptionEntity[]` instead of `string[]`. The signature was taken from swagger, which declares `GET /api/content/subscriptions` as an array of markers; the endpoint actually returns full subscription objects, so response validation reported `expected string, received object` on every call and the declared type never matched the data. Callers that read markers should switch from the array element to its `identifier` field:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const subscriptions = await Subscriptions.getAllSubscriptions();
|
|
61
|
+
// before: subscriptions // string[]
|
|
62
|
+
// now: subscriptions.map((s) => s.identifier)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`getActiveSubscriptions` is unchanged (`string[]`).
|
|
66
|
+
|
|
67
|
+
- **Breaking (types only)** — `Products.searchProduct` returns `IProductsEntity[] | IProductSearchResult[] | IError` and `Pages.searchPage` returns `IPagesEntity[] | IPageSearchResult[] | IError`. With `traficLimit: true` both methods return the raw quick search response — a short card without `attributeValues`, `localizeInfos`, `blocks` and the rest of the entity — while the signature promised a full entity in both modes, so a consumer reading `attributeValues` in traficLimit mode got `undefined` with no type error. Runtime behaviour is unchanged; narrow by config or by field:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const found = await Products.searchProduct('cos');
|
|
71
|
+
if (Array.isArray(found) && found.length && 'attributeValues' in found[0]) {
|
|
72
|
+
// IProductsEntity[] — traficLimit is off
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- `Pages.searchPage` no longer runs the template lookup over the traficLimit response. Short cards carry no `templateIdentifier`, so the step could never attach anything; the result is identical, minus the pointless pass.
|
|
77
|
+
|
|
78
|
+
### Bug Fixes
|
|
79
|
+
|
|
80
|
+
- Methods whose result is just success-or-failure no longer report `true` when the API rejected the request: `Subscriptions.cancelSubscription`, `Subscriptions.recoverSubscriptions`, `Events.subscribeByMarker`, `Events.unsubscribeByMarker`, `Events.subscribeToForm`, `Events.unsubscribeFromForm`.
|
|
81
|
+
|
|
82
|
+
With `errors.isShell` enabled — the default — the SDK **returns** the API error instead of throwing it. The shared helper behind these six methods only had a `try/catch`, so nothing ever reached its `catch` and every failure was reported as a success: `cancelSubscription` answered `true` while the API replied `404 "Subscription already inactive"`, and the `IError` half of the declared `Promise<boolean | IError>` was unreachable. The helper now also inspects the returned value and passes the error through:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const cancelled = await Subscriptions.cancelSubscription({ marker: 'premium' });
|
|
86
|
+
// before: true — on 404 and 403 alike
|
|
87
|
+
// now: { statusCode: 404, message: 'Subscription already inactive', ... }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The success path is unchanged (`true`), and `isShell: false` still throws. Code that checks these results with `if (result)` must switch to `if (result === true)` — an error object is truthy.
|
|
91
|
+
|
|
92
|
+
## v.1.0.156
|
|
93
|
+
|
|
94
|
+
### What's New
|
|
95
|
+
|
|
96
|
+
- `expandAttributeTimeIntervals(attr, { from, to })` — new top-level export that resolves a whole `timeInterval` attribute into concrete `[start, end]` ISO pairs for a window you choose. This is the one-call replacement for the removed `timeIntervals` field: it walks the attribute's groups and schedules and merges the results (merging matters — deduplication and ordering only hold within a single schedule). Anything that is not a `timeInterval` attribute yields an empty array, so it is safe to call without checking `type` first.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { expandAttributeTimeIntervals } from 'oneentry';
|
|
100
|
+
|
|
101
|
+
const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
|
|
102
|
+
from: '2025-04-01',
|
|
103
|
+
to: '2025-04-30',
|
|
104
|
+
});
|
|
105
|
+
// [['2025-04-14T09:00:00.000Z', '2025-04-14T10:00:00.000Z'], …]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `expandTimeIntervals(schedule, { from, to })` — new top-level export that resolves a single schedule. Accepts both shapes the API returns: entity schedules (`attributeValues[marker].value[].values[]` on pages, products, blocks and attribute sets) and form schedules (`attributes[].localizeInfos.intervals[]`). Use it when you already hold one schedule — most notably on forms, whose schedules are already typed:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const field = form.attributes.find((a) => a.marker === 'booking');
|
|
112
|
+
|
|
113
|
+
const slots = (field?.localizeInfos.intervals ?? []).flatMap((schedule) =>
|
|
114
|
+
expandTimeIntervals(schedule, { from: '2025-05-01', to: '2025-05-31' }),
|
|
115
|
+
);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Both functions are pure — they do not mutate their input and perform no requests.
|
|
119
|
+
|
|
120
|
+
- `isTimeIntervalAttribute(attr)` — new exported type guard narrowing an `IAttributeValue` to `ITimeIntervalAttributeValue`. `IAttributeValue.value` is `unknown` because its shape depends on `type`; this guard is what lets you reach the schedules without a cast:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const attr = page.attributeValues.interval;
|
|
124
|
+
if (isTimeIntervalAttribute(attr)) {
|
|
125
|
+
attr.value[0].values[0].dates; // fully typed
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- `ITimeIntervalAttributeValue`, `ITimeIntervalGroup`, `ITimeIntervalEntitySchedule`, `ITimeIntervalWindow` and `TimeIntervalPair` — new exported types covering the whole `timeInterval` payload: the attribute, its groups, an entity schedule, the expansion window and a resolved slot. `ITimeIntervalSchedule` and `IAttributeValue` are now exported for the same reason. The payload previously had no typed representation at all.
|
|
130
|
+
|
|
131
|
+
### What's Changed
|
|
132
|
+
|
|
133
|
+
- `ITimeIntervalSchedule` — `range` is typed `string[]` instead of `unknown[]` (it is a pair of ISO dates), and the optional `inEveryWeek` flag is documented; the SDK always read it, but the interface omitted it.
|
|
134
|
+
|
|
135
|
+
### Bug Fixes
|
|
136
|
+
|
|
137
|
+
These affect `expandTimeIntervals`, which replaces the removed built-in expansion:
|
|
138
|
+
|
|
139
|
+
- The expansion horizon is no longer hardcoded. Monthly recurrence stopped exactly 12 months after the anchor and weekly recurrence stopped at the end of the anchor's month, so slots beyond that could not be obtained at all. The window is now the horizon.
|
|
140
|
+
- A schedule with no recurrence flags (`inEveryWeek: false, inEveryMonth: false`) produced no intervals at all — `_processScheduleDates` had no branch for that case. A plain date range now yields slots for every day in it.
|
|
141
|
+
- Weekly recurrence combined with monthly no longer emits dates **before** the schedule's start date. The old branch walked from the 1st of the anchor's month, so a schedule starting Monday 2025-04-14 also emitted 2025-04-07.
|
|
142
|
+
- Weekly recurrence was host-timezone dependent: it computed its end-of-month bound with `getFullYear`/`getMonth` (local time) while every other date operation used UTC, so the result shifted with the machine's timezone. All arithmetic is now UTC.
|
|
143
|
+
- Weekly+monthly recurrence silently dropped months: it advanced the month before pinning the day to the 1st, so an anchor on the 31st overflowed short months and lost 5 of 12 months.
|
|
144
|
+
- Identical intervals are now actually deduplicated. The old code collected into a `Set` of array references, which compares by identity, so duplicates always survived despite the intent.
|
|
145
|
+
- A range with a non-positive `period` no longer hangs. The slot loop never advanced its cursor and spun forever; such ranges are now skipped.
|
|
146
|
+
- Malformed input no longer throws. `_addTimeIntervalsToFormSchedules` dereferenced its argument unguarded (`TypeError` on `undefined`), and both expanders read `dates[0]` / `range[0]` without checking the array existed. `expandTimeIntervals` returns an empty array instead.
|
|
147
|
+
|
|
148
|
+
### What's Deleted
|
|
149
|
+
|
|
150
|
+
- **Breaking** — the computed `timeIntervals` field is no longer added to `timeInterval` attribute values. It was injected into every response carrying a `timeInterval` attribute (pages, products, blocks, attribute sets and forms) and materialized a full year of slots regardless of what the caller needed: a single attribute with hourly slots expanded to roughly 2,000 lines of JSON, and finer slot periods reached megabytes — enough to blow past framework data-cache limits. The field was never declared in any interface or Zod schema, so TypeScript consumers could only reach it through a cast.
|
|
151
|
+
|
|
152
|
+
Migrate by calling `expandAttributeTimeIntervals(attr, window)` with the window you actually render. The source data it expands (`dates`/`range`, `times`/`intervals`, `inEveryWeek`, `inEveryMonth`) is unchanged and still on every schedule, so nothing is lost — it is now resolved on demand instead of eagerly, and the compact rule is what gets cached.
|
|
153
|
+
|
|
154
|
+
- `_addTimeIntervalsToSchedules` and `_addTimeIntervalsToFormSchedules` — removed from every module. Despite the `_` prefix these were public and callable (e.g. `Pages._addTimeIntervalsToSchedules`). Use `expandTimeIntervals`.
|
|
155
|
+
|
|
3
156
|
## v.1.0.155
|
|
4
157
|
|
|
5
158
|
### What's New
|
|
@@ -247,7 +400,7 @@
|
|
|
247
400
|
|
|
248
401
|
- Discounts > `getAllDiscounts` — removed `'PERSONAL_BONUS'` from type filter parameter.
|
|
249
402
|
|
|
250
|
-
- Forms > `IFormsEntity` — type narrowed to `'order' | '
|
|
403
|
+
- Forms > `IFormsEntity` — type narrowed to `'order' | 'sign_in_up' | 'collection' | 'data' | 'rating'`, removed `moduleFormConfigs` field.
|
|
251
404
|
|
|
252
405
|
- Products > `getProductsEmptyPage` — changed from GET to POST, added `body` parameter, return type changed to `IAggregatedProductGroup[]`.
|
|
253
406
|
|
|
@@ -50,7 +50,7 @@ class AttributesSetsApi extends asyncModules_1.default {
|
|
|
50
50
|
const result = await this._fetchGet(`?` + this._queryParamsToString(query));
|
|
51
51
|
// Validate response if validation is enabled
|
|
52
52
|
const validated = this._validateResponse(result, attributeSetsSchemas_1.AttributeSetsResponseSchema);
|
|
53
|
-
return this.
|
|
53
|
+
return this._normalizeData(validated, langCode);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Getting all attributes with data from the attribute set.
|
|
@@ -65,7 +65,7 @@ class AttributesSetsApi extends asyncModules_1.default {
|
|
|
65
65
|
const result = await this._fetchGet(`/${marker}/attributes?langCode=${langCode}`);
|
|
66
66
|
// Validate response if validation is enabled
|
|
67
67
|
const validated = this._validateResponse(result, attributeSetsSchemas_1.AttributesArrayResponseSchema);
|
|
68
|
-
return this.
|
|
68
|
+
return this._normalizeData(validated, langCode);
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* Get a single attribute with data from the attribute sets.
|
|
@@ -81,7 +81,7 @@ class AttributesSetsApi extends asyncModules_1.default {
|
|
|
81
81
|
const result = await this._fetchGet(`/${setMarker}/attributes/${attributeMarker}?langCode=${langCode}`);
|
|
82
82
|
// Validate response if validation is enabled
|
|
83
83
|
const validated = this._validateResponse(result, attributeSetsSchemas_1.AttributeEntitySchema);
|
|
84
|
-
return this.
|
|
84
|
+
return this._normalizeData(validated, langCode);
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
87
|
* Getting a single object from a set of attributes by marker.
|
|
@@ -96,7 +96,7 @@ class AttributesSetsApi extends asyncModules_1.default {
|
|
|
96
96
|
const result = await this._fetchGet(`/marker/${marker}?langCode=${langCode}`);
|
|
97
97
|
// Validate response if validation is enabled
|
|
98
98
|
const validated = this._validateResponse(result, attributeSetsSchemas_1.AttributeSetEntitySchema);
|
|
99
|
-
return this.
|
|
99
|
+
return this._normalizeData(validated, langCode);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
exports.default = AttributesSetsApi;
|
|
@@ -82,7 +82,7 @@ type AttributeType = 'string' | 'text' | 'textWithHeader' | 'integer' | 'real' |
|
|
|
82
82
|
* Represents an attribute set entity.
|
|
83
83
|
* @interface IAttributesSetsEntity
|
|
84
84
|
* @property {AttributeType} type - Attribute type. Example: "string", "text", "integer", "etc".
|
|
85
|
-
* @property {unknown} [value] - Value of the attribute,
|
|
85
|
+
* @property {unknown} [value] - Value of the attribute, normalized the same way as an entity attribute value: `number | null` for numeric types, the file object itself for a single-file `image`/`file`, `null` when the attribute carries no value.
|
|
86
86
|
* @property {unknown} initialValue - Initial value of the attribute.
|
|
87
87
|
* @property {string} marker - Textual identifier of the attribute (marker). Example: "color", "size", "etc".
|
|
88
88
|
* @property {number} position - Position number for sorting. Example: 1.
|
|
@@ -26,6 +26,8 @@ export declare const SignUpResponseSchema: z.ZodObject<{
|
|
|
26
26
|
isDeleted: z.ZodOptional<z.ZodBoolean>;
|
|
27
27
|
state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
28
28
|
rating: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
29
|
+
attributeSetId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
30
|
+
attributesSets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
29
31
|
}, z.core.$strip>;
|
|
30
32
|
/**
|
|
31
33
|
* Auth response schema (login/refresh)
|
|
@@ -30,6 +30,8 @@ exports.SignUpResponseSchema = zod_1.z.object({
|
|
|
30
30
|
isDeleted: zod_1.z.boolean().optional(),
|
|
31
31
|
state: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
|
|
32
32
|
rating: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
33
|
+
attributeSetId: zod_1.z.number().nullable().optional(),
|
|
34
|
+
attributesSets: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
33
35
|
});
|
|
34
36
|
/**
|
|
35
37
|
* Auth response schema (login/refresh)
|
|
@@ -268,6 +268,8 @@ interface IOauthData {
|
|
|
268
268
|
* @property {boolean} [isDeleted] - Whether the entity is deleted. Example: false.
|
|
269
269
|
* @property {Record<string, unknown>} [state] - Additional state information. Example: {}.
|
|
270
270
|
* @property {IRating} [rating] - Rating data.
|
|
271
|
+
* @property {number | null} [attributeSetId] - Identifier of the attribute set attached to the user, or null when none is attached. Example: null.
|
|
272
|
+
* @property {Record<string, unknown>} [attributesSets] - Attribute sets attached to the user, keyed by marker; empty object when none. Example: {}.
|
|
271
273
|
* @description This interface defines the structure of a sign-up entity.
|
|
272
274
|
*/
|
|
273
275
|
interface ISignUpEntity {
|
|
@@ -285,6 +287,8 @@ interface ISignUpEntity {
|
|
|
285
287
|
isDeleted?: boolean;
|
|
286
288
|
state?: Record<string, unknown>;
|
|
287
289
|
rating?: IRating;
|
|
290
|
+
attributeSetId?: number | null;
|
|
291
|
+
attributesSets?: Record<string, unknown>;
|
|
288
292
|
}
|
|
289
293
|
/**
|
|
290
294
|
* Interface representing a code entity used for user registration or verification processes.
|
|
@@ -15,6 +15,17 @@ export default abstract class AsyncModules extends SyncModules {
|
|
|
15
15
|
* @description Constructor initializes the AsyncModules with a given state.
|
|
16
16
|
*/
|
|
17
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;
|
|
18
29
|
/**
|
|
19
30
|
* Validates API response against a Zod schema (optional)
|
|
20
31
|
* @param {unknown} data - The data to validate
|
|
@@ -59,8 +70,13 @@ export default abstract class AsyncModules extends SyncModules {
|
|
|
59
70
|
*
|
|
60
71
|
* Several endpoints (cancel/recover subscription, subscribe/unsubscribe to
|
|
61
72
|
* events) return no useful body — callers only care whether the request
|
|
62
|
-
* succeeded. This helper resolves to `true` on success and to the
|
|
63
|
-
*
|
|
73
|
+
* succeeded. This helper resolves to `true` on success and to the error
|
|
74
|
+
* (as IError) on failure, centralizing the repeated try/catch.
|
|
75
|
+
*
|
|
76
|
+
* The returned value has to be inspected as well: with `isShell` enabled
|
|
77
|
+
* (the default) browserResponse returns the API error instead of throwing
|
|
78
|
+
* it, so relying on the catch alone would report every failed call — a 404
|
|
79
|
+
* from cancelSubscription, a 403 from recoverSubscriptions — as a success.
|
|
64
80
|
* @param {() => Promise<unknown>} request - Thunk performing the fetch call.
|
|
65
81
|
* @returns {Promise<boolean | IError>} `true` on success, IError on failure.
|
|
66
82
|
*/
|
|
@@ -20,6 +20,26 @@ class AsyncModules extends syncModules_1.default {
|
|
|
20
20
|
this.state = state;
|
|
21
21
|
this._url = this.state.url;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Detects an API error returned as a value instead of being thrown.
|
|
25
|
+
*
|
|
26
|
+
* With `isShell` enabled (the default) `browserResponse` returns the error
|
|
27
|
+
* body — and a caught exception — instead of throwing, so a failed request
|
|
28
|
+
* is indistinguishable from a successful one by control flow alone.
|
|
29
|
+
* @param {unknown} value - Value returned by a request.
|
|
30
|
+
* @returns {boolean} True when the value is an API error (statusCode >= 400) or a thrown error object.
|
|
31
|
+
* @description Recognizes both the OneEntry error body and errors caught by browserResponse (e.g. a network failure).
|
|
32
|
+
*/
|
|
33
|
+
_isErrorResponse(value) {
|
|
34
|
+
if (value instanceof Error) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return (value !== null &&
|
|
38
|
+
typeof value === 'object' &&
|
|
39
|
+
'statusCode' in value &&
|
|
40
|
+
typeof value.statusCode === 'number' &&
|
|
41
|
+
value.statusCode >= 400);
|
|
42
|
+
}
|
|
23
43
|
/**
|
|
24
44
|
* Validates API response against a Zod schema (optional)
|
|
25
45
|
* @param {unknown} data - The data to validate
|
|
@@ -33,11 +53,7 @@ class AsyncModules extends syncModules_1.default {
|
|
|
33
53
|
return data;
|
|
34
54
|
}
|
|
35
55
|
// Skip validation for error responses (statusCode indicates API error)
|
|
36
|
-
if (data
|
|
37
|
-
typeof data === 'object' &&
|
|
38
|
-
'statusCode' in data &&
|
|
39
|
-
typeof data.statusCode === 'number' &&
|
|
40
|
-
data.statusCode >= 400) {
|
|
56
|
+
if (this._isErrorResponse(data)) {
|
|
41
57
|
return data;
|
|
42
58
|
}
|
|
43
59
|
// Use strict or safe validation based on config
|
|
@@ -109,14 +125,22 @@ class AsyncModules extends syncModules_1.default {
|
|
|
109
125
|
*
|
|
110
126
|
* Several endpoints (cancel/recover subscription, subscribe/unsubscribe to
|
|
111
127
|
* events) return no useful body — callers only care whether the request
|
|
112
|
-
* succeeded. This helper resolves to `true` on success and to the
|
|
113
|
-
*
|
|
128
|
+
* succeeded. This helper resolves to `true` on success and to the error
|
|
129
|
+
* (as IError) on failure, centralizing the repeated try/catch.
|
|
130
|
+
*
|
|
131
|
+
* The returned value has to be inspected as well: with `isShell` enabled
|
|
132
|
+
* (the default) browserResponse returns the API error instead of throwing
|
|
133
|
+
* it, so relying on the catch alone would report every failed call — a 404
|
|
134
|
+
* from cancelSubscription, a 403 from recoverSubscriptions — as a success.
|
|
114
135
|
* @param {() => Promise<unknown>} request - Thunk performing the fetch call.
|
|
115
136
|
* @returns {Promise<boolean | IError>} `true` on success, IError on failure.
|
|
116
137
|
*/
|
|
117
138
|
async _fetchBoolean(request) {
|
|
118
139
|
try {
|
|
119
|
-
await request();
|
|
140
|
+
const result = await request();
|
|
141
|
+
if (this._isErrorResponse(result)) {
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
120
144
|
return true;
|
|
121
145
|
}
|
|
122
146
|
catch (e) {
|
|
@@ -88,136 +88,35 @@ export default abstract class SyncModules {
|
|
|
88
88
|
*/
|
|
89
89
|
protected _normalizePostBody(body: any, langCode?: string): any;
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
91
|
+
* Normalizes the value of a single attribute in place.
|
|
92
92
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* In that case `value` is unwrapped: `[img]` → `img`.
|
|
93
|
+
* Applies the three type-driven fixes the API response needs, so that an
|
|
94
|
+
* attribute of a given type always reaches the consumer in the same shape,
|
|
95
|
+
* no matter which collection it arrived in:
|
|
97
96
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
97
|
+
* 1. **Single-file values** (`image`, `file`) — the API always sends an array,
|
|
98
|
+
* even for one file: `[img]` → `img`. Multi-file values and `groupOfImages`
|
|
99
|
+
* (a collection by definition) stay an array.
|
|
100
|
+
* 2. **Empty values** — an attribute with no value comes back as an empty
|
|
101
|
+
* localization map `{}`; it is replaced with `null`, the same marker the
|
|
102
|
+
* numeric branch already produced.
|
|
103
|
+
* 3. **Numbers** (`integer`, `float`, `real`) — cast to a JS number; anything
|
|
104
|
+
* that is not a number (including an empty value) becomes `null`.
|
|
105
|
+
* @param {any} attr - The attribute object to normalize in place.
|
|
101
106
|
*/
|
|
102
|
-
|
|
107
|
+
private _normalizeAttrValue;
|
|
103
108
|
/**
|
|
104
109
|
* Sorts attributes by their positions.
|
|
105
110
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* @
|
|
111
|
+
* Each attribute has a `position` field, and the API returns them in no
|
|
112
|
+
* particular order. The method rebuilds the collection sorted by ascending
|
|
113
|
+
* `position`, so the display order matches the order defined in the CMS.
|
|
114
|
+
* Both container shapes the API uses are handled: an object keyed by marker
|
|
115
|
+
* (`attributeValues`) and an array (form `attributes`).
|
|
116
|
+
* @param {any} data - The attributes collection to sort.
|
|
117
|
+
* @returns {any} Sorted attributes, in the same container shape.
|
|
112
118
|
*/
|
|
113
119
|
protected _sortAttributes: (data: any) => any;
|
|
114
|
-
/**
|
|
115
|
-
* Adds a specified number of days to a date.
|
|
116
|
-
* @param {Date} date - The initial date.
|
|
117
|
-
* @param {number} days - The number of days to add.
|
|
118
|
-
* @returns {any} The new date with added days.
|
|
119
|
-
*/
|
|
120
|
-
protected _addDays(date: Date, days: number): any;
|
|
121
|
-
/**
|
|
122
|
-
* Common logic for processing schedule dates (weekly, monthly, or both).
|
|
123
|
-
*
|
|
124
|
-
* Abstracts date iteration for three scheduling modes:
|
|
125
|
-
*
|
|
126
|
-
* - **`inEveryWeek` only**: starting from the start date, generates dates
|
|
127
|
-
* with a 7-day step until the end of the current month.
|
|
128
|
-
*
|
|
129
|
-
* - **`inEveryMonth` only**: pins the day-of-month from the start date
|
|
130
|
-
* and repeats it for each of the next 12 months. If the month does not
|
|
131
|
-
* have that day (e.g. Feb 31), the iteration is skipped.
|
|
132
|
-
*
|
|
133
|
-
* - **`inEveryWeek` + `inEveryMonth`**: for each of the next 12 months finds
|
|
134
|
-
* the first occurrence of the target weekday (from the start date), then
|
|
135
|
-
* iterates all occurrences of that weekday in the month with a 7-day step.
|
|
136
|
-
*
|
|
137
|
-
* `processDate(currentDate)` is called for every resolved date.
|
|
138
|
-
* @param {Date} date - The date for which to process intervals.
|
|
139
|
-
* @param {object} config - Configuration for schedule repetition.
|
|
140
|
-
* @param {boolean} config.inEveryWeek - Whether to repeat weekly.
|
|
141
|
-
* @param {boolean} config.inEveryMonth - Whether to repeat monthly.
|
|
142
|
-
* @param {(currentDate: Date) => void} processDate - Callback function to process each date.
|
|
143
|
-
*/
|
|
144
|
-
protected _processScheduleDates(date: Date, config: {
|
|
145
|
-
inEveryWeek: boolean;
|
|
146
|
-
inEveryMonth: boolean;
|
|
147
|
-
}, processDate: (currentDate: Date) => void): void;
|
|
148
|
-
/**
|
|
149
|
-
* Generates intervals for a specific date based on a schedule.
|
|
150
|
-
*
|
|
151
|
-
* For each date resolved by `_processScheduleDates`, iterates over
|
|
152
|
-
* the `schedule.times` array of time ranges. Each range is a pair
|
|
153
|
-
* `[startTime, endTime]` with `{ hours, minutes }` fields.
|
|
154
|
-
* Creates an ISO interval `[start.toISOString(), end.toISOString()]`
|
|
155
|
-
* and adds it to `utcIntervals` (Set deduplicates automatically).
|
|
156
|
-
* @param {Date} date - The date for which to generate intervals.
|
|
157
|
-
* @param {object} schedule - The schedule defining the intervals.
|
|
158
|
-
* @param {boolean} schedule.inEveryWeek - The number of weeks between intervals.
|
|
159
|
-
* @param {any[]} schedule.times - The times for each interval.
|
|
160
|
-
* @param {boolean} schedule.inEveryMonth - The month intervals for each interval.
|
|
161
|
-
* @param {Set<Array<string>>} utcIntervals - A set to store unique intervals.
|
|
162
|
-
*/
|
|
163
|
-
protected _generateIntervalsForDate(date: Date, schedule: {
|
|
164
|
-
inEveryWeek: boolean;
|
|
165
|
-
times: any[];
|
|
166
|
-
inEveryMonth: boolean;
|
|
167
|
-
}, utcIntervals: Set<Array<string>>): void;
|
|
168
|
-
/**
|
|
169
|
-
* Adds time intervals to schedules.
|
|
170
|
-
*
|
|
171
|
-
* Accepts an array of schedule groups (structure of `timeInterval` attributes
|
|
172
|
-
* for pages/products). For each group iterates over `values` — the set of
|
|
173
|
-
* concrete schedules. Each schedule contains a date range `dates[0..1]`.
|
|
174
|
-
*
|
|
175
|
-
* If both boundaries are equal (`isSameDay`), intervals are generated only
|
|
176
|
-
* for that single date. Otherwise — for every day in the range inclusive.
|
|
177
|
-
*
|
|
178
|
-
* The result (`schedule.timeIntervals`) is a sorted array of ISO pairs,
|
|
179
|
-
* ready to pass to UI components.
|
|
180
|
-
* @param {any[]} schedules - The schedules to process.
|
|
181
|
-
* @returns {any} Schedules with added time intervals.
|
|
182
|
-
*/
|
|
183
|
-
_addTimeIntervalsToSchedules(schedules: any[]): any;
|
|
184
|
-
/**
|
|
185
|
-
* Generates intervals for a specific date for form schedules.
|
|
186
|
-
*
|
|
187
|
-
* Unlike `_generateIntervalsForDate`, time ranges here have a different shape:
|
|
188
|
-
* each `timeInterval` contains `start`, `end` and `period`
|
|
189
|
-
* (slot length in minutes). The method slices the [start, end) window into
|
|
190
|
-
* fixed-length slots of `period` minutes:
|
|
191
|
-
*
|
|
192
|
-
* start=09:00, end=12:00, period=30 → [09:00–09:30], [09:30–10:00], …, [11:30–12:00]
|
|
193
|
-
*
|
|
194
|
-
* Generation stops if the next slot would exceed `end`.
|
|
195
|
-
* Each slot is added to `utcIntervals` (Set deduplicates automatically).
|
|
196
|
-
* @param {Date} date - The date for which to generate intervals.
|
|
197
|
-
* @param {object} interval - The interval configuration.
|
|
198
|
-
* @param {boolean} interval.inEveryWeek - Indicates whether the schedule is weekly.
|
|
199
|
-
* @param {boolean} interval.inEveryMonth - Indicates whether the schedule is monthly.
|
|
200
|
-
* @param {any[]} timeIntervals - The time intervals to process.
|
|
201
|
-
* @param {Set<Array<string>>} utcIntervals - A set to store unique intervals.
|
|
202
|
-
*/
|
|
203
|
-
protected _generateIntervalsForFormDate(date: Date, interval: {
|
|
204
|
-
inEveryWeek: boolean;
|
|
205
|
-
inEveryMonth: boolean;
|
|
206
|
-
}, timeIntervals: any[], utcIntervals: Set<Array<string>>): void;
|
|
207
|
-
/**
|
|
208
|
-
* Adds time intervals to form schedules (different structure).
|
|
209
|
-
*
|
|
210
|
-
* Same as `_addTimeIntervalsToSchedules` but for `timeInterval` attributes
|
|
211
|
-
* in **forms** (different API data structure):
|
|
212
|
-
* - `interval.range[0..1]` instead of `schedule.dates[0..1]`
|
|
213
|
-
* - `interval.intervals` — array of time ranges with slots (`period`)
|
|
214
|
-
* instead of `[startTime, endTime]` pairs
|
|
215
|
-
*
|
|
216
|
-
* Result is written to `interval.timeIntervals`.
|
|
217
|
-
* @param {any[]} intervals - The intervals to process.
|
|
218
|
-
* @returns {any} Intervals with added time intervals.
|
|
219
|
-
*/
|
|
220
|
-
_addTimeIntervalsToFormSchedules(intervals: any[]): any;
|
|
221
120
|
/**
|
|
222
121
|
* Transforms additionalFields from array to object keyed by marker.
|
|
223
122
|
*
|
|
@@ -234,36 +133,34 @@ export default abstract class SyncModules {
|
|
|
234
133
|
*
|
|
235
134
|
* Handles three different attribute formats returned by the API:
|
|
236
135
|
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* - `_normalizeAdditionalFields`
|
|
240
|
-
* -
|
|
241
|
-
*
|
|
242
|
-
* - the
|
|
136
|
+
* All three go through the same steps, so an attribute of a given type looks
|
|
137
|
+
* the same whichever collection it arrived in:
|
|
138
|
+
* - `_normalizeAdditionalFields` turns nested fields into a marker map;
|
|
139
|
+
* - `_normalizeAttrValue` unwraps single-file values, empties to `null` and
|
|
140
|
+
* casts numbers;
|
|
141
|
+
* - the collection is re-sorted by `position`.
|
|
142
|
+
*
|
|
143
|
+
* **1. `attributeValues`** — attributes of pages, products and other entities,
|
|
144
|
+
* an object `{ marker: AttrObject }`.
|
|
145
|
+
*
|
|
146
|
+
* **2. `attributes`** — form attributes, an array (or a marker map on some
|
|
147
|
+
* endpoints); form-only boolean flags (`isLogin`, `isSignUp`, notifications)
|
|
148
|
+
* are additionally coerced from `null` to `false`.
|
|
243
149
|
*
|
|
244
|
-
* **
|
|
245
|
-
*
|
|
246
|
-
*
|
|
150
|
+
* **3. `type`** — a standalone attribute: an attribute-set entry, a form-data
|
|
151
|
+
* field or a nested `additionalFields` entry. Same transformations, but there
|
|
152
|
+
* is no collection to sort.
|
|
247
153
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
154
|
+
* `timeInterval` attributes are left exactly as the API returned them — a
|
|
155
|
+
* compact recurrence rule. Resolving one into concrete slots is the caller's
|
|
156
|
+
* job, via `expandTimeIntervals`: the rule is open-ended, so only the caller
|
|
157
|
+
* knows how wide a window it needs.
|
|
250
158
|
*
|
|
251
159
|
* If none of the keys are found — data is returned unchanged.
|
|
252
160
|
* @param {any} data - The data to normalize.
|
|
253
161
|
* @returns {any} Normalized attributes.
|
|
254
162
|
*/
|
|
255
163
|
protected _normalizeAttr(data: any): any;
|
|
256
|
-
/**
|
|
257
|
-
* Processes data after fetching or receiving it.
|
|
258
|
-
*
|
|
259
|
-
* Final post-processing of the API response: first unwraps localized fields
|
|
260
|
-
* (`_normalizeData`), then fixes single-element image attributes
|
|
261
|
-
* (`_clearArray`). Called at the end of every fetch method.
|
|
262
|
-
* @param {any} data - The data to process.
|
|
263
|
-
* @param {any} [langCode] - The language code for processing.
|
|
264
|
-
* @returns {any} Processed data.
|
|
265
|
-
*/
|
|
266
|
-
protected _dataPostProcess(data: any, langCode?: string): any;
|
|
267
164
|
/**
|
|
268
165
|
* Sets the access token in the state.
|
|
269
166
|
* @param {string} accessToken - The access token to set.
|