oneentry 1.0.169 → 1.0.171

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/changelog.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # SDK Change Log
2
2
 
3
+ ## v.1.0.171
4
+
5
+ ### What's Fixed
6
+
7
+ - **`postFormsData` threw `fd.value.map is not a function` on the value its own uploader returns.** For a `file`, `image` or `groupOfImages` field the method converted the value — an array was uploaded file by file, a lone `File`/`Blob` into a single object — and then called `fd.value.map(...)` **unconditionally**, to strip `contentType`. A value the package had not converted reached `.map` as a non-array and the call died inside the library, before any request was made. That value is not an exotic one: it is exactly what `FileUploading.upload` returns, the natural thing to pass when the file is already in storage. The other plausible reading — an array of those descriptors — was re-uploaded as if the descriptors were files, and the platform refused the result with `formData's marker 'resume' value[0].filename is required`, naming the field the SDK itself had replaced. It cost a shipped pilot its application form: every visitor who attached a document got a generic refusal while the submission counter stayed at 0, and the only trace was the `TypeError` in the site log. Now only a `File` or a `Blob` is uploaded, an entry already in storage is passed through untouched — the two may be mixed in one array — and `contentType` is stripped from an array of values and from a lone value object alike. A value of any other shape is sent as it came, so the endpoint names the field it cannot read instead of the library throwing (CMS-990).
8
+
9
+ - **The accepted shapes of a file value were not declared.** `IBodyTypeFile.value` and `IBodyTypeImageGroupOfImages.value` described a hand-built `IFileValue` / `IImageValue` only — neither a raw `File`/`Blob`, which the SDK has always uploaded on the caller's behalf, nor the descriptor the uploader returns for a file already in storage. Both are in the types now, mixable in one array, and the JSDoc states what the endpoint does with them: a submission wants an **array**, so a lone descriptor or `IFileValue` answers `400 formData's marker '<marker>' value must be an array` while a lone `File`/`Blob` works because the upload result is already one. `fileQuery` is also declared where the SDK actually reads it — on the field; `IBodyPostFormData.fileQuery` is kept for compatibility, but setting it there changes nothing. Measured on js-sdk-tests.oneentry.cloud, 2026-10-08.
10
+
11
+ ### Tests
12
+
13
+ - **`formsdata` pins the file already in storage.** The new case uploads a probe with `FileUploading.upload`, submits the descriptor it returns as a one-element array — which used to be re-uploaded and refused — and then submits the same descriptor alone, which must come back as the endpoint's own `400 … value must be an array`, not as a `TypeError` from inside the package.
14
+
15
+ ## v.1.0.170
16
+
17
+ ### What's Changed
18
+
19
+ - **`IAttributeValidators` named four validators of the eighteen the platform accepts.** The interface gave a shape to `requiredValidator`, `stringInspectionValidator`, `emailInspectionValidator` and `defaultValueValidator`, and closed with `[key: string]: unknown`; its JSDoc said only that the set is extensible. A developer reading the types learned that a required flag, a length constraint, an e-mail toggle and a default value exist, and did not learn that a **regular expression**, an **input mask**, a **whitespace trim** and **date bounds** exist — fourteen capabilities absent from the model of the platform, which on one pilot reached three client-facing documents as the sentence "a field has exactly four validators; there are no regular expressions and no phone check". All eighteen names are now declared with the shape the platform stores: `requiredValidator`, `trimValidator`, `stringInspectionValidator`, `urlInspectionValidator`, `emailInspectionValidator`, `checkForNumberValidator`, `roundingNumberValidator`, `booleanValidator`, `comparisonValidator`, `regExpValidator`, `fieldMaskValidator`, `checkForAGivenList`, `defaultValueValidator`, `sizeInPixelsValidator`, `checkingFilesValidator`, `minMaxDateValidator`, `valueValidator`, `checkForLettersValidator` (CMS-983).
20
+
21
+ - **A misspelt validator name is a compile error instead of a `400`.** The index signature `[key: string]: unknown` made the gap silent in the other direction too: `emailValidator` typechecked and the platform refused the write at run time with `schema contains unknown validator name(s)`. The signature is gone, so an unknown name is caught where it is written. Code that still needs a name the SDK does not know can cast at that one place.
22
+
23
+ - **Shapes follow what the platform executes, not what reads well.** `regExpValidator` takes `{ patternValue, invert, flags }` and not `{ regExp }`, `fieldMaskValidator` takes `{ maskValue }`, `checkForAGivenList` carries no `Validator` suffix, and `minMaxDateValidator` stores `minDateTimeValue` / `maxDateTimeValue`. The toggles — `requiredValidator`, `trimValidator`, `urlInspectionValidator`, `emailInspectionValidator` — are typed `object | boolean`, because both forms are in live data: an e-mail check is stored as the boolean `true` on seven fields of the stands checked and as an object on one. Every validator may also carry `customErrorText`, which is now in the type. `valueValidator` is kept with the same shape as `defaultValueValidator`: it is the panel's own name for that control, and the API stores it.
24
+
25
+ - **The attribute JSDoc in `base/utils.ts` named `regexValidator`,** which does not exist. It points at `IAttributeValidators` for the full list instead.
26
+
27
+ Types and documentation only; the wire format did not change.
28
+
3
29
  ## v.1.0.169
4
30
 
5
31
  ### What's Fixed
@@ -189,28 +189,130 @@ interface IAttributeSchemaItem {
189
189
  }
190
190
  /**
191
191
  * @interface IAttributeValidators
192
- * @property {object} [requiredValidator] - Marks the field as required. Shape: `{ strict: boolean }`. Example: `{ strict: true }`.
193
- * @property {object} [stringInspectionValidator] - Length constraints for string fields. Shape: `{ stringMin: number; stringMax: number; stringLength: number }`.
194
- * @property {boolean} [emailInspectionValidator] - Toggle for email-format validation.
195
- * @property {object} [defaultValueValidator] - Default value configuration with optional custom error text. Shape: `{ customErrorText?: string; fieldDefaultValue?: unknown; fieldDefaultValue2?: unknown }`.
196
- * @description Map of validators applied to an attribute or form field. Set is extensible — additional validator types may be added by the API.
192
+ * @property {object | boolean} [requiredValidator] - Field must be filled in. Shape: `{ strict: boolean }`. Example: `{ strict: true }`.
193
+ * @property {object | boolean} [trimValidator] - Leading and trailing whitespace is stripped from the value. Stored as an empty object when the toggle is on. Example: `{}`.
194
+ * @property {object} [stringInspectionValidator] - Length constraints for string fields. Example: `{ stringLength: 0, stringMin: 2, stringMax: 60 }`.
195
+ * @property {object | boolean} [urlInspectionValidator] - Value must look like a URL. Stored either as `true` or as an object. Example: `true`.
196
+ * @property {object | boolean} [emailInspectionValidator] - Value must look like an e-mail address. Stored either as `true` or as an object. Example: `true`.
197
+ * @property {object} [checkForNumberValidator] - Value must be a number, optionally an integer within bounds. `0` disables a bound. Example: `{ integerOnly: true, minValue: 1, maxValue: 10 }`.
198
+ * @property {object} [roundingNumberValidator] - Rounds the number before storing it. Example: `{ integerOnly: false, numberOfDecimals: 2, direction: 'round' }`.
199
+ * @property {object} [booleanValidator] - Value must equal one of the two declared values. Example: `{ trueValue: 1, falseValue: 0 }`.
200
+ * @property {object} [comparisonValidator] - Compares the value with another attribute or with a constant. Example: `{ compareAttribute: 'notChoosed', compareValue: '10', type: 'number', operator: 'equality' }`.
201
+ * @property {object} [regExpValidator] - Value must match a regular expression; `invert` refuses matches instead. Example: `{ patternValue: '^[0-9]{5}$', invert: false, flags: ['i'] }`.
202
+ * @property {object} [fieldMaskValidator] - Value must match an input mask (`9` digit, `A` upper letter, `a` lower letter, `*` any, `$` one of `()+-`). Example: `{ maskValue: '+9 (999) 999-99-99' }`.
203
+ * @property {object} [checkForAGivenList] - Value must be in the list, or outside it when `notValue` is true. Example: `{ rangeValue: ['red', 'green'], notValue: false }`.
204
+ * @property {object} [defaultValueValidator] - Value substituted when the field is left empty. Example: `{ fieldDefaultValue: 'USD' }`.
205
+ * @property {object} [sizeInPixelsValidator] - Image bounds in pixels; executed by the admin panel. Example: `{ maxX: 1920, maxY: 1080 }`.
206
+ * @property {object} [checkingFilesValidator] - File size bounds and allowed extensions; executed by the admin panel. Example: `{ minValue: 0, maxValue: 5, minUnits: 'kb', maxUnits: 'mb', extensions: ['pdf'] }`.
207
+ * @property {object} [minMaxDateValidator] - Date bounds; executed by the admin panel. Example: `{ minDateTimeValue: '2026-01-01', maxDateTimeValue: '2026-12-31' }`.
208
+ * @property {object} [valueValidator] - The panel's "default value" control; it writes `defaultValueValidator`, and this name is kept because the API accepts and stores it. Example: `{ fieldDefaultValue: 'USD' }`.
209
+ * @property {object} [checkForLettersValidator] - Letters-only check by pattern; executed by the admin panel. Example: `{ patternValue: '^[A-Za-z ]+$' }`.
210
+ * @description Map of validators applied to an attribute or form field, keyed by validator name.
211
+ *
212
+ * These eighteen names are the full set the API accepts in
213
+ * `attributes_sets.schema.<attribute>.validators.<langCode>`; any other name is refused
214
+ * with `400`. The first thirteen are executed by the platform on write, the last five are
215
+ * stored as given and executed by the admin panel.
216
+ *
217
+ * Every validator may also carry `customErrorText` — the message shown instead of the
218
+ * default one when the value is refused.
197
219
  */
198
220
  interface IAttributeValidators {
199
221
  requiredValidator?: {
200
- strict: boolean;
201
- };
222
+ strict?: boolean;
223
+ customErrorText?: string;
224
+ } | boolean;
225
+ trimValidator?: {
226
+ strict?: boolean;
227
+ customErrorText?: string;
228
+ } | boolean;
202
229
  stringInspectionValidator?: {
203
- stringMin: number;
204
- stringMax: number;
205
- stringLength: number;
230
+ stringMin?: number;
231
+ stringMax?: number;
232
+ stringLength?: number;
233
+ customErrorText?: string;
234
+ };
235
+ urlInspectionValidator?: {
236
+ strict?: boolean;
237
+ customErrorText?: string;
238
+ } | boolean;
239
+ emailInspectionValidator?: {
240
+ strict?: boolean;
241
+ customErrorText?: string;
242
+ } | boolean;
243
+ checkForNumberValidator?: {
244
+ integerOnly?: boolean;
245
+ minValue?: number;
246
+ maxValue?: number;
247
+ customErrorText?: string;
248
+ };
249
+ roundingNumberValidator?: {
250
+ integerOnly?: boolean;
251
+ numberOfDecimals?: number;
252
+ direction?: 'round' | 'up' | 'down' | 'truncate';
253
+ customErrorText?: string;
254
+ };
255
+ booleanValidator?: {
256
+ trueValue?: unknown;
257
+ falseValue?: unknown;
258
+ customErrorText?: string;
259
+ };
260
+ comparisonValidator?: {
261
+ compareAttribute?: string;
262
+ compareValue?: string;
263
+ compareValue2?: string;
264
+ type?: string;
265
+ operator?: string;
266
+ customErrorText?: string;
267
+ };
268
+ regExpValidator?: {
269
+ patternValue?: string;
270
+ invert?: boolean;
271
+ flags?: string[];
272
+ customErrorText?: string;
273
+ };
274
+ fieldMaskValidator?: {
275
+ maskValue?: string;
276
+ customErrorText?: string;
277
+ };
278
+ checkForAGivenList?: {
279
+ rangeValue?: unknown[];
280
+ rangeValue2?: unknown[];
281
+ notValue?: boolean;
282
+ customErrorText?: string;
206
283
  };
207
- emailInspectionValidator?: boolean;
208
284
  defaultValueValidator?: {
285
+ fieldDefaultValue?: unknown;
286
+ fieldDefaultValue2?: unknown;
287
+ customErrorText?: string;
288
+ };
289
+ sizeInPixelsValidator?: {
290
+ maxX?: number;
291
+ maxY?: number;
209
292
  customErrorText?: string;
293
+ };
294
+ checkingFilesValidator?: {
295
+ minValue?: number;
296
+ maxValue?: number;
297
+ minUnits?: 'kb' | 'mb';
298
+ maxUnits?: 'kb' | 'mb';
299
+ extensions?: string[];
300
+ customErrorText?: string;
301
+ };
302
+ minMaxDateValidator?: {
303
+ minDateTimeValue?: string;
304
+ maxDateTimeValue?: string;
305
+ customErrorText?: string;
306
+ };
307
+ valueValidator?: {
210
308
  fieldDefaultValue?: unknown;
211
309
  fieldDefaultValue2?: unknown;
310
+ customErrorText?: string;
311
+ };
312
+ checkForLettersValidator?: {
313
+ patternValue?: string;
314
+ customErrorText?: string;
212
315
  };
213
- [key: string]: unknown;
214
316
  }
215
317
  /**
216
318
  * Represents an attribute set entity.
@@ -96,7 +96,7 @@ interface IConfig {
96
96
  * @property {boolean} isVisible - Whether the attribute is exposed in the public API/UI. Example: true.
97
97
  * @property {string} type - Attribute data type (e.g. "string", "integer", "list", "file", "image").
98
98
  * @property {Record<string, unknown>} [settings] - Type-specific configuration (e.g. min/max for numbers, accepted MIME types for files). Optional.
99
- * @property {Record<string, unknown>} validators - Validation rules applied to the attribute value (e.g. `requiredValidator`, `regexValidator`). Example: { "requiredValidator": { "strict": true } }.
99
+ * @property {Record<string, unknown>} validators - Validation rules applied to the attribute value, keyed by validator name (e.g. `requiredValidator`, `regExpValidator`); the full set of names is listed on `IAttributeValidators`. Example: { "requiredValidator": { "strict": true } }.
100
100
  * @property {Record<string, IAttributes>} [additionalFields] - Nested sub-attributes attached to this attribute, keyed by marker. Optional.
101
101
  * @property {boolean} [isIcon] - Block/preview attribute flag — whether the field is treated as an icon. Optional.
102
102
  * @property {boolean} [isProductPreview] - Block/preview attribute flag — whether the field is shown in product preview. Optional.
@@ -56,10 +56,34 @@ export default class FormsDataApi extends AsyncModules implements IFormsData {
56
56
  * @param {string} [langCode] - Language code. Default: "en_US".
57
57
  * @returns {Promise<IPostFormResponse | IError>} Returns an object containing the created form data entry and message.
58
58
  * @throws {IError} When isShell=false and an error occurs during the fetch
59
- * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects. Passing a `File`/`FileList` as the value is also supported — the SDK uploads it first, then strips `contentType` from the resulting value.
59
+ * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects.
60
+ *
61
+ * A file value may be a `File`/`Blob` (a `FileList` too), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which the SDK passes through untouched; or a hand-built {@link IFileValue} / {@link IImageValue}. The three may be mixed in one array. `contentType` is stripped from all of them, and a value of none of these shapes is sent as it came — the endpoint then names the field it cannot read, instead of the SDK throwing before the request.
62
+ *
63
+ * The endpoint wants file values in an **array**: a lone descriptor or `IFileValue` answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` works because the upload result is already one.
60
64
  * @see {@link https://js-sdk.oneentry.cloud/docs/forms-data/postFormsData postFormsData} documentation.
61
65
  */
62
66
  postFormsData(body: IBodyPostFormData, langCode?: string): Promise<IPostFormResponse | IError>;
67
+ /**
68
+ * Tells a file the SDK still has to upload from one already in storage.
69
+ * @param {unknown} value - One value of a `file` / `image` / `groupOfImages` field.
70
+ * @returns {boolean} True when the value is a `File` or a `Blob`, which has to be uploaded first.
71
+ * @description Only a `File` or a `Blob` is uploaded. Anything else — above all the
72
+ * descriptor `FileUploading.upload` returns for a file already in storage — is sent
73
+ * as it came: re-uploading it would send the descriptor as the file itself.
74
+ */
75
+ private _isUploadable;
76
+ /**
77
+ * Removes `contentType` from a file value, which the endpoint does not accept.
78
+ * @param {T} value - Value of a `file` / `image` / `groupOfImages` field, after the uploads.
79
+ * @returns {T} The same value, without `contentType`.
80
+ * @description `FileUploading.upload` returns `contentType` and form data rejects it,
81
+ * so it is stripped from an array of values and from a lone value object alike. A value
82
+ * of any other shape is returned untouched and the endpoint names the field it cannot
83
+ * read — instead of the library dying on `value.map is not a function` before the
84
+ * request is made (CMS-990).
85
+ */
86
+ private _stripContentType;
63
87
  /**
64
88
  * Drops the date bounds the endpoint refuses to parse.
65
89
  *
@@ -96,7 +96,11 @@ class FormsDataApi extends asyncModules_1.default {
96
96
  * @param {string} [langCode] - Language code. Default: "en_US".
97
97
  * @returns {Promise<IPostFormResponse | IError>} Returns an object containing the created form data entry and message.
98
98
  * @throws {IError} When isShell=false and an error occurs during the fetch
99
- * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects. Passing a `File`/`FileList` as the value is also supported — the SDK uploads it first, then strips `contentType` from the resulting value.
99
+ * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects.
100
+ *
101
+ * A file value may be a `File`/`Blob` (a `FileList` too), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which the SDK passes through untouched; or a hand-built {@link IFileValue} / {@link IImageValue}. The three may be mixed in one array. `contentType` is stripped from all of them, and a value of none of these shapes is sent as it came — the endpoint then names the field it cannot read, instead of the SDK throwing before the request.
102
+ *
103
+ * The endpoint wants file values in an **array**: a lone descriptor or `IFileValue` answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` works because the upload result is already one.
100
104
  * @see {@link https://js-sdk.oneentry.cloud/docs/forms-data/postFormsData postFormsData} documentation.
101
105
  */
102
106
  async postFormsData(body, langCode = this.state.lang) {
@@ -132,23 +136,27 @@ class FormsDataApi extends asyncModules_1.default {
132
136
  const filesArray = typeof FileList !== 'undefined' && fd.value instanceof FileList
133
137
  ? Array.from(fd.value)
134
138
  : fd.value;
135
- // If filesArray is an array, upload each file asynchronously
139
+ // If filesArray is an array, upload the files it holds asynchronously
136
140
  if (Array.isArray(filesArray)) {
137
- const uploadPromises = filesArray.map((file) => fileUploader.upload(file, fd.fileQuery).catch((e) => e));
141
+ const uploadPromises = filesArray.map((file) =>
142
+ // An entry that is already in storage is passed through: a
143
+ // second upload would send the descriptor itself as the file
144
+ // and the endpoint answers `value[0].filename is required`.
145
+ this._isUploadable(file)
146
+ ? fileUploader.upload(file, fd.fileQuery).catch((e) => e)
147
+ : file);
138
148
  fd.value = (await Promise.all(uploadPromises)).flat();
139
149
  }
140
150
  // If fd.value is a single File or Blob, upload it
141
- else if (fd.value instanceof File || fd.value instanceof Blob) {
151
+ else if (this._isUploadable(fd.value)) {
142
152
  fd.value = await fileUploader
143
153
  .upload(fd.value, fd.fileQuery)
144
154
  .catch((e) => e); // Catch any errors during upload
145
155
  }
146
156
  // Remove the 'fileQuery' property from the object after processing
147
157
  delete fd.fileQuery;
148
- // Remove the 'contentType' property from the file object because it is not needed and not valid
149
- fd.value.map((file) => {
150
- delete file.contentType;
151
- });
158
+ // Remove the 'contentType' property from the file object because it is not needed and not valid
159
+ fd.value = this._stripContentType(fd.value);
152
160
  }
153
161
  // Return the processed form data element
154
162
  return fd;
@@ -160,6 +168,42 @@ class FormsDataApi extends asyncModules_1.default {
160
168
  const validated = await this._validateResponse(result, schema('PostFormResponseSchema'));
161
169
  return this._normalizeData(validated);
162
170
  }
171
+ /**
172
+ * Tells a file the SDK still has to upload from one already in storage.
173
+ * @param {unknown} value - One value of a `file` / `image` / `groupOfImages` field.
174
+ * @returns {boolean} True when the value is a `File` or a `Blob`, which has to be uploaded first.
175
+ * @description Only a `File` or a `Blob` is uploaded. Anything else — above all the
176
+ * descriptor `FileUploading.upload` returns for a file already in storage — is sent
177
+ * as it came: re-uploading it would send the descriptor as the file itself.
178
+ */
179
+ _isUploadable(value) {
180
+ return ((typeof File !== 'undefined' && value instanceof File) ||
181
+ (typeof Blob !== 'undefined' && value instanceof Blob));
182
+ }
183
+ /**
184
+ * Removes `contentType` from a file value, which the endpoint does not accept.
185
+ * @param {T} value - Value of a `file` / `image` / `groupOfImages` field, after the uploads.
186
+ * @returns {T} The same value, without `contentType`.
187
+ * @description `FileUploading.upload` returns `contentType` and form data rejects it,
188
+ * so it is stripped from an array of values and from a lone value object alike. A value
189
+ * of any other shape is returned untouched and the endpoint names the field it cannot
190
+ * read — instead of the library dying on `value.map is not a function` before the
191
+ * request is made (CMS-990).
192
+ */
193
+ _stripContentType(value) {
194
+ const strip = (item) => {
195
+ if (item && typeof item === 'object' && !Array.isArray(item)) {
196
+ delete item.contentType;
197
+ }
198
+ };
199
+ if (Array.isArray(value)) {
200
+ value.forEach(strip);
201
+ }
202
+ else {
203
+ strip(value);
204
+ }
205
+ return value;
206
+ }
163
207
  /**
164
208
  * Drops the date bounds the endpoint refuses to parse.
165
209
  *
@@ -1,5 +1,5 @@
1
1
  import type { IError } from '../base/utils';
2
- import type { IUploadingQuery } from '../file-uploading/fileUploadingInterfaces';
2
+ import type { IUploadingQuery, IUploadingReturn } from '../file-uploading/fileUploadingInterfaces';
3
3
  /**
4
4
  * Interface for retrieving and posting form data in the system.
5
5
  * @interface IFormsData
@@ -567,7 +567,7 @@ interface ICaptchaValue {
567
567
  * @property {string} formData[].marker - The marker identifying the form field. Example: "name".
568
568
  * @property {string} formData[].type - The type of the form field. Example: "string".
569
569
  * @property {string} formData[].value - The value of the form field. Example: "name".
570
- * @property {IUploadingQuery} [fileQuery] - Optional file query for uploading files.
570
+ * @property {IUploadingQuery} [fileQuery] - Optional file query for uploading files. Kept for compatibility: the SDK reads `fileQuery` from the **file field itself** (see IBodyTypeFile), not from the body, so one set here does not change where a file is uploaded.
571
571
  * @example
572
572
  {
573
573
  "type": "page",
@@ -715,7 +715,7 @@ interface ITextWithHeaderValue {
715
715
  * @interface IBodyTypeImageGroupOfImages
716
716
  * @property {string} marker - marker name. Example: "avatar".
717
717
  * @property {'image' | 'groupOfImages'} type - Type value — must match the attribute type in the set, note the plural in "groupOfImages". Example: "image".
718
- * @property {object} value - Image Object. Contains image information.
718
+ * @property {object} value - The attached image. The same three shapes as a `file` field accepts, mixable in one array: a `File`/`Blob` (also a `FileList`), which the SDK uploads first; the descriptor `FileUploading.upload` returns for an image **already in storage**, passed through as it is; or a hand-built {@link IImageValue}. In a SUBMISSION the value must be an **array**, as for `file` — a lone object answers `400 formData's marker '<marker>' value must be an array`. Measured on js-sdk-tests.oneentry.cloud, 2026-10-08 (CMS-990).
719
719
  * @example
720
720
  [
721
721
  {
@@ -728,12 +728,14 @@ interface ITextWithHeaderValue {
728
728
  }
729
729
  }
730
730
  ]
731
+ * @property {IUploadingQuery} [fileQuery] - Where the SDK uploads a `File`/`Blob` value to. Read **per field**, not from the body; omitted, the SDK uploads to `page`/`editor` under a random id. Ignored for an image already in storage. Example: `{ "type": "page", "entity": "editor", "id": 3787 }`.
731
732
  * @description Represents an image or a group of images with their details, including filename, download link, size, preview link, and parameters for image compression.
732
733
  */
733
734
  interface IBodyTypeImageGroupOfImages {
734
735
  marker: string;
735
736
  type: 'image' | 'groupOfImages';
736
- value: IImageValue | IImageValue[];
737
+ value: IImageValue | IUploadingReturn | File | Blob | (IImageValue | IUploadingReturn | File | Blob)[];
738
+ fileQuery?: IUploadingQuery;
737
739
  }
738
740
  /**
739
741
  * @interface IImageValueParams
@@ -764,7 +766,7 @@ interface IImageValue {
764
766
  * @interface IBodyTypeFile
765
767
  * @property {string} marker - marker name. Example: "picture".
766
768
  * @property {'file'} type - Type value. Example: "file".
767
- * @property {object} value - File Object. Contains file information. A single attached file is returned as the object itself, several files as an array.
769
+ * @property {object} value - The attached file. Three shapes are accepted and may be mixed in one array: a `File`/`Blob` (also a `FileList`), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which is passed through as it is; or a hand-built {@link IFileValue}. In a SUBMISSION the value must be an **array** — a lone descriptor or {@link IFileValue} answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` is fine because the SDK wraps the upload result. A READ returns a single attached file as the object itself. Measured on js-sdk-tests.oneentry.cloud, 2026-10-08 (CMS-990).
768
770
  * @example
769
771
  [
770
772
  {
@@ -773,12 +775,14 @@ interface IImageValue {
773
775
  "size": 392585
774
776
  }
775
777
  ]
778
+ * @property {IUploadingQuery} [fileQuery] - Where the SDK uploads a `File`/`Blob` value to. Read **per field**, not from the body; omitted, the SDK uploads to `page`/`editor` under a random id. Ignored for a file already in storage. Example: `{ "type": "page", "entity": "editor", "id": 3787 }`.
776
779
  * @description Represents a file with its details, including filename, download link, and size.
777
780
  */
778
781
  interface IBodyTypeFile {
779
782
  marker: string;
780
783
  type: 'file';
781
- value: IFileValue | IFileValue[];
784
+ value: IFileValue | IUploadingReturn | File | Blob | (IFileValue | IUploadingReturn | File | Blob)[];
785
+ fileQuery?: IUploadingQuery;
782
786
  }
783
787
  /**
784
788
  * @interface IFileValue
@@ -189,28 +189,130 @@ interface IAttributeSchemaItem {
189
189
  }
190
190
  /**
191
191
  * @interface IAttributeValidators
192
- * @property {object} [requiredValidator] - Marks the field as required. Shape: `{ strict: boolean }`. Example: `{ strict: true }`.
193
- * @property {object} [stringInspectionValidator] - Length constraints for string fields. Shape: `{ stringMin: number; stringMax: number; stringLength: number }`.
194
- * @property {boolean} [emailInspectionValidator] - Toggle for email-format validation.
195
- * @property {object} [defaultValueValidator] - Default value configuration with optional custom error text. Shape: `{ customErrorText?: string; fieldDefaultValue?: unknown; fieldDefaultValue2?: unknown }`.
196
- * @description Map of validators applied to an attribute or form field. Set is extensible — additional validator types may be added by the API.
192
+ * @property {object | boolean} [requiredValidator] - Field must be filled in. Shape: `{ strict: boolean }`. Example: `{ strict: true }`.
193
+ * @property {object | boolean} [trimValidator] - Leading and trailing whitespace is stripped from the value. Stored as an empty object when the toggle is on. Example: `{}`.
194
+ * @property {object} [stringInspectionValidator] - Length constraints for string fields. Example: `{ stringLength: 0, stringMin: 2, stringMax: 60 }`.
195
+ * @property {object | boolean} [urlInspectionValidator] - Value must look like a URL. Stored either as `true` or as an object. Example: `true`.
196
+ * @property {object | boolean} [emailInspectionValidator] - Value must look like an e-mail address. Stored either as `true` or as an object. Example: `true`.
197
+ * @property {object} [checkForNumberValidator] - Value must be a number, optionally an integer within bounds. `0` disables a bound. Example: `{ integerOnly: true, minValue: 1, maxValue: 10 }`.
198
+ * @property {object} [roundingNumberValidator] - Rounds the number before storing it. Example: `{ integerOnly: false, numberOfDecimals: 2, direction: 'round' }`.
199
+ * @property {object} [booleanValidator] - Value must equal one of the two declared values. Example: `{ trueValue: 1, falseValue: 0 }`.
200
+ * @property {object} [comparisonValidator] - Compares the value with another attribute or with a constant. Example: `{ compareAttribute: 'notChoosed', compareValue: '10', type: 'number', operator: 'equality' }`.
201
+ * @property {object} [regExpValidator] - Value must match a regular expression; `invert` refuses matches instead. Example: `{ patternValue: '^[0-9]{5}$', invert: false, flags: ['i'] }`.
202
+ * @property {object} [fieldMaskValidator] - Value must match an input mask (`9` digit, `A` upper letter, `a` lower letter, `*` any, `$` one of `()+-`). Example: `{ maskValue: '+9 (999) 999-99-99' }`.
203
+ * @property {object} [checkForAGivenList] - Value must be in the list, or outside it when `notValue` is true. Example: `{ rangeValue: ['red', 'green'], notValue: false }`.
204
+ * @property {object} [defaultValueValidator] - Value substituted when the field is left empty. Example: `{ fieldDefaultValue: 'USD' }`.
205
+ * @property {object} [sizeInPixelsValidator] - Image bounds in pixels; executed by the admin panel. Example: `{ maxX: 1920, maxY: 1080 }`.
206
+ * @property {object} [checkingFilesValidator] - File size bounds and allowed extensions; executed by the admin panel. Example: `{ minValue: 0, maxValue: 5, minUnits: 'kb', maxUnits: 'mb', extensions: ['pdf'] }`.
207
+ * @property {object} [minMaxDateValidator] - Date bounds; executed by the admin panel. Example: `{ minDateTimeValue: '2026-01-01', maxDateTimeValue: '2026-12-31' }`.
208
+ * @property {object} [valueValidator] - The panel's "default value" control; it writes `defaultValueValidator`, and this name is kept because the API accepts and stores it. Example: `{ fieldDefaultValue: 'USD' }`.
209
+ * @property {object} [checkForLettersValidator] - Letters-only check by pattern; executed by the admin panel. Example: `{ patternValue: '^[A-Za-z ]+$' }`.
210
+ * @description Map of validators applied to an attribute or form field, keyed by validator name.
211
+ *
212
+ * These eighteen names are the full set the API accepts in
213
+ * `attributes_sets.schema.<attribute>.validators.<langCode>`; any other name is refused
214
+ * with `400`. The first thirteen are executed by the platform on write, the last five are
215
+ * stored as given and executed by the admin panel.
216
+ *
217
+ * Every validator may also carry `customErrorText` — the message shown instead of the
218
+ * default one when the value is refused.
197
219
  */
198
220
  interface IAttributeValidators {
199
221
  requiredValidator?: {
200
- strict: boolean;
201
- };
222
+ strict?: boolean;
223
+ customErrorText?: string;
224
+ } | boolean;
225
+ trimValidator?: {
226
+ strict?: boolean;
227
+ customErrorText?: string;
228
+ } | boolean;
202
229
  stringInspectionValidator?: {
203
- stringMin: number;
204
- stringMax: number;
205
- stringLength: number;
230
+ stringMin?: number;
231
+ stringMax?: number;
232
+ stringLength?: number;
233
+ customErrorText?: string;
234
+ };
235
+ urlInspectionValidator?: {
236
+ strict?: boolean;
237
+ customErrorText?: string;
238
+ } | boolean;
239
+ emailInspectionValidator?: {
240
+ strict?: boolean;
241
+ customErrorText?: string;
242
+ } | boolean;
243
+ checkForNumberValidator?: {
244
+ integerOnly?: boolean;
245
+ minValue?: number;
246
+ maxValue?: number;
247
+ customErrorText?: string;
248
+ };
249
+ roundingNumberValidator?: {
250
+ integerOnly?: boolean;
251
+ numberOfDecimals?: number;
252
+ direction?: 'round' | 'up' | 'down' | 'truncate';
253
+ customErrorText?: string;
254
+ };
255
+ booleanValidator?: {
256
+ trueValue?: unknown;
257
+ falseValue?: unknown;
258
+ customErrorText?: string;
259
+ };
260
+ comparisonValidator?: {
261
+ compareAttribute?: string;
262
+ compareValue?: string;
263
+ compareValue2?: string;
264
+ type?: string;
265
+ operator?: string;
266
+ customErrorText?: string;
267
+ };
268
+ regExpValidator?: {
269
+ patternValue?: string;
270
+ invert?: boolean;
271
+ flags?: string[];
272
+ customErrorText?: string;
273
+ };
274
+ fieldMaskValidator?: {
275
+ maskValue?: string;
276
+ customErrorText?: string;
277
+ };
278
+ checkForAGivenList?: {
279
+ rangeValue?: unknown[];
280
+ rangeValue2?: unknown[];
281
+ notValue?: boolean;
282
+ customErrorText?: string;
206
283
  };
207
- emailInspectionValidator?: boolean;
208
284
  defaultValueValidator?: {
285
+ fieldDefaultValue?: unknown;
286
+ fieldDefaultValue2?: unknown;
287
+ customErrorText?: string;
288
+ };
289
+ sizeInPixelsValidator?: {
290
+ maxX?: number;
291
+ maxY?: number;
209
292
  customErrorText?: string;
293
+ };
294
+ checkingFilesValidator?: {
295
+ minValue?: number;
296
+ maxValue?: number;
297
+ minUnits?: 'kb' | 'mb';
298
+ maxUnits?: 'kb' | 'mb';
299
+ extensions?: string[];
300
+ customErrorText?: string;
301
+ };
302
+ minMaxDateValidator?: {
303
+ minDateTimeValue?: string;
304
+ maxDateTimeValue?: string;
305
+ customErrorText?: string;
306
+ };
307
+ valueValidator?: {
210
308
  fieldDefaultValue?: unknown;
211
309
  fieldDefaultValue2?: unknown;
310
+ customErrorText?: string;
311
+ };
312
+ checkForLettersValidator?: {
313
+ patternValue?: string;
314
+ customErrorText?: string;
212
315
  };
213
- [key: string]: unknown;
214
316
  }
215
317
  /**
216
318
  * Represents an attribute set entity.
@@ -96,7 +96,7 @@ interface IConfig {
96
96
  * @property {boolean} isVisible - Whether the attribute is exposed in the public API/UI. Example: true.
97
97
  * @property {string} type - Attribute data type (e.g. "string", "integer", "list", "file", "image").
98
98
  * @property {Record<string, unknown>} [settings] - Type-specific configuration (e.g. min/max for numbers, accepted MIME types for files). Optional.
99
- * @property {Record<string, unknown>} validators - Validation rules applied to the attribute value (e.g. `requiredValidator`, `regexValidator`). Example: { "requiredValidator": { "strict": true } }.
99
+ * @property {Record<string, unknown>} validators - Validation rules applied to the attribute value, keyed by validator name (e.g. `requiredValidator`, `regExpValidator`); the full set of names is listed on `IAttributeValidators`. Example: { "requiredValidator": { "strict": true } }.
100
100
  * @property {Record<string, IAttributes>} [additionalFields] - Nested sub-attributes attached to this attribute, keyed by marker. Optional.
101
101
  * @property {boolean} [isIcon] - Block/preview attribute flag — whether the field is treated as an icon. Optional.
102
102
  * @property {boolean} [isProductPreview] - Block/preview attribute flag — whether the field is shown in product preview. Optional.
@@ -56,10 +56,34 @@ export default class FormsDataApi extends AsyncModules implements IFormsData {
56
56
  * @param {string} [langCode] - Language code. Default: "en_US".
57
57
  * @returns {Promise<IPostFormResponse | IError>} Returns an object containing the created form data entry and message.
58
58
  * @throws {IError} When isShell=false and an error occurs during the fetch
59
- * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects. Passing a `File`/`FileList` as the value is also supported — the SDK uploads it first, then strips `contentType` from the resulting value.
59
+ * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects.
60
+ *
61
+ * A file value may be a `File`/`Blob` (a `FileList` too), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which the SDK passes through untouched; or a hand-built {@link IFileValue} / {@link IImageValue}. The three may be mixed in one array. `contentType` is stripped from all of them, and a value of none of these shapes is sent as it came — the endpoint then names the field it cannot read, instead of the SDK throwing before the request.
62
+ *
63
+ * The endpoint wants file values in an **array**: a lone descriptor or `IFileValue` answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` works because the upload result is already one.
60
64
  * @see {@link https://js-sdk.oneentry.cloud/docs/forms-data/postFormsData postFormsData} documentation.
61
65
  */
62
66
  postFormsData(body: IBodyPostFormData, langCode?: string): Promise<IPostFormResponse | IError>;
67
+ /**
68
+ * Tells a file the SDK still has to upload from one already in storage.
69
+ * @param {unknown} value - One value of a `file` / `image` / `groupOfImages` field.
70
+ * @returns {boolean} True when the value is a `File` or a `Blob`, which has to be uploaded first.
71
+ * @description Only a `File` or a `Blob` is uploaded. Anything else — above all the
72
+ * descriptor `FileUploading.upload` returns for a file already in storage — is sent
73
+ * as it came: re-uploading it would send the descriptor as the file itself.
74
+ */
75
+ private _isUploadable;
76
+ /**
77
+ * Removes `contentType` from a file value, which the endpoint does not accept.
78
+ * @param {T} value - Value of a `file` / `image` / `groupOfImages` field, after the uploads.
79
+ * @returns {T} The same value, without `contentType`.
80
+ * @description `FileUploading.upload` returns `contentType` and form data rejects it,
81
+ * so it is stripped from an array of values and from a lone value object alike. A value
82
+ * of any other shape is returned untouched and the endpoint names the field it cannot
83
+ * read — instead of the library dying on `value.map is not a function` before the
84
+ * request is made (CMS-990).
85
+ */
86
+ private _stripContentType;
63
87
  /**
64
88
  * Drops the date bounds the endpoint refuses to parse.
65
89
  *
@@ -58,7 +58,11 @@ export default class FormsDataApi extends AsyncModules {
58
58
  * @param {string} [langCode] - Language code. Default: "en_US".
59
59
  * @returns {Promise<IPostFormResponse | IError>} Returns an object containing the created form data entry and message.
60
60
  * @throws {IError} When isShell=false and an error occurs during the fetch
61
- * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects. Passing a `File`/`FileList` as the value is also supported — the SDK uploads it first, then strips `contentType` from the resulting value.
61
+ * @description Field values are typed per field type by {@link FormDataType}. For attached files see {@link IImageValue} (`image`, `groupOfImages`) and {@link IFileValue} (`file`) — the shape the endpoint expects, which is **not** what `FileUploading.upload` returns: that object carries `contentType`, which form data rejects.
62
+ *
63
+ * A file value may be a `File`/`Blob` (a `FileList` too), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which the SDK passes through untouched; or a hand-built {@link IFileValue} / {@link IImageValue}. The three may be mixed in one array. `contentType` is stripped from all of them, and a value of none of these shapes is sent as it came — the endpoint then names the field it cannot read, instead of the SDK throwing before the request.
64
+ *
65
+ * The endpoint wants file values in an **array**: a lone descriptor or `IFileValue` answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` works because the upload result is already one.
62
66
  * @see {@link https://js-sdk.oneentry.cloud/docs/forms-data/postFormsData postFormsData} documentation.
63
67
  */
64
68
  async postFormsData(body, langCode = this.state.lang) {
@@ -94,23 +98,27 @@ export default class FormsDataApi extends AsyncModules {
94
98
  const filesArray = typeof FileList !== 'undefined' && fd.value instanceof FileList
95
99
  ? Array.from(fd.value)
96
100
  : fd.value;
97
- // If filesArray is an array, upload each file asynchronously
101
+ // If filesArray is an array, upload the files it holds asynchronously
98
102
  if (Array.isArray(filesArray)) {
99
- const uploadPromises = filesArray.map((file) => fileUploader.upload(file, fd.fileQuery).catch((e) => e));
103
+ const uploadPromises = filesArray.map((file) =>
104
+ // An entry that is already in storage is passed through: a
105
+ // second upload would send the descriptor itself as the file
106
+ // and the endpoint answers `value[0].filename is required`.
107
+ this._isUploadable(file)
108
+ ? fileUploader.upload(file, fd.fileQuery).catch((e) => e)
109
+ : file);
100
110
  fd.value = (await Promise.all(uploadPromises)).flat();
101
111
  }
102
112
  // If fd.value is a single File or Blob, upload it
103
- else if (fd.value instanceof File || fd.value instanceof Blob) {
113
+ else if (this._isUploadable(fd.value)) {
104
114
  fd.value = await fileUploader
105
115
  .upload(fd.value, fd.fileQuery)
106
116
  .catch((e) => e); // Catch any errors during upload
107
117
  }
108
118
  // Remove the 'fileQuery' property from the object after processing
109
119
  delete fd.fileQuery;
110
- // Remove the 'contentType' property from the file object because it is not needed and not valid
111
- fd.value.map((file) => {
112
- delete file.contentType;
113
- });
120
+ // Remove the 'contentType' property from the file object because it is not needed and not valid
121
+ fd.value = this._stripContentType(fd.value);
114
122
  }
115
123
  // Return the processed form data element
116
124
  return fd;
@@ -122,6 +130,42 @@ export default class FormsDataApi extends AsyncModules {
122
130
  const validated = await this._validateResponse(result, schema('PostFormResponseSchema'));
123
131
  return this._normalizeData(validated);
124
132
  }
133
+ /**
134
+ * Tells a file the SDK still has to upload from one already in storage.
135
+ * @param {unknown} value - One value of a `file` / `image` / `groupOfImages` field.
136
+ * @returns {boolean} True when the value is a `File` or a `Blob`, which has to be uploaded first.
137
+ * @description Only a `File` or a `Blob` is uploaded. Anything else — above all the
138
+ * descriptor `FileUploading.upload` returns for a file already in storage — is sent
139
+ * as it came: re-uploading it would send the descriptor as the file itself.
140
+ */
141
+ _isUploadable(value) {
142
+ return ((typeof File !== 'undefined' && value instanceof File) ||
143
+ (typeof Blob !== 'undefined' && value instanceof Blob));
144
+ }
145
+ /**
146
+ * Removes `contentType` from a file value, which the endpoint does not accept.
147
+ * @param {T} value - Value of a `file` / `image` / `groupOfImages` field, after the uploads.
148
+ * @returns {T} The same value, without `contentType`.
149
+ * @description `FileUploading.upload` returns `contentType` and form data rejects it,
150
+ * so it is stripped from an array of values and from a lone value object alike. A value
151
+ * of any other shape is returned untouched and the endpoint names the field it cannot
152
+ * read — instead of the library dying on `value.map is not a function` before the
153
+ * request is made (CMS-990).
154
+ */
155
+ _stripContentType(value) {
156
+ const strip = (item) => {
157
+ if (item && typeof item === 'object' && !Array.isArray(item)) {
158
+ delete item.contentType;
159
+ }
160
+ };
161
+ if (Array.isArray(value)) {
162
+ value.forEach(strip);
163
+ }
164
+ else {
165
+ strip(value);
166
+ }
167
+ return value;
168
+ }
125
169
  /**
126
170
  * Drops the date bounds the endpoint refuses to parse.
127
171
  *
@@ -1,5 +1,5 @@
1
1
  import type { IError } from '../base/utils.js';
2
- import type { IUploadingQuery } from '../file-uploading/fileUploadingInterfaces.js';
2
+ import type { IUploadingQuery, IUploadingReturn } from '../file-uploading/fileUploadingInterfaces.js';
3
3
  /**
4
4
  * Interface for retrieving and posting form data in the system.
5
5
  * @interface IFormsData
@@ -567,7 +567,7 @@ interface ICaptchaValue {
567
567
  * @property {string} formData[].marker - The marker identifying the form field. Example: "name".
568
568
  * @property {string} formData[].type - The type of the form field. Example: "string".
569
569
  * @property {string} formData[].value - The value of the form field. Example: "name".
570
- * @property {IUploadingQuery} [fileQuery] - Optional file query for uploading files.
570
+ * @property {IUploadingQuery} [fileQuery] - Optional file query for uploading files. Kept for compatibility: the SDK reads `fileQuery` from the **file field itself** (see IBodyTypeFile), not from the body, so one set here does not change where a file is uploaded.
571
571
  * @example
572
572
  {
573
573
  "type": "page",
@@ -715,7 +715,7 @@ interface ITextWithHeaderValue {
715
715
  * @interface IBodyTypeImageGroupOfImages
716
716
  * @property {string} marker - marker name. Example: "avatar".
717
717
  * @property {'image' | 'groupOfImages'} type - Type value — must match the attribute type in the set, note the plural in "groupOfImages". Example: "image".
718
- * @property {object} value - Image Object. Contains image information.
718
+ * @property {object} value - The attached image. The same three shapes as a `file` field accepts, mixable in one array: a `File`/`Blob` (also a `FileList`), which the SDK uploads first; the descriptor `FileUploading.upload` returns for an image **already in storage**, passed through as it is; or a hand-built {@link IImageValue}. In a SUBMISSION the value must be an **array**, as for `file` — a lone object answers `400 formData's marker '<marker>' value must be an array`. Measured on js-sdk-tests.oneentry.cloud, 2026-10-08 (CMS-990).
719
719
  * @example
720
720
  [
721
721
  {
@@ -728,12 +728,14 @@ interface ITextWithHeaderValue {
728
728
  }
729
729
  }
730
730
  ]
731
+ * @property {IUploadingQuery} [fileQuery] - Where the SDK uploads a `File`/`Blob` value to. Read **per field**, not from the body; omitted, the SDK uploads to `page`/`editor` under a random id. Ignored for an image already in storage. Example: `{ "type": "page", "entity": "editor", "id": 3787 }`.
731
732
  * @description Represents an image or a group of images with their details, including filename, download link, size, preview link, and parameters for image compression.
732
733
  */
733
734
  interface IBodyTypeImageGroupOfImages {
734
735
  marker: string;
735
736
  type: 'image' | 'groupOfImages';
736
- value: IImageValue | IImageValue[];
737
+ value: IImageValue | IUploadingReturn | File | Blob | (IImageValue | IUploadingReturn | File | Blob)[];
738
+ fileQuery?: IUploadingQuery;
737
739
  }
738
740
  /**
739
741
  * @interface IImageValueParams
@@ -764,7 +766,7 @@ interface IImageValue {
764
766
  * @interface IBodyTypeFile
765
767
  * @property {string} marker - marker name. Example: "picture".
766
768
  * @property {'file'} type - Type value. Example: "file".
767
- * @property {object} value - File Object. Contains file information. A single attached file is returned as the object itself, several files as an array.
769
+ * @property {object} value - The attached file. Three shapes are accepted and may be mixed in one array: a `File`/`Blob` (also a `FileList`), which the SDK uploads first; the descriptor `FileUploading.upload` returns for a file **already in storage**, which is passed through as it is; or a hand-built {@link IFileValue}. In a SUBMISSION the value must be an **array** — a lone descriptor or {@link IFileValue} answers `400 formData's marker '<marker>' value must be an array`, while a lone `File`/`Blob` is fine because the SDK wraps the upload result. A READ returns a single attached file as the object itself. Measured on js-sdk-tests.oneentry.cloud, 2026-10-08 (CMS-990).
768
770
  * @example
769
771
  [
770
772
  {
@@ -773,12 +775,14 @@ interface IImageValue {
773
775
  "size": 392585
774
776
  }
775
777
  ]
778
+ * @property {IUploadingQuery} [fileQuery] - Where the SDK uploads a `File`/`Blob` value to. Read **per field**, not from the body; omitted, the SDK uploads to `page`/`editor` under a random id. Ignored for a file already in storage. Example: `{ "type": "page", "entity": "editor", "id": 3787 }`.
776
779
  * @description Represents a file with its details, including filename, download link, and size.
777
780
  */
778
781
  interface IBodyTypeFile {
779
782
  marker: string;
780
783
  type: 'file';
781
- value: IFileValue | IFileValue[];
784
+ value: IFileValue | IUploadingReturn | File | Blob | (IFileValue | IUploadingReturn | File | Blob)[];
785
+ fileQuery?: IUploadingQuery;
782
786
  }
783
787
  /**
784
788
  * @interface IFileValue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oneentry",
3
- "version": "1.0.169",
3
+ "version": "1.0.171",
4
4
  "description": "OneEntry NPM package",
5
5
  "main": "dist/index.js",
6
6
  "module": "esm/index.js",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "scripts": {
50
50
  "prepublishOnly": "node ../scripts/smoke-pack.js --files-only",
51
- "postpublish": "node ../scripts/verify-published.js --named defineOneEntry --expect 1.0.169"
51
+ "postpublish": "node ../scripts/verify-published.js --named defineOneEntry --expect 1.0.171"
52
52
  },
53
53
  "sideEffects": false,
54
54
  "files": [