oneentry 1.0.136 → 1.0.138
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 +15 -3
- package/configure.js +27 -3
- package/dist/admins/adminsApi.d.ts +2 -2
- package/dist/admins/adminsApi.js +6 -3
- package/dist/admins/adminsInterfaces.d.ts +2 -2
- package/dist/admins/adminsSchemas.d.ts +30 -0
- package/dist/admins/adminsSchemas.js +27 -0
- package/dist/attribute-sets/attributeSetsApi.d.ts +8 -8
- package/dist/attribute-sets/attributeSetsApi.js +21 -12
- package/dist/attribute-sets/attributeSetsInterfaces.d.ts +3 -3
- package/dist/attribute-sets/attributeSetsSchemas.d.ts +90 -0
- package/dist/attribute-sets/attributeSetsSchemas.js +74 -0
- package/dist/auth-provider/authProviderApi.d.ts +44 -41
- package/dist/auth-provider/authProviderApi.js +58 -48
- package/dist/auth-provider/authProviderSchemas.d.ts +137 -0
- package/dist/auth-provider/authProviderSchemas.js +85 -0
- package/dist/auth-provider/authProvidersInterfaces.d.ts +17 -67
- package/dist/base/asyncModules.d.ts +25 -15
- package/dist/base/asyncModules.js +65 -44
- package/dist/base/stateModule.d.ts +8 -0
- package/dist/base/stateModule.js +27 -11
- package/dist/base/syncModules.d.ts +18 -0
- package/dist/base/syncModules.js +93 -99
- package/dist/base/utils.d.ts +56 -10
- package/dist/base/validation.d.ts +118 -0
- package/dist/base/validation.js +132 -0
- package/dist/blocks/blocksApi.d.ts +10 -10
- package/dist/blocks/blocksApi.js +26 -21
- package/dist/blocks/blocksInterfaces.d.ts +2 -1
- package/dist/blocks/blocksSchemas.d.ts +187 -0
- package/dist/blocks/blocksSchemas.js +43 -0
- package/dist/events/eventsApi.d.ts +5 -5
- package/dist/events/eventsApi.js +5 -5
- package/dist/events/eventsInterfaces.d.ts +25 -15
- package/dist/file-uploading/fileUploadingApi.d.ts +6 -6
- package/dist/file-uploading/fileUploadingApi.js +10 -7
- package/dist/file-uploading/fileUploadingSchemas.d.ts +22 -0
- package/dist/file-uploading/fileUploadingSchemas.js +21 -0
- package/dist/forms/formsApi.d.ts +4 -4
- package/dist/forms/formsApi.js +11 -6
- package/dist/forms/formsInterfaces.d.ts +21 -8
- package/dist/forms/formsSchemas.d.ts +65 -0
- package/dist/forms/formsSchemas.js +36 -0
- package/dist/forms-data/formsDataApi.d.ts +10 -10
- package/dist/forms-data/formsDataApi.js +20 -13
- package/dist/forms-data/formsDataInterfaces.d.ts +26 -26
- package/dist/forms-data/formsDataSchemas.d.ts +115 -0
- package/dist/forms-data/formsDataSchemas.js +86 -0
- package/dist/general-types/generalTypesApi.d.ts +2 -2
- package/dist/general-types/generalTypesApi.js +6 -3
- package/dist/general-types/generalTypesSchemas.d.ts +50 -0
- package/dist/general-types/generalTypesSchemas.js +35 -0
- package/dist/index.d.ts +23 -1
- package/dist/integration-collections/integrationCollectionsApi.d.ts +17 -17
- package/dist/integration-collections/integrationCollectionsApi.js +42 -26
- package/dist/integration-collections/integrationCollectionsSchemas.d.ts +84 -0
- package/dist/integration-collections/integrationCollectionsSchemas.js +63 -0
- package/dist/locales/localesApi.d.ts +2 -2
- package/dist/locales/localesApi.js +6 -3
- package/dist/locales/localesSchemas.d.ts +32 -0
- package/dist/locales/localesSchemas.js +26 -0
- package/dist/menus/menusApi.d.ts +2 -2
- package/dist/menus/menusApi.js +6 -3
- package/dist/menus/menusInterfaces.d.ts +2 -2
- package/dist/menus/menusSchemas.d.ts +16 -0
- package/dist/menus/menusSchemas.js +28 -0
- package/dist/orders/ordersApi.d.ts +12 -12
- package/dist/orders/ordersApi.js +25 -16
- package/dist/orders/ordersInterfaces.d.ts +5 -4
- package/dist/orders/ordersSchemas.d.ts +158 -0
- package/dist/orders/ordersSchemas.js +120 -0
- package/dist/pages/pagesApi.d.ts +22 -21
- package/dist/pages/pagesApi.js +107 -54
- package/dist/pages/pagesInterfaces.d.ts +15 -11
- package/dist/pages/pagesSchemas.d.ts +85 -0
- package/dist/pages/pagesSchemas.js +46 -0
- package/dist/payments/paymentsApi.d.ts +13 -13
- package/dist/payments/paymentsApi.js +25 -16
- package/dist/payments/paymentsInterfaces.d.ts +11 -5
- package/dist/payments/paymentsSchemas.d.ts +137 -0
- package/dist/payments/paymentsSchemas.js +78 -0
- package/dist/product-statuses/productStatusesApi.d.ts +6 -6
- package/dist/product-statuses/productStatusesApi.js +19 -9
- package/dist/product-statuses/productStatusesSchemas.d.ts +34 -0
- package/dist/product-statuses/productStatusesSchemas.js +30 -0
- package/dist/products/productsApi.d.ts +29 -28
- package/dist/products/productsApi.js +50 -36
- package/dist/products/productsInterfaces.d.ts +27 -22
- package/dist/products/productsSchemas.d.ts +212 -0
- package/dist/products/productsSchemas.js +85 -0
- package/dist/system/systemApi.d.ts +10 -10
- package/dist/system/systemApi.js +10 -10
- package/dist/templates/templatesApi.d.ts +6 -6
- package/dist/templates/templatesApi.js +17 -10
- package/dist/templates/templatesSchemas.d.ts +48 -0
- package/dist/templates/templatesSchemas.js +31 -0
- package/dist/templates-preview/templatesPreviewApi.d.ts +3 -3
- package/dist/templates-preview/templatesPreviewApi.js +10 -5
- package/dist/templates-preview/templatesPreviewInterfaces.d.ts +1 -0
- package/dist/templates-preview/templatesPreviewSchemas.d.ts +83 -0
- package/dist/templates-preview/templatesPreviewSchemas.js +48 -0
- package/dist/users/usersApi.d.ts +18 -18
- package/dist/users/usersApi.js +26 -23
- package/dist/users/usersInterfaces.d.ts +10 -11
- package/dist/users/usersSchemas.d.ts +38 -0
- package/dist/users/usersSchemas.js +28 -0
- package/package.json +36 -12
- package/dist/config.d.ts +0 -13
- package/dist/config.js +0 -32
package/dist/base/syncModules.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// Using WeakMap to store unique instance IDs for each object instance
|
|
4
|
+
const instanceIds = new WeakMap();
|
|
5
|
+
// Counter to ensure even more uniqueness
|
|
6
|
+
let instanceCounter = 0;
|
|
3
7
|
/**
|
|
4
8
|
* Abstract class representing synchronization modules.
|
|
5
9
|
*/
|
|
@@ -17,6 +21,15 @@ class SyncModules {
|
|
|
17
21
|
this._sortAttributes = (data) => Object.fromEntries(Object.entries(data).sort(([, a], [, b]) => a.position - b.position));
|
|
18
22
|
this.state = state;
|
|
19
23
|
this._url = state.url;
|
|
24
|
+
// Generate and store a unique instance ID using WeakMap
|
|
25
|
+
if (!instanceIds.has(this)) {
|
|
26
|
+
const timestampPart = Date.now().toString(36);
|
|
27
|
+
const randomPart = Math.random().toString(36).substring(2, 15) +
|
|
28
|
+
Math.random().toString(36).substring(2, 15);
|
|
29
|
+
const counterPart = (++instanceCounter).toString(36);
|
|
30
|
+
const instanceId = `${timestampPart}${randomPart}${counterPart}`;
|
|
31
|
+
instanceIds.set(this, instanceId);
|
|
32
|
+
}
|
|
20
33
|
}
|
|
21
34
|
/**
|
|
22
35
|
* Constructs the full URL path by appending the given path to the base URL.
|
|
@@ -136,44 +149,29 @@ class SyncModules {
|
|
|
136
149
|
return result;
|
|
137
150
|
}
|
|
138
151
|
/**
|
|
139
|
-
*
|
|
140
|
-
* @param {Date} date - The date for which to
|
|
141
|
-
* @param {object}
|
|
142
|
-
* @param {boolean}
|
|
143
|
-
* @param {
|
|
144
|
-
* @param {
|
|
145
|
-
* @param {Set<Array<string>>} utcIntervals - A set to store unique intervals.
|
|
152
|
+
* Common logic for processing schedule dates (weekly, monthly, or both).
|
|
153
|
+
* @param {Date} date - The date for which to process intervals.
|
|
154
|
+
* @param {object} config - Configuration for schedule repetition.
|
|
155
|
+
* @param {boolean} config.inEveryWeek - Whether to repeat weekly.
|
|
156
|
+
* @param {boolean} config.inEveryMonth - Whether to repeat monthly.
|
|
157
|
+
* @param {Function} processDate - Callback function to process each date.
|
|
146
158
|
*/
|
|
147
|
-
|
|
159
|
+
_processScheduleDates(date, config, processDate) {
|
|
148
160
|
// Handle weekly schedules
|
|
149
|
-
if (
|
|
161
|
+
if (config.inEveryWeek && !config.inEveryMonth) {
|
|
150
162
|
let currentDate = new Date(date);
|
|
151
163
|
// Calculate the last day of the current month
|
|
152
164
|
const endOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
|
153
165
|
while (currentDate <= endOfMonth) {
|
|
154
|
-
|
|
155
|
-
const [startTime, endTime] = timeRange;
|
|
156
|
-
const intervalStart = new Date(currentDate);
|
|
157
|
-
intervalStart.setUTCHours(startTime.hours, startTime.minutes, 0, 0);
|
|
158
|
-
const intervalEnd = new Date(currentDate);
|
|
159
|
-
intervalEnd.setUTCHours(endTime.hours, endTime.minutes, 0, 0);
|
|
160
|
-
// Add JSON string to Set for uniqueness
|
|
161
|
-
utcIntervals.add([
|
|
162
|
-
intervalStart.toISOString(),
|
|
163
|
-
intervalEnd.toISOString(),
|
|
164
|
-
]);
|
|
165
|
-
});
|
|
166
|
+
processDate(currentDate);
|
|
166
167
|
// Move to the next week
|
|
167
168
|
currentDate = this._addDays(currentDate, 7);
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
// Handle monthly schedules
|
|
171
|
-
if (
|
|
172
|
-
// Начальная дата
|
|
172
|
+
if (config.inEveryMonth && !config.inEveryWeek) {
|
|
173
173
|
const startDate = new Date(date);
|
|
174
|
-
// Определяем день месяца начальной даты
|
|
175
174
|
const targetDayOfMonth = startDate.getUTCDate();
|
|
176
|
-
// Количество месяцев, на которые нужно повторить
|
|
177
175
|
const numberOfMonths = 12;
|
|
178
176
|
for (let i = 0; i < numberOfMonths; i++) {
|
|
179
177
|
const currentDate = new Date(startDate);
|
|
@@ -184,26 +182,13 @@ class SyncModules {
|
|
|
184
182
|
if (currentDate.getUTCMonth() !== (startDate.getUTCMonth() + i) % 12) {
|
|
185
183
|
continue; // Skip this month if exceeded
|
|
186
184
|
}
|
|
187
|
-
|
|
188
|
-
const [startTime, endTime] = timeRange;
|
|
189
|
-
const intervalStart = new Date(currentDate);
|
|
190
|
-
intervalStart.setUTCHours(startTime.hours, startTime.minutes, 0, 0);
|
|
191
|
-
const intervalEnd = new Date(currentDate);
|
|
192
|
-
intervalEnd.setUTCHours(endTime.hours, endTime.minutes, 0, 0);
|
|
193
|
-
utcIntervals.add([
|
|
194
|
-
intervalStart.toISOString(),
|
|
195
|
-
intervalEnd.toISOString(),
|
|
196
|
-
]);
|
|
197
|
-
});
|
|
185
|
+
processDate(currentDate);
|
|
198
186
|
}
|
|
199
187
|
}
|
|
200
188
|
// Handle both weekly and monthly schedules
|
|
201
|
-
if (
|
|
202
|
-
// Initial date
|
|
189
|
+
if (config.inEveryMonth && config.inEveryWeek) {
|
|
203
190
|
const startDate = new Date(date);
|
|
204
|
-
// Determine the day of the week
|
|
205
191
|
const targetDayOfWeek = startDate.getUTCDay();
|
|
206
|
-
// Number of months to repeat
|
|
207
192
|
const numberOfMonths = 12;
|
|
208
193
|
for (let i = 0; i < numberOfMonths; i++) {
|
|
209
194
|
const currentDate = new Date(startDate);
|
|
@@ -216,30 +201,50 @@ class SyncModules {
|
|
|
216
201
|
// Iterate over all target days of the week in the current month
|
|
217
202
|
while (currentDate.getUTCMonth() ===
|
|
218
203
|
(startDate.getUTCMonth() + i) % 12) {
|
|
219
|
-
|
|
220
|
-
const [startTime, endTime] = timeRange;
|
|
221
|
-
const intervalStart = new Date(currentDate);
|
|
222
|
-
intervalStart.setUTCHours(startTime.hours, startTime.minutes, 0, 0);
|
|
223
|
-
const intervalEnd = new Date(currentDate);
|
|
224
|
-
intervalEnd.setUTCHours(endTime.hours, endTime.minutes, 0, 0);
|
|
225
|
-
utcIntervals.add([
|
|
226
|
-
intervalStart.toISOString(),
|
|
227
|
-
intervalEnd.toISOString(),
|
|
228
|
-
]);
|
|
229
|
-
});
|
|
204
|
+
processDate(currentDate);
|
|
230
205
|
// Move to the next week (same day of the week)
|
|
231
206
|
currentDate.setUTCDate(currentDate.getUTCDate() + 7);
|
|
232
207
|
}
|
|
233
208
|
}
|
|
234
209
|
}
|
|
235
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Generates intervals for a specific date based on a schedule.
|
|
213
|
+
* @param {Date} date - The date for which to generate intervals.
|
|
214
|
+
* @param {object} schedule - The schedule defining the intervals.
|
|
215
|
+
* @param {boolean} schedule.inEveryWeek - The number of weeks between intervals.
|
|
216
|
+
* @param {any[]} schedule.times - The times for each interval.
|
|
217
|
+
* @param {boolean} schedule.inEveryMonth - The month intervals for each interval.
|
|
218
|
+
* @param {Set<Array<string>>} utcIntervals - A set to store unique intervals.
|
|
219
|
+
*/
|
|
220
|
+
_generateIntervalsForDate(date, schedule, utcIntervals) {
|
|
221
|
+
this._processScheduleDates(date, schedule, (currentDate) => {
|
|
222
|
+
schedule.times.forEach((timeRange) => {
|
|
223
|
+
const [startTime, endTime] = timeRange;
|
|
224
|
+
const intervalStart = new Date(currentDate);
|
|
225
|
+
intervalStart.setUTCHours(startTime.hours, startTime.minutes, 0, 0);
|
|
226
|
+
const intervalEnd = new Date(currentDate);
|
|
227
|
+
intervalEnd.setUTCHours(endTime.hours, endTime.minutes, 0, 0);
|
|
228
|
+
utcIntervals.add([
|
|
229
|
+
intervalStart.toISOString(),
|
|
230
|
+
intervalEnd.toISOString(),
|
|
231
|
+
]);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
236
235
|
/**
|
|
237
236
|
* Adds time intervals to schedules.
|
|
238
237
|
* @param {any[]} schedules - The schedules to process.
|
|
239
238
|
* @returns {any} Schedules with added time intervals.
|
|
240
239
|
*/
|
|
241
240
|
_addTimeIntervalsToSchedules(schedules) {
|
|
242
|
-
schedules.forEach((scheduleGroup) => {
|
|
241
|
+
schedules === null || schedules === void 0 ? void 0 : schedules.forEach((scheduleGroup) => {
|
|
242
|
+
// Skip if scheduleGroup.values is not an array
|
|
243
|
+
if (!scheduleGroup ||
|
|
244
|
+
!scheduleGroup.values ||
|
|
245
|
+
!Array.isArray(scheduleGroup.values)) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
243
248
|
scheduleGroup.values.forEach((schedule) => {
|
|
244
249
|
const utcIntervals = new Set();
|
|
245
250
|
const startDate = new Date(schedule.dates[0]);
|
|
@@ -294,48 +299,7 @@ class SyncModules {
|
|
|
294
299
|
}
|
|
295
300
|
});
|
|
296
301
|
};
|
|
297
|
-
|
|
298
|
-
if (interval.inEveryWeek && !interval.inEveryMonth) {
|
|
299
|
-
let currentDate = new Date(date);
|
|
300
|
-
const endOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
|
301
|
-
while (currentDate <= endOfMonth) {
|
|
302
|
-
generateTimeSlotsForDate(currentDate);
|
|
303
|
-
currentDate = this._addDays(currentDate, 7);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
// Handle monthly schedules
|
|
307
|
-
if (interval.inEveryMonth && !interval.inEveryWeek) {
|
|
308
|
-
const startDate = new Date(date);
|
|
309
|
-
const targetDayOfMonth = startDate.getUTCDate();
|
|
310
|
-
const numberOfMonths = 12;
|
|
311
|
-
for (let i = 0; i < numberOfMonths; i++) {
|
|
312
|
-
const currentDate = new Date(startDate);
|
|
313
|
-
currentDate.setUTCMonth(currentDate.getUTCMonth() + i);
|
|
314
|
-
currentDate.setUTCDate(targetDayOfMonth);
|
|
315
|
-
if (currentDate.getUTCMonth() !== (startDate.getUTCMonth() + i) % 12) {
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
generateTimeSlotsForDate(currentDate);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
// Handle both weekly and monthly schedules
|
|
322
|
-
if (interval.inEveryMonth && interval.inEveryWeek) {
|
|
323
|
-
const startDate = new Date(date);
|
|
324
|
-
const targetDayOfWeek = startDate.getUTCDay();
|
|
325
|
-
const numberOfMonths = 12;
|
|
326
|
-
for (let i = 0; i < numberOfMonths; i++) {
|
|
327
|
-
const currentDate = new Date(startDate);
|
|
328
|
-
currentDate.setUTCMonth(currentDate.getUTCMonth() + i);
|
|
329
|
-
currentDate.setUTCDate(1);
|
|
330
|
-
const daysUntilTargetDay = (targetDayOfWeek - currentDate.getUTCDay() + 7) % 7;
|
|
331
|
-
currentDate.setUTCDate(currentDate.getUTCDate() + daysUntilTargetDay);
|
|
332
|
-
while (currentDate.getUTCMonth() ===
|
|
333
|
-
(startDate.getUTCMonth() + i) % 12) {
|
|
334
|
-
generateTimeSlotsForDate(currentDate);
|
|
335
|
-
currentDate.setUTCDate(currentDate.getUTCDate() + 7);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
302
|
+
this._processScheduleDates(date, interval, generateTimeSlotsForDate);
|
|
339
303
|
}
|
|
340
304
|
/**
|
|
341
305
|
* Adds time intervals to form schedules (different structure).
|
|
@@ -368,6 +332,16 @@ class SyncModules {
|
|
|
368
332
|
});
|
|
369
333
|
return intervals;
|
|
370
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* Transforms additionalFields from array to object keyed by marker.
|
|
337
|
+
* Skipped when rawData is enabled in config.
|
|
338
|
+
* @param {any} attr - The attribute object that may contain additionalFields.
|
|
339
|
+
*/
|
|
340
|
+
_normalizeAdditionalFields(attr) {
|
|
341
|
+
if (!this.state.rawData && Array.isArray(attr.additionalFields)) {
|
|
342
|
+
attr.additionalFields = Object.fromEntries(attr.additionalFields.map((field) => [field.marker, field]));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
371
345
|
/**
|
|
372
346
|
* Normalizes attributes within the data.
|
|
373
347
|
* @param {any} data - The data to normalize.
|
|
@@ -379,6 +353,7 @@ class SyncModules {
|
|
|
379
353
|
if ('attributeValues' in data) {
|
|
380
354
|
for (const attr in data.attributeValues) {
|
|
381
355
|
const d = data.attributeValues[attr];
|
|
356
|
+
this._normalizeAdditionalFields(d);
|
|
382
357
|
// normalize numbers
|
|
383
358
|
if (d.type === 'integer' || d.type === 'float') {
|
|
384
359
|
const numValue = Number(d.value);
|
|
@@ -403,6 +378,7 @@ class SyncModules {
|
|
|
403
378
|
if ('attributes' in data) {
|
|
404
379
|
const d = data.attributes;
|
|
405
380
|
for (const attr in d) {
|
|
381
|
+
this._normalizeAdditionalFields(d[attr]);
|
|
406
382
|
// Normalize numbers
|
|
407
383
|
// if (d[attr].type === 'integer' || d[attr].type === 'float') {
|
|
408
384
|
// const numValue = Number(d[attr].value);
|
|
@@ -422,6 +398,7 @@ class SyncModules {
|
|
|
422
398
|
}
|
|
423
399
|
// For single attribute - for attribute sets
|
|
424
400
|
if ('type' in data) {
|
|
401
|
+
this._normalizeAdditionalFields(data);
|
|
425
402
|
// Normalize numbers
|
|
426
403
|
if (data.type === 'integer' || data.type === 'float') {
|
|
427
404
|
const numValue = Number(data.value);
|
|
@@ -478,12 +455,29 @@ class SyncModules {
|
|
|
478
455
|
}
|
|
479
456
|
// Access navigator through globalThis.window object to avoid direct reference
|
|
480
457
|
const win = globalThis.window;
|
|
481
|
-
|
|
458
|
+
// Get the instance ID from the WeakMap
|
|
459
|
+
const instanceId = instanceIds.get(this) ||
|
|
460
|
+
Date.now().toString(36) +
|
|
461
|
+
Math.random().toString(36).substring(2, 15) +
|
|
462
|
+
Math.random().toString(36).substring(2, 15) +
|
|
463
|
+
(++instanceCounter).toString(36);
|
|
464
|
+
// Node.js environment - unique per-instance fingerprint (no shared process ID)
|
|
465
|
+
if (!win) {
|
|
466
|
+
return JSON.stringify({
|
|
467
|
+
fingerprint: `UQ_${instanceId}`,
|
|
468
|
+
deviceInfo: {
|
|
469
|
+
os: 'Node.js',
|
|
470
|
+
browser: `Node.js/${instanceId.substring(0, 10)}`,
|
|
471
|
+
location: 'en-US',
|
|
472
|
+
},
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
const nav = win.navigator || {};
|
|
482
476
|
const platform = nav.platform || 'Win32';
|
|
483
477
|
const userAgent = nav.userAgent || 'Node.js/22';
|
|
484
478
|
const language = nav.language || 'en-US';
|
|
485
479
|
// Get screen information if available
|
|
486
|
-
const screen =
|
|
480
|
+
const screen = win.screen || {};
|
|
487
481
|
const screenWidth = screen.width || 0;
|
|
488
482
|
const screenHeight = screen.height || 0;
|
|
489
483
|
const colorDepth = screen.colorDepth || 0;
|
|
@@ -500,7 +494,7 @@ class SyncModules {
|
|
|
500
494
|
let isPrivateBrowsing = false;
|
|
501
495
|
try {
|
|
502
496
|
// Simple localStorage test to detect private browsing
|
|
503
|
-
if (win
|
|
497
|
+
if (win.localStorage) {
|
|
504
498
|
const testKey = 'test_private_browsing';
|
|
505
499
|
win.localStorage.setItem(testKey, '1');
|
|
506
500
|
win.localStorage.removeItem(testKey);
|
|
@@ -514,7 +508,7 @@ class SyncModules {
|
|
|
514
508
|
isPrivateBrowsing = true; // Error during localStorage access indicates private browsing
|
|
515
509
|
}
|
|
516
510
|
// Create a stable fingerprint string using stable device/browser characteristics
|
|
517
|
-
const fingerprintString = `${platform}|${userAgent}|${language}|${screenWidth}|${screenHeight}|${colorDepth}|${timezone}|${isPrivateBrowsing ? 'private' : 'normal'}`;
|
|
511
|
+
const fingerprintString = `${platform}|${userAgent}|${language}|${screenWidth}|${screenHeight}|${colorDepth}|${timezone}|${isPrivateBrowsing ? 'private' : 'normal'}|${instanceId}`;
|
|
518
512
|
// Simple but stable hash function
|
|
519
513
|
let hash = 0;
|
|
520
514
|
for (let i = 0; i < fingerprintString.length; i++) {
|
|
@@ -523,7 +517,7 @@ class SyncModules {
|
|
|
523
517
|
hash = hash & hash; // Convert to 32-bit integer
|
|
524
518
|
}
|
|
525
519
|
const deviceMetadata = {
|
|
526
|
-
fingerprint: `UQ_${Math.abs(hash).toString(36)}`,
|
|
520
|
+
fingerprint: `UQ_${Math.abs(hash).toString(36)}_${instanceId.substring(0, 12)}`,
|
|
527
521
|
deviceInfo: {
|
|
528
522
|
os: platform.replace(/ /g, '_'),
|
|
529
523
|
browser: userAgent.replace(/ /g, '_'),
|
package/dist/base/utils.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {string} Types - Type of block.
|
|
3
|
+
*/
|
|
1
4
|
type Types = 'product' | 'error_page' | 'catalog_page' | 'product_preview' | 'similar_products_block' | 'product_block' | 'form' | 'common_page' | 'common_block' | 'order' | 'service' | 'none';
|
|
2
5
|
/**
|
|
3
|
-
* @
|
|
4
|
-
* @
|
|
5
|
-
* @
|
|
6
|
-
* @
|
|
7
|
-
* @
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
10
|
-
* @
|
|
6
|
+
* @property {string} [token] - If your project is protected by a token, specify this token in this parameter.
|
|
7
|
+
* @property {string} [langCode] - specify the default language to avoid specifying it in every request.
|
|
8
|
+
* @property {boolean} [traficLimit] - Some methods use multiple queries to make it easier to work with the API. Set this parameter to "false" to save traffic and decide for yourself what data you need.
|
|
9
|
+
* @property {boolean} [rawData] - Set to true to receive raw API responses without any transformation.
|
|
10
|
+
* @property {object} [validation] - Validation settings for API responses.
|
|
11
|
+
* @property {boolean} [auth] - An object with authorization settings.
|
|
12
|
+
* @property {boolean} [auth.customAuth] - Set this flag to true if you want to configure the authorization process yourself. Set the flag to false, or do not pass it at all to have automatic authorization and token renewal.
|
|
13
|
+
* @property {boolean} [auth.refreshToken] - Transfer the refresh token here, for example from the local storage, to resume the user's session. Otherwise, the user will need to log in every time a new session is created.
|
|
14
|
+
* @property {boolean} [auth.providerMarker] - The marker of the provider, for example, email, google, facebook, etc. Default 'email';
|
|
15
|
+
* @property {boolean} [auth.saveFunction] - If you want to store the token between sessions, for example in local storage, create a custom function that takes refreshToken as a parameter and executes the necessary instructions. This function will be called every time the tokens are updated.
|
|
16
|
+
* @property {object} [errors] - Error handling settings.
|
|
11
17
|
* @example
|
|
12
18
|
* ```ts
|
|
13
19
|
* const saveToken = (token) => {
|
|
@@ -27,8 +33,11 @@ type Types = 'product' | 'error_page' | 'catalog_page' | 'product_preview' | 'si
|
|
|
27
33
|
* errors: {
|
|
28
34
|
* isShell: true,
|
|
29
35
|
* customErrors: {
|
|
36
|
+
* '400': badRequestFunction,
|
|
30
37
|
* '404': notFoundFunction,
|
|
31
|
-
* '
|
|
38
|
+
* '429': rateLimitFunction,
|
|
39
|
+
* '500': serverErrorFunction,
|
|
40
|
+
* '503': serviceUnavailableFunction
|
|
32
41
|
* }
|
|
33
42
|
* }
|
|
34
43
|
* }
|
|
@@ -38,6 +47,12 @@ interface IConfig {
|
|
|
38
47
|
token?: string;
|
|
39
48
|
langCode?: string;
|
|
40
49
|
traficLimit?: boolean;
|
|
50
|
+
rawData?: boolean;
|
|
51
|
+
validation?: {
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
strictMode?: boolean;
|
|
54
|
+
logErrors?: boolean;
|
|
55
|
+
};
|
|
41
56
|
auth?: {
|
|
42
57
|
customAuth?: boolean;
|
|
43
58
|
refreshToken?: string;
|
|
@@ -51,7 +66,11 @@ interface IConfig {
|
|
|
51
66
|
401?: (data?: IError) => any;
|
|
52
67
|
403?: (data?: IError) => any;
|
|
53
68
|
404?: (data?: IError) => any;
|
|
69
|
+
429?: (data?: IError) => any;
|
|
54
70
|
500?: (data?: IError) => any;
|
|
71
|
+
502?: (data?: IError) => any;
|
|
72
|
+
503?: (data?: IError) => any;
|
|
73
|
+
504?: (data?: IError) => any;
|
|
55
74
|
};
|
|
56
75
|
};
|
|
57
76
|
}
|
|
@@ -136,6 +155,33 @@ interface IError {
|
|
|
136
155
|
timestamp: string;
|
|
137
156
|
[key: string]: any;
|
|
138
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* @interface IHttpHeaders
|
|
160
|
+
* @property {string} [Content-Type] - Content type header
|
|
161
|
+
* @property {string} [x-app-token] - App token header
|
|
162
|
+
* @property {string} [x-device-metadata] - Device metadata header
|
|
163
|
+
* @property {string} [Authorization] - Authorization header
|
|
164
|
+
* @description Interface for HTTP headers
|
|
165
|
+
*/
|
|
166
|
+
interface IHttpHeaders {
|
|
167
|
+
'Content-Type'?: string;
|
|
168
|
+
'x-app-token'?: string;
|
|
169
|
+
'x-device-metadata'?: string;
|
|
170
|
+
Authorization?: string;
|
|
171
|
+
[key: string]: string | undefined;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* @interface IHttpOptions
|
|
175
|
+
* @property {string} method - HTTP method
|
|
176
|
+
* @property {IHttpHeaders} headers - HTTP headers
|
|
177
|
+
* @property {string | FormData | Blob} [body] - Request body
|
|
178
|
+
* @description Interface for HTTP request options
|
|
179
|
+
*/
|
|
180
|
+
interface IHttpOptions {
|
|
181
|
+
method: string;
|
|
182
|
+
headers: IHttpHeaders;
|
|
183
|
+
body?: string | FormData | Blob;
|
|
184
|
+
}
|
|
139
185
|
/**
|
|
140
186
|
* AttributeType
|
|
141
187
|
*/
|
|
@@ -148,4 +194,4 @@ type LangType = string | Array<string>;
|
|
|
148
194
|
* LocalizeType
|
|
149
195
|
*/
|
|
150
196
|
type LocalizeType = ILocalizeInfos | ILocalizeInfo;
|
|
151
|
-
export type { AttributeType, IAttributes, IAttributeValues, IConfig, IError, ILocalizeInfo, ILocalizeInfos, LangType, LocalizeType, Types, };
|
|
197
|
+
export type { AttributeType, IAttributes, IAttributeValues, IConfig, IError, IHttpHeaders, IHttpOptions, ILocalizeInfo, ILocalizeInfos, LangType, LocalizeType, Types, };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Common validation schemas for API responses
|
|
4
|
+
* @description Base schemas that can be reused across different modules
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Error response schema
|
|
8
|
+
*/
|
|
9
|
+
export declare const ErrorSchema: z.ZodObject<{
|
|
10
|
+
statusCode: z.ZodNumber;
|
|
11
|
+
message: z.ZodString;
|
|
12
|
+
localizeMessage: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
/**
|
|
15
|
+
* Localize info schema
|
|
16
|
+
*/
|
|
17
|
+
export declare const LocalizeInfoSchema: z.ZodObject<{
|
|
18
|
+
title: z.ZodString;
|
|
19
|
+
content: z.ZodOptional<z.ZodString>;
|
|
20
|
+
menuTitle: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
/**
|
|
23
|
+
* Attribute schema
|
|
24
|
+
*/
|
|
25
|
+
export declare const AttributeSchema: z.ZodObject<{
|
|
26
|
+
id: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
marker: z.ZodString;
|
|
28
|
+
type: z.ZodString;
|
|
29
|
+
isVisible: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
isRequired: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
localizeInfos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
33
|
+
title: z.ZodString;
|
|
34
|
+
content: z.ZodOptional<z.ZodString>;
|
|
35
|
+
menuTitle: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strip>>>;
|
|
37
|
+
value: z.ZodOptional<z.ZodAny>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
/**
|
|
40
|
+
* User entity schema
|
|
41
|
+
*/
|
|
42
|
+
export declare const UserEntitySchema: z.ZodObject<{
|
|
43
|
+
id: z.ZodNumber;
|
|
44
|
+
identifier: z.ZodOptional<z.ZodString>;
|
|
45
|
+
email: z.ZodOptional<z.ZodString>;
|
|
46
|
+
phoneMask: z.ZodOptional<z.ZodString>;
|
|
47
|
+
phoneCode: z.ZodOptional<z.ZodString>;
|
|
48
|
+
phoneNumber: z.ZodOptional<z.ZodString>;
|
|
49
|
+
statusMarker: z.ZodOptional<z.ZodString>;
|
|
50
|
+
formData: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodAny>, z.ZodRecord<z.ZodString, z.ZodAny>]>>;
|
|
51
|
+
total: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
52
|
+
authProviderIdentifier: z.ZodOptional<z.ZodString>;
|
|
53
|
+
formIdentifier: z.ZodOptional<z.ZodString>;
|
|
54
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
55
|
+
state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
56
|
+
moduleFormConfigs: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
57
|
+
}, z.core.$strip>;
|
|
58
|
+
/**
|
|
59
|
+
* Auth entity schema
|
|
60
|
+
* API returns only accessToken and refreshToken
|
|
61
|
+
* userIdentifier and authProviderIdentifier are optional legacy fields
|
|
62
|
+
*/
|
|
63
|
+
export declare const AuthEntitySchema: z.ZodObject<{
|
|
64
|
+
accessToken: z.ZodString;
|
|
65
|
+
refreshToken: z.ZodString;
|
|
66
|
+
userIdentifier: z.ZodOptional<z.ZodString>;
|
|
67
|
+
authProviderIdentifier: z.ZodOptional<z.ZodString>;
|
|
68
|
+
user: z.ZodOptional<z.ZodObject<{
|
|
69
|
+
id: z.ZodNumber;
|
|
70
|
+
identifier: z.ZodOptional<z.ZodString>;
|
|
71
|
+
email: z.ZodOptional<z.ZodString>;
|
|
72
|
+
phoneMask: z.ZodOptional<z.ZodString>;
|
|
73
|
+
phoneCode: z.ZodOptional<z.ZodString>;
|
|
74
|
+
phoneNumber: z.ZodOptional<z.ZodString>;
|
|
75
|
+
statusMarker: z.ZodOptional<z.ZodString>;
|
|
76
|
+
formData: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodAny>, z.ZodRecord<z.ZodString, z.ZodAny>]>>;
|
|
77
|
+
total: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
78
|
+
authProviderIdentifier: z.ZodOptional<z.ZodString>;
|
|
79
|
+
formIdentifier: z.ZodOptional<z.ZodString>;
|
|
80
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
81
|
+
state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
82
|
+
moduleFormConfigs: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
83
|
+
}, z.core.$strip>>;
|
|
84
|
+
}, z.core.$strip>;
|
|
85
|
+
/**
|
|
86
|
+
* Paginated response schema factory
|
|
87
|
+
* @param {T} itemSchema - The schema for each item in the paginated response
|
|
88
|
+
* @returns {any} Paginated response schema
|
|
89
|
+
*/
|
|
90
|
+
export declare function createPaginatedSchema<T extends z.ZodTypeAny>(itemSchema: T): any;
|
|
91
|
+
/**
|
|
92
|
+
* Validation helper function
|
|
93
|
+
* @param {z.ZodSchema<T>} schema - Zod schema to validate against
|
|
94
|
+
* @param {unknown} data - Data to validate
|
|
95
|
+
* @param {object} options - Validation options
|
|
96
|
+
* @param {boolean} options.strict - Whether to use strict mode
|
|
97
|
+
* @param {boolean} options.logErrors - Whether to log errors
|
|
98
|
+
* @returns {object} Validated data or error
|
|
99
|
+
*/
|
|
100
|
+
export declare function validateResponse<T>(schema: z.ZodSchema<T>, data: unknown, options?: {
|
|
101
|
+
strict?: boolean;
|
|
102
|
+
logErrors?: boolean;
|
|
103
|
+
}): {
|
|
104
|
+
success: true;
|
|
105
|
+
data: T;
|
|
106
|
+
} | {
|
|
107
|
+
success: false;
|
|
108
|
+
error: z.ZodError;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Safe validation helper - returns data even if validation fails
|
|
112
|
+
* Used when strict mode is disabled
|
|
113
|
+
* @param {z.ZodSchema<T>} schema - Zod schema to validate against
|
|
114
|
+
* @param {unknown} data - Data to validate
|
|
115
|
+
* @param {boolean} logErrors - Whether to log errors
|
|
116
|
+
* @returns {T} Validated data or original data if validation fails in non-strict mode
|
|
117
|
+
*/
|
|
118
|
+
export declare function validateResponseSafe<T>(schema: z.ZodSchema<T>, data: unknown, logErrors?: boolean): T;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthEntitySchema = exports.UserEntitySchema = exports.AttributeSchema = exports.LocalizeInfoSchema = exports.ErrorSchema = void 0;
|
|
4
|
+
exports.createPaginatedSchema = createPaginatedSchema;
|
|
5
|
+
exports.validateResponse = validateResponse;
|
|
6
|
+
exports.validateResponseSafe = validateResponseSafe;
|
|
7
|
+
/* eslint-disable jsdoc/reject-any-type */
|
|
8
|
+
/* eslint-disable jsdoc/no-undefined-types */
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
/**
|
|
11
|
+
* Common validation schemas for API responses
|
|
12
|
+
* @description Base schemas that can be reused across different modules
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Error response schema
|
|
16
|
+
*/
|
|
17
|
+
exports.ErrorSchema = zod_1.z.object({
|
|
18
|
+
statusCode: zod_1.z.number(),
|
|
19
|
+
message: zod_1.z.string(),
|
|
20
|
+
localizeMessage: zod_1.z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Localize info schema
|
|
24
|
+
*/
|
|
25
|
+
exports.LocalizeInfoSchema = zod_1.z.object({
|
|
26
|
+
title: zod_1.z.string(),
|
|
27
|
+
content: zod_1.z.string().optional(),
|
|
28
|
+
menuTitle: zod_1.z.string().optional(),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Attribute schema
|
|
32
|
+
*/
|
|
33
|
+
exports.AttributeSchema = zod_1.z.object({
|
|
34
|
+
id: zod_1.z.number().optional(),
|
|
35
|
+
marker: zod_1.z.string(),
|
|
36
|
+
type: zod_1.z.string(),
|
|
37
|
+
isVisible: zod_1.z.boolean().optional(),
|
|
38
|
+
isRequired: zod_1.z.boolean().optional(),
|
|
39
|
+
position: zod_1.z.number().optional(),
|
|
40
|
+
localizeInfos: zod_1.z.record(zod_1.z.string(), exports.LocalizeInfoSchema).optional(),
|
|
41
|
+
value: zod_1.z.any().optional(),
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* User entity schema
|
|
45
|
+
*/
|
|
46
|
+
exports.UserEntitySchema = zod_1.z.object({
|
|
47
|
+
id: zod_1.z.number(),
|
|
48
|
+
identifier: zod_1.z.string().optional(),
|
|
49
|
+
email: zod_1.z.string().email().optional(),
|
|
50
|
+
phoneMask: zod_1.z.string().optional(),
|
|
51
|
+
phoneCode: zod_1.z.string().optional(),
|
|
52
|
+
phoneNumber: zod_1.z.string().optional(),
|
|
53
|
+
statusMarker: zod_1.z.string().optional(),
|
|
54
|
+
formData: zod_1.z
|
|
55
|
+
.union([zod_1.z.array(zod_1.z.any()), zod_1.z.record(zod_1.z.string(), zod_1.z.any())])
|
|
56
|
+
.optional(),
|
|
57
|
+
total: zod_1.z.union([zod_1.z.number(), zod_1.z.string()]).optional(),
|
|
58
|
+
authProviderIdentifier: zod_1.z.string().optional(),
|
|
59
|
+
formIdentifier: zod_1.z.string().optional(),
|
|
60
|
+
groups: zod_1.z.array(zod_1.z.number()).optional(),
|
|
61
|
+
state: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
|
|
62
|
+
moduleFormConfigs: zod_1.z.array(zod_1.z.any()).optional(),
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Auth entity schema
|
|
66
|
+
* API returns only accessToken and refreshToken
|
|
67
|
+
* userIdentifier and authProviderIdentifier are optional legacy fields
|
|
68
|
+
*/
|
|
69
|
+
exports.AuthEntitySchema = zod_1.z.object({
|
|
70
|
+
accessToken: zod_1.z.string(),
|
|
71
|
+
refreshToken: zod_1.z.string(),
|
|
72
|
+
userIdentifier: zod_1.z.string().optional(),
|
|
73
|
+
authProviderIdentifier: zod_1.z.string().optional(),
|
|
74
|
+
user: exports.UserEntitySchema.optional(),
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Paginated response schema factory
|
|
78
|
+
* @param {T} itemSchema - The schema for each item in the paginated response
|
|
79
|
+
* @returns {any} Paginated response schema
|
|
80
|
+
*/
|
|
81
|
+
function createPaginatedSchema(itemSchema) {
|
|
82
|
+
return zod_1.z.object({
|
|
83
|
+
items: zod_1.z.array(itemSchema),
|
|
84
|
+
total: zod_1.z.number(),
|
|
85
|
+
page: zod_1.z.number().optional(),
|
|
86
|
+
limit: zod_1.z.number().optional(),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validation helper function
|
|
91
|
+
* @param {z.ZodSchema<T>} schema - Zod schema to validate against
|
|
92
|
+
* @param {unknown} data - Data to validate
|
|
93
|
+
* @param {object} options - Validation options
|
|
94
|
+
* @param {boolean} options.strict - Whether to use strict mode
|
|
95
|
+
* @param {boolean} options.logErrors - Whether to log errors
|
|
96
|
+
* @returns {object} Validated data or error
|
|
97
|
+
*/
|
|
98
|
+
function validateResponse(schema, data, options) {
|
|
99
|
+
try {
|
|
100
|
+
const validated = schema.parse(data);
|
|
101
|
+
return { success: true, data: validated };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
105
|
+
if (options === null || options === void 0 ? void 0 : options.logErrors) {
|
|
106
|
+
// eslint-disable-next-line no-undef, no-console
|
|
107
|
+
console.error('Validation error:', {
|
|
108
|
+
errors: error.issues,
|
|
109
|
+
data,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return { success: false, error };
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Safe validation helper - returns data even if validation fails
|
|
119
|
+
* Used when strict mode is disabled
|
|
120
|
+
* @param {z.ZodSchema<T>} schema - Zod schema to validate against
|
|
121
|
+
* @param {unknown} data - Data to validate
|
|
122
|
+
* @param {boolean} logErrors - Whether to log errors
|
|
123
|
+
* @returns {T} Validated data or original data if validation fails in non-strict mode
|
|
124
|
+
*/
|
|
125
|
+
function validateResponseSafe(schema, data, logErrors = false) {
|
|
126
|
+
const result = validateResponse(schema, data, { logErrors });
|
|
127
|
+
if (result.success) {
|
|
128
|
+
return result.data;
|
|
129
|
+
}
|
|
130
|
+
// Return original data if validation fails in non-strict mode
|
|
131
|
+
return data;
|
|
132
|
+
}
|