oneentry 1.0.161 → 1.0.163
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 +18 -0
- package/changelog.md +80 -3
- package/dist/admins/adminsInterfaces.d.ts +2 -0
- package/dist/admins/adminsSchemas.d.ts +8 -22
- package/dist/admins/adminsSchemas.js +3 -9
- package/dist/attribute-sets/attributeSetsInterfaces.d.ts +8 -6
- package/dist/auth-provider/authProviderSchemas.d.ts +1 -0
- package/dist/auth-provider/authProvidersInterfaces.d.ts +4 -4
- package/dist/base/attributes.d.ts +105 -0
- package/dist/base/attributes.js +172 -0
- package/dist/base/utils.d.ts +95 -2
- package/dist/base/validation.d.ts +30 -0
- package/dist/base/validation.js +94 -1
- package/dist/blocks/blocksApi.d.ts +16 -8
- package/dist/blocks/blocksApi.js +24 -15
- package/dist/blocks/blocksInterfaces.d.ts +17 -9
- package/dist/blocks/blocksSchemas.d.ts +6 -6
- package/dist/blocks/blocksSchemas.js +2 -1
- package/dist/discounts/discountsInterfaces.d.ts +3 -1
- package/dist/forms-data/formsDataApi.d.ts +16 -6
- package/dist/forms-data/formsDataApi.js +14 -4
- package/dist/forms-data/formsDataInterfaces.d.ts +57 -20
- package/dist/index.d.ts +1 -0
- package/dist/index.js +9 -1
- package/dist/integration-collections/integrationCollectionsInterfaces.d.ts +6 -6
- package/dist/menus/menusInterfaces.d.ts +5 -1
- package/dist/menus/menusSchemas.js +4 -1
- package/dist/orders/ordersInterfaces.d.ts +3 -1
- package/dist/orders/ordersSchemas.d.ts +2 -0
- package/dist/orders/ordersSchemas.js +1 -0
- package/dist/pages/pagesApi.d.ts +1 -11
- package/dist/pages/pagesApi.js +0 -17
- package/dist/pages/pagesInterfaces.d.ts +3 -20
- package/dist/pages/pagesSchemas.d.ts +6 -10
- package/dist/pages/pagesSchemas.js +4 -9
- package/dist/product-statuses/productStatusesInterfaces.d.ts +2 -2
- package/dist/products/productsSchemas.d.ts +5 -5
- package/dist/products/productsSchemas.js +3 -2
- package/dist/templates/templatesInterfaces.d.ts +1 -1
- package/dist/templates/templatesSchemas.d.ts +3 -3
- package/dist/templates/templatesSchemas.js +2 -1
- package/dist/templates-preview/templatesPreviewInterfaces.d.ts +2 -2
- package/dist/users/usersInterfaces.d.ts +2 -0
- package/dist/users/usersSchemas.d.ts +1 -0
- package/esm/admins/adminsInterfaces.d.ts +2 -0
- package/esm/admins/adminsSchemas.d.ts +8 -22
- package/esm/admins/adminsSchemas.js +3 -9
- package/esm/attribute-sets/attributeSetsInterfaces.d.ts +8 -6
- package/esm/auth-provider/authProviderSchemas.d.ts +1 -0
- package/esm/auth-provider/authProvidersInterfaces.d.ts +4 -4
- package/esm/base/attributes.d.ts +105 -0
- package/esm/base/attributes.js +163 -0
- package/esm/base/utils.d.ts +95 -2
- package/esm/base/validation.d.ts +30 -0
- package/esm/base/validation.js +93 -0
- package/esm/blocks/blocksApi.d.ts +16 -8
- package/esm/blocks/blocksApi.js +24 -15
- package/esm/blocks/blocksInterfaces.d.ts +17 -9
- package/esm/blocks/blocksSchemas.d.ts +6 -6
- package/esm/blocks/blocksSchemas.js +2 -1
- package/esm/discounts/discountsInterfaces.d.ts +3 -1
- package/esm/forms-data/formsDataApi.d.ts +16 -6
- package/esm/forms-data/formsDataApi.js +14 -4
- package/esm/forms-data/formsDataInterfaces.d.ts +57 -20
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/integration-collections/integrationCollectionsInterfaces.d.ts +6 -6
- package/esm/menus/menusInterfaces.d.ts +5 -1
- package/esm/menus/menusSchemas.js +4 -1
- package/esm/orders/ordersInterfaces.d.ts +3 -1
- package/esm/orders/ordersSchemas.d.ts +2 -0
- package/esm/orders/ordersSchemas.js +1 -0
- package/esm/pages/pagesApi.d.ts +1 -11
- package/esm/pages/pagesApi.js +0 -17
- package/esm/pages/pagesInterfaces.d.ts +3 -20
- package/esm/pages/pagesSchemas.d.ts +6 -10
- package/esm/pages/pagesSchemas.js +3 -8
- package/esm/product-statuses/productStatusesInterfaces.d.ts +2 -2
- package/esm/products/productsSchemas.d.ts +5 -5
- package/esm/products/productsSchemas.js +3 -2
- package/esm/templates/templatesInterfaces.d.ts +1 -1
- package/esm/templates/templatesSchemas.d.ts +3 -3
- package/esm/templates/templatesSchemas.js +2 -1
- package/esm/templates-preview/templatesPreviewInterfaces.d.ts +2 -2
- package/esm/users/usersInterfaces.d.ts +2 -0
- package/esm/users/usersSchemas.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -202,6 +202,24 @@ Zod and the response schemas are loaded on demand, the first time a response act
|
|
|
202
202
|
|
|
203
203
|
Together that means a project calling a single SDK method loads about **43 kB minified (9.7 kB gzip)** instead of 536 kB, with Zod, the schemas and Socket.io landing in chunks that are never requested. The SDK is published as both CommonJS and ESM (`sideEffects: false`), so bundlers can tree-shake the rest.
|
|
204
204
|
|
|
205
|
+
### Attribute Values
|
|
206
|
+
|
|
207
|
+
`IAttributeValue.value` is typed `unknown` — its shape is decided by `type` at runtime. The trap is files: an `image`/`file` attribute holding **one** file has its value unwrapped to the file object itself, while several files and every `groupOfImages` stay an array. Reading the wrong shape is not a compile error, it is a silently missing image. Read files through the helpers instead:
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
import { defineOneEntry, getAttributeFile, getAttributeFiles } from 'oneentry'
|
|
211
|
+
|
|
212
|
+
const { Pages } = defineOneEntry('your-url', { token: 'your-app-token' })
|
|
213
|
+
const page = await Pages.getPageByUrl('catalog')
|
|
214
|
+
|
|
215
|
+
// Same call whether the attribute holds one file or a gallery.
|
|
216
|
+
const images = getAttributeFiles(page.attributeValues.gallery) // IAttributeFile[]
|
|
217
|
+
const cover = getAttributeFile(page.attributeValues.cover) // IAttributeFile | null
|
|
218
|
+
const blurDataURL = cover?.previewLink?.default?.[0]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Also exported: `getAdditionalFields(attr)` for an attribute's nested fields as a marker map, the type guards `isFileAttribute`, `isStringAttribute`, `isNumberAttribute`, `isListAttribute`, the file type `IAttributeFile`, and `ITypedAttributeValue` — `IAttributeValue` as a discriminated union over `type`, to annotate with where you want the compiler to enforce the shape.
|
|
222
|
+
|
|
205
223
|
### Time Intervals
|
|
206
224
|
|
|
207
225
|
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:
|
package/changelog.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# SDK Change Log
|
|
2
2
|
|
|
3
|
+
## v.1.0.163
|
|
4
|
+
|
|
5
|
+
### What's Fixed
|
|
6
|
+
|
|
7
|
+
- **FormData > `getFormsDataByMarker` — the filter body is typed.** It was `body?: object`, so nothing about it was checked or suggested. That is worse than merely inconvenient: the API **ignores** a field it does not recognize, so `statuses: ['approved']` (note the "s") returned every record — unmoderated ones included — while the code looked correct. The new `IFormsDataFilter` declares the fields the endpoint actually applies, each verified against a live project:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
await FormData.getFormsDataByMarker('review', 12, {
|
|
11
|
+
entityIdentifier: 'blog',
|
|
12
|
+
parentId: 10,
|
|
13
|
+
userIdentifier: '',
|
|
14
|
+
status: ['approved'],
|
|
15
|
+
dateFrom: '2025-01-01',
|
|
16
|
+
dateTo: '',
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Note `entityparentIdentifier` from the old JSDoc example is **not** among them: the API ignores it (filtering by it changes nothing), so it is not declared. Use `parentId` to fetch replies to a submission. Also exported: `FormDataStatus`.
|
|
21
|
+
|
|
22
|
+
- **FormData > the JSDoc example used a status that does not exist.** It showed `"status": ["new", "approved"]`; copied as-is it answers `400 each value in status must be a valid enum value`, without naming the valid ones. The set is `sent`, `moderation`, `approved`, `banned`, `deleted` — now spelled out next to `status` in the JSDoc, and enforced by `FormDataStatus`. `status` must also be an array; a bare string is a `400`.
|
|
23
|
+
|
|
24
|
+
- **FormData > the locale unwrapping of `formData` is now documented.** The API returns `formData: { "en_US": [ … ] }`, the SDK normalizes it and hands over the array for the requested `langCode`. Nothing said so, so code written against the raw API response — the one you see first, through curl or the panel — read `formData[langCode]`, got `undefined`, and rendered an empty list with no error anywhere. It is now stated in the method's JSDoc and on `formData` in `IFormByMarkerDataEntity` / `IFormDataEntity`. Behaviour is unchanged.
|
|
25
|
+
|
|
26
|
+
- **FormData > `IBodyTypeImageGroupOfImages.type` had a typo: `'groupOfImage'`**, a value the API rejects (`400 formData's marker '…' type must be one of […]`). Worse than a plain typo — the editor autocompleted it. It is now `'groupOfImages'`, matching the attribute type and the SDK's own upload branch, which has always checked for the plural.
|
|
27
|
+
|
|
28
|
+
- **FormData > `postFormsData` JSDoc now points at `IImageValue` / `IFileValue`** — the shape an attached file must take, which is *not* what `FileUploading.upload` returns (that one carries `contentType`, which form data rejects; the SDK strips it for you when it uploads the file itself). These interfaces were the only place that shape was written down, and nothing linked to them.
|
|
29
|
+
|
|
30
|
+
- **AttributesSets > `getSingleAttributeByMarkerSet` — the interface declared its arguments in the reverse order of the implementation.** `IAttributesSets` (and its JSDoc) said `(attributeMarker, setMarker, langCode)`, while `AttributesSetsApi` — and the request path `/{setMarker}/attributes/{attributeMarker}` — take `(setMarker, attributeMarker, langCode)`. Both parameters are `string`, so `implements` did not catch it and neither did any caller's compiler: a call written from the interface built `/icon/attributes/page_content` and the API answered `404 Attribute not found`, which reads like a missing attribute rather than a wrong call. The interface now matches the implementation; no runtime behaviour changed.
|
|
31
|
+
|
|
32
|
+
- **15 module interfaces declared `langCode` as required** while the implementing method defaults it — Blocks > `getBlockByMarker`, Discounts > `getDiscountByMarker`, IntegrationCollections > `getICollections` / `getICollectionById` / `getICollectionRowsById` / `getICollectionRowByMarkerAndId` / `createICollectionRow` / `updateICollectionRow`, Menus > `getMenusByMarker`, Orders > `getAllStatusesByStorageMarker`, ProductStatuses > `getProductStatuses` / `getProductsByStatusMarker`, Templates > `getTemplateByType`, TemplatePreviews > `getTemplatePreviews` / `getTemplatePreviewByMarker`. All are now optional, as the JSDoc already stated.
|
|
33
|
+
|
|
34
|
+
- **Two parameters were named differently in the interface than in the implementation**: AuthProvider > `signUp` / `auth` took `data` (now `body`), and FormData > `getFormsDataByMarker` took `isNested`, documented as "hierarchical data", while the method sends `isExtended` — a flag for additional fields. Names and docs now follow the implementation.
|
|
35
|
+
|
|
36
|
+
- **A test now guards this whole class of defect.** `src/base/tests/signatures.spec.ts` parses the sources with the TypeScript compiler API and compares every `*Api` class against the interface it `implements` — parameter names, order and optionality. The compiler cannot do this: it matches parameters positionally by type, so a swapped pair of `string`s is a valid implementation to it.
|
|
37
|
+
|
|
38
|
+
### What's New
|
|
39
|
+
|
|
40
|
+
- **Typed access to attribute values.** `IAttributeValue.value` is `unknown` — its shape is decided by `type` at runtime — and the rule for that shape lived only in a JSDoc comment, so breaking it cost nothing at compile time. The classic case: an `image` attribute holding **one** file has its `value` unwrapped to the file object itself, so a helper written as `Array.isArray(v) ? v[0] : undefined` returns `undefined` for every single-image attribute, builds cleanly, and shows an empty page. The SDK now ships the missing pieces:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { getAttributeFiles, getAttributeFile } from 'oneentry'
|
|
44
|
+
|
|
45
|
+
// Same call for one image and for a gallery — no branching on the shape.
|
|
46
|
+
const images = getAttributeFiles(page.attributeValues.cover)
|
|
47
|
+
const cover = getAttributeFile(product.attributeValues.img)
|
|
48
|
+
const blurDataURL = cover?.previewLink?.default?.[0]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- `getAttributeFiles(attr)` → `IAttributeFile[]` — every file of an `image`, `file` or `groupOfImages` attribute, collapsing the single-file and array shapes to one list; empty for anything else.
|
|
52
|
+
- `getAttributeFile(attr)` → `IAttributeFile | null` — the first file, for covers and previews.
|
|
53
|
+
- `getAdditionalFields(attr)` → `Record<string, IAttributeValue>` — nested fields as a marker map. `additionalFields` is typed `Record<string, IAttributeValue> | unknown[]` because the API returns an empty **array** when there are none, and that union makes every field read a type error; the helper collapses it (and converts the `rawData: true` array by `marker`).
|
|
54
|
+
- Type guards `isFileAttribute`, `isStringAttribute`, `isNumberAttribute`, `isListAttribute` — alongside the existing `isTimeIntervalAttribute`.
|
|
55
|
+
|
|
56
|
+
- **`IAttributeFile`** — the file object of an attribute value is now an exported type: `filename`, `downloadLink`, `size`, `contentType`, plus the optional `previewLink` (previews keyed by template, each a `[base64 placeholder, url]` pair — the placeholder is what a `blurDataURL` needs) and `defaultPreview`. It had to be re-declared by hand in every project until now.
|
|
57
|
+
|
|
58
|
+
- **Attribute values are now validated.** Every schema carrying `attributeValues` used `z.record(z.string(), z.any())` — the whole attribute payload passed validation unconditionally, so a change in the API's file shape reached consumers as an empty gallery, not as an error. The shared `AttributeValuesSchema` (`base/validation.ts`) replaces it in the admins, blocks, menus, pages, products and templates schemas. It stays open where the data is open — what `value` holds is defined by the project's own attribute set — and checks the one part the API fixes and the SDK's helpers depend on: the files of `image` / `file` / `groupOfImages` attributes, nested `additionalFields` included. A renamed or dropped `downloadLink` is reported as a validation issue naming the marker and index; unknown new fields on a file are accepted. Exported alongside it: `AttributeFileSchema`.
|
|
59
|
+
|
|
60
|
+
- **`ITypedAttributeValue`** — `IAttributeValue` as a discriminated union over `type` (`IFileAttributeValue`, `IStringAttributeValue`, `INumberAttributeValue`, `IListAttributeValue`, `ITimeIntervalAttributeValue`), so `switch (attr.type)` narrows `value` for you. The union is closed on purpose: a loose member (`type: string`) would match every case and collapse the narrowing back to `unknown`; types the SDK does not model (`entity`, `date`, custom ones) stay on `IAttributeValue`. Opt-in — `IAttributeValues` keeps the loose `IAttributeValue`, so nothing existing changes.
|
|
61
|
+
|
|
62
|
+
## v.1.0.162
|
|
63
|
+
|
|
64
|
+
### What's New
|
|
65
|
+
|
|
66
|
+
- `distance?: number` is now declared on the entities the vector search endpoints return — `IAdminEntity`, `IDiscountsEntity`, `IOrderByMarkerEntity`, `IPagesEntity`, `IUserEntity`, `IFormDataSearchEntity` — and validated by the matching Zod schemas, mirroring `IProductsEntity.distance`. The field is the cosine distance to the query and is returned **only** when the search body carries `debug: true`.
|
|
67
|
+
|
|
68
|
+
- AttributeSets > `IAttributeSchemaItem.multiselect?: boolean` — for `list` fields, whether several options from `listTitles` may be selected. The panel has always stored the flag; the API only now declares it. Note it is still absent from every attribute the test project returns, so the field is declared but not yet observed in real data.
|
|
69
|
+
|
|
70
|
+
- Menus > `IMenusPages` — `parentType?: 'page' | 'custom' | null` and `itemType?: 'page' | 'custom'` are now declared (and validated by `MenusPagesSchema`). Page ids and custom item ids overlap, so `parentId` alone addresses a parent ambiguously; `itemType` is the value an item's children must pass in `parentType`. Both are already returned by the API.
|
|
71
|
+
|
|
72
|
+
### What's Changed
|
|
73
|
+
|
|
74
|
+
- Blocks > the eight recommendation methods (`getCartComplement`, `getCartSimilar`, `getPersonalRecommendations`, `getRecentlyViewed`, `getRepeatPurchase`, `getTrending`, `getWishlistSimilar`, `getFrequentlyOrderedProducts`) accept a trailing optional `limit` — the query parameter the endpoints now support. It is not defaulted: when omitted, the block's own quantity setting keeps applying, so existing calls are unchanged.
|
|
75
|
+
|
|
76
|
+
- FormData > `IFormDataSearchEntity` — `formModuleId?: number` is added, and `userIdentifier` / `parentId` are widened to `string | null` / `number | null`. `formModuleId` is absent from the swagger schema but present in every record the endpoint returns; the two nullable fields are declared non-nullable there while the real data returns `null`.
|
|
77
|
+
|
|
78
|
+
### What's Deleted
|
|
79
|
+
|
|
80
|
+
- **Breaking** — Pages > `getConfigPageByUrl` is removed, along with the `IPageConfig` type and `PageConfigSchema`. The API dropped `GET /api/content/pages/{url}/config` (and its `ConfigPageDto`); the route now answers `404`. Page display settings are available through the `config` field of a page entity.
|
|
81
|
+
|
|
3
82
|
## v.1.0.161
|
|
4
83
|
|
|
5
84
|
### What's New
|
|
@@ -10,7 +89,7 @@
|
|
|
10
89
|
const { Search } = defineOneEntry('your-url', config)
|
|
11
90
|
|
|
12
91
|
const all = await Search.globalSearch('winter')
|
|
13
|
-
// drilldown: offset/limit
|
|
92
|
+
// drilldown: offset/limit require exactly one accessible type, else the API answers 400
|
|
14
93
|
const products = await Search.globalSearch('winter', ['products'], 'visible', 0, 20)
|
|
15
94
|
```
|
|
16
95
|
|
|
@@ -27,8 +106,6 @@
|
|
|
27
106
|
- Pages > `getPagesByVectorSearch` → `IPagesResponse`;
|
|
28
107
|
- Users > `getUsersByVectorSearch` → `IUsersResponse` (requires user authorization).
|
|
29
108
|
|
|
30
|
-
All six answer `500` on the test project at the time of release — the SDK side follows the documented contract, which is the same `ItemsWithTotal` container the working products endpoint returns.
|
|
31
|
-
|
|
32
109
|
- FormData > `IFormDataSearchEntity` — new exported type for the records returned by the form data vector search. It carries the moderation and sender fields of the raw record (`status`, `ip`, `fingerprint`, `isUserAdmin`, `userIdentifier`, `entityIdentifier`, `parentId`), which `IFormDataEntity` does not declare.
|
|
33
110
|
|
|
34
111
|
### What's Changed
|
|
@@ -109,6 +109,7 @@ interface IPosition {
|
|
|
109
109
|
}
|
|
110
110
|
]
|
|
111
111
|
* @property {IFormConfig[]} [moduleFormConfigs] - Array of module form configurations associated with the admin.
|
|
112
|
+
* @property {number} [distance] - Cosine distance to the query. Returned only by the semantic (vector) search endpoint when `debug: true` is passed in the search body. Example: 0.12.
|
|
112
113
|
* @description This interface captures the essential details and additional attributes of an admin entity.
|
|
113
114
|
*/
|
|
114
115
|
interface IAdminEntity {
|
|
@@ -120,6 +121,7 @@ interface IAdminEntity {
|
|
|
120
121
|
isSync: boolean;
|
|
121
122
|
attributeValues: IAttributeValues;
|
|
122
123
|
moduleFormConfigs?: IFormConfig[];
|
|
124
|
+
distance?: number;
|
|
123
125
|
}
|
|
124
126
|
/**
|
|
125
127
|
* Interface representing a query for fetching admin data.
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* @description Zod schemas for validating admins-related API responses
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
/**
|
|
7
|
+
* Admin entity schema
|
|
8
|
+
* Includes all fields returned by the API
|
|
9
|
+
*/
|
|
6
10
|
export declare const AdminEntitySchema: z.ZodObject<{
|
|
7
11
|
id: z.ZodNumber;
|
|
8
12
|
attributeSetId: z.ZodNullable<z.ZodNumber>;
|
|
@@ -10,18 +14,9 @@ export declare const AdminEntitySchema: z.ZodObject<{
|
|
|
10
14
|
attributeSetIdentifier: z.ZodNullable<z.ZodString>;
|
|
11
15
|
position: z.ZodNullable<z.ZodNumber>;
|
|
12
16
|
isSync: z.ZodBoolean;
|
|
13
|
-
attributeValues: z.ZodRecord<z.ZodString, z.
|
|
14
|
-
type: string;
|
|
15
|
-
value: unknown;
|
|
16
|
-
position?: number;
|
|
17
|
-
additionalFields?: Record<string, unknown> | unknown[];
|
|
18
|
-
}, unknown, z.core.$ZodTypeInternals<{
|
|
19
|
-
type: string;
|
|
20
|
-
value: unknown;
|
|
21
|
-
position?: number;
|
|
22
|
-
additionalFields?: Record<string, unknown> | unknown[];
|
|
23
|
-
}, unknown>>>>;
|
|
17
|
+
attributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
24
18
|
moduleFormConfigs: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
19
|
+
distance: z.ZodOptional<z.ZodNumber>;
|
|
25
20
|
}, z.core.$strip>;
|
|
26
21
|
/**
|
|
27
22
|
* Admins response schema (array of admin entities)
|
|
@@ -33,16 +28,7 @@ export declare const AdminsResponseSchema: z.ZodArray<z.ZodObject<{
|
|
|
33
28
|
attributeSetIdentifier: z.ZodNullable<z.ZodString>;
|
|
34
29
|
position: z.ZodNullable<z.ZodNumber>;
|
|
35
30
|
isSync: z.ZodBoolean;
|
|
36
|
-
attributeValues: z.ZodRecord<z.ZodString, z.
|
|
37
|
-
type: string;
|
|
38
|
-
value: unknown;
|
|
39
|
-
position?: number;
|
|
40
|
-
additionalFields?: Record<string, unknown> | unknown[];
|
|
41
|
-
}, unknown, z.core.$ZodTypeInternals<{
|
|
42
|
-
type: string;
|
|
43
|
-
value: unknown;
|
|
44
|
-
position?: number;
|
|
45
|
-
additionalFields?: Record<string, unknown> | unknown[];
|
|
46
|
-
}, unknown>>>>;
|
|
31
|
+
attributeValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
47
32
|
moduleFormConfigs: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
33
|
+
distance: z.ZodOptional<z.ZodNumber>;
|
|
48
34
|
}, z.core.$strip>>;
|
|
@@ -6,18 +6,11 @@ exports.AdminsResponseSchema = exports.AdminEntitySchema = void 0;
|
|
|
6
6
|
* @description Zod schemas for validating admins-related API responses
|
|
7
7
|
*/
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
|
+
const validation_1 = require("../base/validation");
|
|
9
10
|
/**
|
|
10
11
|
* Admin entity schema
|
|
11
12
|
* Includes all fields returned by the API
|
|
12
13
|
*/
|
|
13
|
-
const AttributeValueSchema = zod_1.z.object({
|
|
14
|
-
type: zod_1.z.string(),
|
|
15
|
-
value: zod_1.z.unknown(),
|
|
16
|
-
position: zod_1.z.number().optional(),
|
|
17
|
-
additionalFields: zod_1.z
|
|
18
|
-
.union([zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()), zod_1.z.array(zod_1.z.unknown())])
|
|
19
|
-
.optional(),
|
|
20
|
-
});
|
|
21
14
|
exports.AdminEntitySchema = zod_1.z.object({
|
|
22
15
|
id: zod_1.z.number(),
|
|
23
16
|
attributeSetId: zod_1.z.number().nullable(),
|
|
@@ -25,8 +18,9 @@ exports.AdminEntitySchema = zod_1.z.object({
|
|
|
25
18
|
attributeSetIdentifier: zod_1.z.string().nullable(),
|
|
26
19
|
position: zod_1.z.number().nullable(),
|
|
27
20
|
isSync: zod_1.z.boolean(),
|
|
28
|
-
attributeValues:
|
|
21
|
+
attributeValues: validation_1.AttributeValuesSchema,
|
|
29
22
|
moduleFormConfigs: zod_1.z.array(zod_1.z.any()).optional(),
|
|
23
|
+
distance: zod_1.z.number().optional(),
|
|
30
24
|
});
|
|
31
25
|
/**
|
|
32
26
|
* Admins response schema (array of admin entities)
|
|
@@ -14,18 +14,18 @@ interface IAttributesSets {
|
|
|
14
14
|
* @throws {IError} - If there is an error during the fetch operation, it will return an error object.
|
|
15
15
|
* @description This method fetches attributes by a specific marker.
|
|
16
16
|
*/
|
|
17
|
-
getAttributesByMarker(marker: string, langCode
|
|
17
|
+
getAttributesByMarker(marker: string, langCode?: string): Promise<IAttributesSetsEntity[] | IError>;
|
|
18
18
|
/**
|
|
19
|
-
* Fetches a single attribute by
|
|
19
|
+
* Fetches a single attribute by the set marker and the attribute marker.
|
|
20
20
|
* @handleName getSingleAttributeByMarkerSet
|
|
21
|
-
* @param {string}
|
|
22
|
-
* @param {string}
|
|
21
|
+
* @param {string} setMarker - The marker identifying the attribute set — the first path segment. Example: "productAttributes".
|
|
22
|
+
* @param {string} attributeMarker - The marker identifying the attribute inside that set. Example: "color".
|
|
23
23
|
* @param {string} [langCode] - The language code for localization purposes. Default: "en_US".
|
|
24
24
|
* @returns {IAttributesSetsEntity} A promise that resolves to an attribute set entity or an error.
|
|
25
25
|
* @throws {IError} - If there is an error during the fetch operation, it will return an error object.
|
|
26
|
-
* @description This method fetches a single attribute
|
|
26
|
+
* @description This method fetches a single attribute of an attribute set. The order matches the request path `/{setMarker}/attributes/{attributeMarker}`: the set comes first. Both parameters are strings, so swapping them type-checks and answers `404 Attribute not found`.
|
|
27
27
|
*/
|
|
28
|
-
getSingleAttributeByMarkerSet(
|
|
28
|
+
getSingleAttributeByMarkerSet(setMarker: string, attributeMarker: string, langCode?: string): Promise<IAttributesSetsEntity | IError>;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Represents the structure of a list item.
|
|
@@ -146,6 +146,7 @@ interface IAttributesSetsEntity {
|
|
|
146
146
|
* @property {number} [position] - Sort position of the field inside the set. Optional. Example: 1.
|
|
147
147
|
* @property {IListTitle[]} [listTitles] - Options for `list`/`radioButton`/`entity` fields (with extended data or linked-entity values). Optional.
|
|
148
148
|
* @property {string} [listType] - For `entity` fields — how the option list is organized. Optional. Example: "nested".
|
|
149
|
+
* @property {boolean} [multiselect] - For `list` fields — whether several options from `listTitles` may be selected. Optional. Example: false.
|
|
149
150
|
* @property {string} [moduleIdentifier] - For `entity` fields — identifier of the module the linked entities are taken from. Optional. Example: "catalog".
|
|
150
151
|
* @property {number | null} [parentId] - Identifier of the parent field, `null` for top-level. Optional, seen on `groupOfImages` fields.
|
|
151
152
|
* @property {Record<string, IAttributeSchemaItem>} [additionalFields] - Nested sub-fields keyed by marker. Optional.
|
|
@@ -171,6 +172,7 @@ interface IAttributeSchemaItem {
|
|
|
171
172
|
type: AttributeType;
|
|
172
173
|
position?: number;
|
|
173
174
|
listTitles?: IListTitle[];
|
|
175
|
+
multiselect?: boolean;
|
|
174
176
|
listType?: string;
|
|
175
177
|
moduleIdentifier?: string;
|
|
176
178
|
parentId?: number | null;
|
|
@@ -54,6 +54,7 @@ export declare const UserResponseSchema: z.ZodObject<{
|
|
|
54
54
|
state: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
55
55
|
moduleFormConfigs: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
56
56
|
rating: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
57
|
+
distance: z.ZodOptional<z.ZodNumber>;
|
|
57
58
|
}, z.core.$strip>;
|
|
58
59
|
/**
|
|
59
60
|
* Auth provider entity schema
|
|
@@ -8,7 +8,7 @@ interface IAuthProvider {
|
|
|
8
8
|
* Registers a new user.
|
|
9
9
|
* @handleName signUp
|
|
10
10
|
* @param {string} marker - The marker identifying the auth provider. Example: "email".
|
|
11
|
-
* @param {ISignUpData}
|
|
11
|
+
* @param {ISignUpData} body - The data required for user registration.
|
|
12
12
|
* @example
|
|
13
13
|
{
|
|
14
14
|
"formIdentifier": "reg",
|
|
@@ -40,7 +40,7 @@ interface IAuthProvider {
|
|
|
40
40
|
* @throws {IError} - If there is an error during the fetch operation, it will return an error object.
|
|
41
41
|
* @description This method registers a new user.
|
|
42
42
|
*/
|
|
43
|
-
signUp(marker: string,
|
|
43
|
+
signUp(marker: string, body: ISignUpData, langCode?: string): Promise<ISignUpEntity | IError>;
|
|
44
44
|
/**
|
|
45
45
|
* Generates an activation code for a user.
|
|
46
46
|
* @handleName generateCode
|
|
@@ -79,12 +79,12 @@ interface IAuthProvider {
|
|
|
79
79
|
* Authorizes a user.
|
|
80
80
|
* @handleName auth
|
|
81
81
|
* @param {string} marker - The marker identifying the auth provider. Example: "email".
|
|
82
|
-
* @param {IAuthPostBody}
|
|
82
|
+
* @param {IAuthPostBody} body - The data required for user authorization. Example: .
|
|
83
83
|
* @returns {IAuthEntity} A promise that resolves to an auth entity or an error.
|
|
84
84
|
* @throws {IError} - If there is an error during the fetch operation, it will return an error object.
|
|
85
85
|
* @description This method authorizes a user.
|
|
86
86
|
*/
|
|
87
|
-
auth(marker: string,
|
|
87
|
+
auth(marker: string, body: IAuthPostBody): Promise<IAuthEntity | IError>;
|
|
88
88
|
/**
|
|
89
89
|
* Refreshes a user's access token.
|
|
90
90
|
* @handleName refresh
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { IAttributeFile, IAttributeValue, IFileAttributeValue, IListAttributeValue, INumberAttributeValue, IStringAttributeValue } from './utils';
|
|
2
|
+
/**
|
|
3
|
+
* Narrows an attribute value to a file-bearing attribute.
|
|
4
|
+
*
|
|
5
|
+
* `IAttributeValue.value` is `unknown` — its shape depends on `type` — so this
|
|
6
|
+
* guard is what lets you reach the files without a cast. It accepts both shapes
|
|
7
|
+
* the SDK produces: a single file object for an `image`/`file` attribute holding
|
|
8
|
+
* exactly one file, an array for several and for every `groupOfImages`.
|
|
9
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
10
|
+
* @returns {boolean} True when the attribute is an `image`, `file` or `groupOfImages` carrying files (or nothing).
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const attr = page.attributeValues.cover;
|
|
14
|
+
* if (isFileAttribute(attr)) {
|
|
15
|
+
* // attr.value is IAttributeFile | IAttributeFile[] | null — no cast
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function isFileAttribute(attr: IAttributeValue | undefined): attr is IFileAttributeValue;
|
|
20
|
+
/**
|
|
21
|
+
* Reads every file of an attribute as an array.
|
|
22
|
+
*
|
|
23
|
+
* The one-call path for the common case. An `image`/`file` attribute holding a
|
|
24
|
+
* single file has it unwrapped to the object itself, while several files and
|
|
25
|
+
* every `groupOfImages` stay an array — a rule that is easy to get wrong in a
|
|
26
|
+
* way the compiler cannot catch, since `value` is `unknown`: reading `value[0]`
|
|
27
|
+
* off a single file yields `undefined` and nothing anywhere reports an error.
|
|
28
|
+
* This helper collapses both shapes to a list.
|
|
29
|
+
*
|
|
30
|
+
* Anything that is not a file-bearing attribute yields an empty array, so it is
|
|
31
|
+
* safe to call on an arbitrary attribute without checking `type` first.
|
|
32
|
+
* @param {IAttributeValue | undefined} attr - An attribute value, e.g. `page.attributeValues.cover`.
|
|
33
|
+
* @returns {IAttributeFile[]} The files, in the order the API returned them; empty when the attribute holds none or is not file-bearing.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { getAttributeFiles } from 'oneentry';
|
|
37
|
+
*
|
|
38
|
+
* // Works the same for one image and for a gallery.
|
|
39
|
+
* const images = getAttributeFiles(page.attributeValues.cover);
|
|
40
|
+
* images.map((file) => file.downloadLink);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function getAttributeFiles(attr: IAttributeValue | undefined): IAttributeFile[];
|
|
44
|
+
/**
|
|
45
|
+
* Reads the first file of an attribute.
|
|
46
|
+
*
|
|
47
|
+
* The single-image counterpart of {@link getAttributeFiles} — same shape
|
|
48
|
+
* handling, but returns the file itself instead of a list. For a gallery it
|
|
49
|
+
* returns the first entry, which is what a preview or a cover usually needs.
|
|
50
|
+
* @param {IAttributeValue | undefined} attr - An attribute value, e.g. `product.attributeValues.img`.
|
|
51
|
+
* @returns {IAttributeFile | null} The first file, or null when the attribute holds none.
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { getAttributeFile } from 'oneentry';
|
|
55
|
+
*
|
|
56
|
+
* const cover = getAttributeFile(product.attributeValues.img);
|
|
57
|
+
* const blurDataURL = cover?.previewLink?.default?.[0];
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function getAttributeFile(attr: IAttributeValue | undefined): IAttributeFile | null;
|
|
61
|
+
/**
|
|
62
|
+
* Narrows an attribute value to a text attribute.
|
|
63
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
64
|
+
* @returns {boolean} True when the attribute is a `string`, `text` or `textEditor` carrying a string (or nothing).
|
|
65
|
+
*/
|
|
66
|
+
export declare function isStringAttribute(attr: IAttributeValue | undefined): attr is IStringAttributeValue;
|
|
67
|
+
/**
|
|
68
|
+
* Narrows an attribute value to a numeric attribute.
|
|
69
|
+
*
|
|
70
|
+
* The SDK casts `integer`, `float` and `real` values to a JS number, so the
|
|
71
|
+
* guard checks for one — a value that failed to cast is `null`.
|
|
72
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
73
|
+
* @returns {boolean} True when the attribute is an `integer`, `float` or `real` carrying a number (or nothing).
|
|
74
|
+
*/
|
|
75
|
+
export declare function isNumberAttribute(attr: IAttributeValue | undefined): attr is INumberAttributeValue;
|
|
76
|
+
/**
|
|
77
|
+
* Narrows an attribute value to a `list` attribute.
|
|
78
|
+
*
|
|
79
|
+
* The option shape is defined by the attribute set, so the entries stay
|
|
80
|
+
* `unknown` — the guard only promises the array container.
|
|
81
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
82
|
+
* @returns {boolean} True when the attribute is a `list` carrying an array.
|
|
83
|
+
*/
|
|
84
|
+
export declare function isListAttribute(attr: IAttributeValue | undefined): attr is IListAttributeValue;
|
|
85
|
+
/**
|
|
86
|
+
* Reads the nested fields of an attribute as a marker map.
|
|
87
|
+
*
|
|
88
|
+
* `additionalFields` is typed `Record<string, IAttributeValue> | unknown[]`
|
|
89
|
+
* because the API returns an empty **array** when an attribute has no nested
|
|
90
|
+
* fields — the union makes every read of a field a type error. This helper
|
|
91
|
+
* collapses that case to an empty map, so the result is always keyed by marker.
|
|
92
|
+
*
|
|
93
|
+
* With `rawData: true` in the config the SDK keeps the API's original array of
|
|
94
|
+
* fields; it is converted here by `marker` as well, so the helper returns the
|
|
95
|
+
* same map in both modes.
|
|
96
|
+
* @param {IAttributeValue | undefined} attr - An attribute value whose nested fields to read.
|
|
97
|
+
* @returns {Record<string, IAttributeValue>} Nested attribute values keyed by marker; empty when there are none.
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { getAdditionalFields } from 'oneentry';
|
|
101
|
+
*
|
|
102
|
+
* const alt = getAdditionalFields(page.attributeValues.cover).alt?.value;
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function getAdditionalFields(attr: IAttributeValue | undefined): Record<string, IAttributeValue>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isFileAttribute = isFileAttribute;
|
|
4
|
+
exports.getAttributeFiles = getAttributeFiles;
|
|
5
|
+
exports.getAttributeFile = getAttributeFile;
|
|
6
|
+
exports.isStringAttribute = isStringAttribute;
|
|
7
|
+
exports.isNumberAttribute = isNumberAttribute;
|
|
8
|
+
exports.isListAttribute = isListAttribute;
|
|
9
|
+
exports.getAdditionalFields = getAdditionalFields;
|
|
10
|
+
const _FILE_TYPES = ['image', 'file', 'groupOfImages'];
|
|
11
|
+
/**
|
|
12
|
+
* Tests whether a value looks like a file object of an attribute.
|
|
13
|
+
*
|
|
14
|
+
* A file is identified by `downloadLink`: it is the one field every file of
|
|
15
|
+
* every attribute carries, while previews are only generated for images.
|
|
16
|
+
* @param {unknown} value - The value to test.
|
|
17
|
+
* @returns {boolean} True when the value is a file object.
|
|
18
|
+
*/
|
|
19
|
+
function _isFile(value) {
|
|
20
|
+
return (!!value &&
|
|
21
|
+
typeof value === 'object' &&
|
|
22
|
+
typeof value.downloadLink === 'string');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Narrows an attribute value to a file-bearing attribute.
|
|
26
|
+
*
|
|
27
|
+
* `IAttributeValue.value` is `unknown` — its shape depends on `type` — so this
|
|
28
|
+
* guard is what lets you reach the files without a cast. It accepts both shapes
|
|
29
|
+
* the SDK produces: a single file object for an `image`/`file` attribute holding
|
|
30
|
+
* exactly one file, an array for several and for every `groupOfImages`.
|
|
31
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
32
|
+
* @returns {boolean} True when the attribute is an `image`, `file` or `groupOfImages` carrying files (or nothing).
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const attr = page.attributeValues.cover;
|
|
36
|
+
* if (isFileAttribute(attr)) {
|
|
37
|
+
* // attr.value is IAttributeFile | IAttributeFile[] | null — no cast
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function isFileAttribute(attr) {
|
|
42
|
+
if (!attr || !_FILE_TYPES.includes(attr.type))
|
|
43
|
+
return false;
|
|
44
|
+
if (attr.value === null || attr.value === undefined)
|
|
45
|
+
return true;
|
|
46
|
+
return Array.isArray(attr.value)
|
|
47
|
+
? attr.value.every((item) => _isFile(item))
|
|
48
|
+
: _isFile(attr.value);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reads every file of an attribute as an array.
|
|
52
|
+
*
|
|
53
|
+
* The one-call path for the common case. An `image`/`file` attribute holding a
|
|
54
|
+
* single file has it unwrapped to the object itself, while several files and
|
|
55
|
+
* every `groupOfImages` stay an array — a rule that is easy to get wrong in a
|
|
56
|
+
* way the compiler cannot catch, since `value` is `unknown`: reading `value[0]`
|
|
57
|
+
* off a single file yields `undefined` and nothing anywhere reports an error.
|
|
58
|
+
* This helper collapses both shapes to a list.
|
|
59
|
+
*
|
|
60
|
+
* Anything that is not a file-bearing attribute yields an empty array, so it is
|
|
61
|
+
* safe to call on an arbitrary attribute without checking `type` first.
|
|
62
|
+
* @param {IAttributeValue | undefined} attr - An attribute value, e.g. `page.attributeValues.cover`.
|
|
63
|
+
* @returns {IAttributeFile[]} The files, in the order the API returned them; empty when the attribute holds none or is not file-bearing.
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { getAttributeFiles } from 'oneentry';
|
|
67
|
+
*
|
|
68
|
+
* // Works the same for one image and for a gallery.
|
|
69
|
+
* const images = getAttributeFiles(page.attributeValues.cover);
|
|
70
|
+
* images.map((file) => file.downloadLink);
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
function getAttributeFiles(attr) {
|
|
74
|
+
if (!attr)
|
|
75
|
+
return [];
|
|
76
|
+
const value = attr.value;
|
|
77
|
+
if (Array.isArray(value))
|
|
78
|
+
return value.filter((item) => _isFile(item));
|
|
79
|
+
return _isFile(value) ? [value] : [];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Reads the first file of an attribute.
|
|
83
|
+
*
|
|
84
|
+
* The single-image counterpart of {@link getAttributeFiles} — same shape
|
|
85
|
+
* handling, but returns the file itself instead of a list. For a gallery it
|
|
86
|
+
* returns the first entry, which is what a preview or a cover usually needs.
|
|
87
|
+
* @param {IAttributeValue | undefined} attr - An attribute value, e.g. `product.attributeValues.img`.
|
|
88
|
+
* @returns {IAttributeFile | null} The first file, or null when the attribute holds none.
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* import { getAttributeFile } from 'oneentry';
|
|
92
|
+
*
|
|
93
|
+
* const cover = getAttributeFile(product.attributeValues.img);
|
|
94
|
+
* const blurDataURL = cover?.previewLink?.default?.[0];
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
function getAttributeFile(attr) {
|
|
98
|
+
var _a;
|
|
99
|
+
return (_a = getAttributeFiles(attr)[0]) !== null && _a !== void 0 ? _a : null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Narrows an attribute value to a text attribute.
|
|
103
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
104
|
+
* @returns {boolean} True when the attribute is a `string`, `text` or `textEditor` carrying a string (or nothing).
|
|
105
|
+
*/
|
|
106
|
+
function isStringAttribute(attr) {
|
|
107
|
+
return (!!attr &&
|
|
108
|
+
(attr.type === 'string' ||
|
|
109
|
+
attr.type === 'text' ||
|
|
110
|
+
attr.type === 'textEditor') &&
|
|
111
|
+
(attr.value === null || typeof attr.value === 'string'));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Narrows an attribute value to a numeric attribute.
|
|
115
|
+
*
|
|
116
|
+
* The SDK casts `integer`, `float` and `real` values to a JS number, so the
|
|
117
|
+
* guard checks for one — a value that failed to cast is `null`.
|
|
118
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
119
|
+
* @returns {boolean} True when the attribute is an `integer`, `float` or `real` carrying a number (or nothing).
|
|
120
|
+
*/
|
|
121
|
+
function isNumberAttribute(attr) {
|
|
122
|
+
return (!!attr &&
|
|
123
|
+
(attr.type === 'integer' ||
|
|
124
|
+
attr.type === 'float' ||
|
|
125
|
+
attr.type === 'real') &&
|
|
126
|
+
(attr.value === null || typeof attr.value === 'number'));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Narrows an attribute value to a `list` attribute.
|
|
130
|
+
*
|
|
131
|
+
* The option shape is defined by the attribute set, so the entries stay
|
|
132
|
+
* `unknown` — the guard only promises the array container.
|
|
133
|
+
* @param {IAttributeValue | undefined} attr - The attribute value to test.
|
|
134
|
+
* @returns {boolean} True when the attribute is a `list` carrying an array.
|
|
135
|
+
*/
|
|
136
|
+
function isListAttribute(attr) {
|
|
137
|
+
return !!attr && attr.type === 'list' && Array.isArray(attr.value);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Reads the nested fields of an attribute as a marker map.
|
|
141
|
+
*
|
|
142
|
+
* `additionalFields` is typed `Record<string, IAttributeValue> | unknown[]`
|
|
143
|
+
* because the API returns an empty **array** when an attribute has no nested
|
|
144
|
+
* fields — the union makes every read of a field a type error. This helper
|
|
145
|
+
* collapses that case to an empty map, so the result is always keyed by marker.
|
|
146
|
+
*
|
|
147
|
+
* With `rawData: true` in the config the SDK keeps the API's original array of
|
|
148
|
+
* fields; it is converted here by `marker` as well, so the helper returns the
|
|
149
|
+
* same map in both modes.
|
|
150
|
+
* @param {IAttributeValue | undefined} attr - An attribute value whose nested fields to read.
|
|
151
|
+
* @returns {Record<string, IAttributeValue>} Nested attribute values keyed by marker; empty when there are none.
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* import { getAdditionalFields } from 'oneentry';
|
|
155
|
+
*
|
|
156
|
+
* const alt = getAdditionalFields(page.attributeValues.cover).alt?.value;
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
function getAdditionalFields(attr) {
|
|
160
|
+
const fields = attr === null || attr === void 0 ? void 0 : attr.additionalFields;
|
|
161
|
+
if (!fields || typeof fields !== 'object')
|
|
162
|
+
return {};
|
|
163
|
+
if (Array.isArray(fields)) {
|
|
164
|
+
// rawData mode: the API's own array of fields, each carrying its marker.
|
|
165
|
+
return Object.fromEntries(fields
|
|
166
|
+
.filter((field) => !!field &&
|
|
167
|
+
typeof field === 'object' &&
|
|
168
|
+
typeof field.marker === 'string')
|
|
169
|
+
.map((field) => [field.marker, field]));
|
|
170
|
+
}
|
|
171
|
+
return fields;
|
|
172
|
+
}
|