@shushed/helpers 0.0.203 → 0.0.204
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/dist/cjs/src-public/airtable.js +1 -0
- package/dist/cjs/src-public/centra.js +38 -45
- package/dist/cjs/src-public/dato.js +10 -244
- package/dist/types/src-public/airtable.d.ts +1 -0
- package/dist/types/src-public/centra.d.ts +5 -7
- package/dist/types/src-public/dato.d.ts +1 -27
- package/package.json +1 -1
|
@@ -62,6 +62,7 @@ class AirtableHelper extends runtime_1.default {
|
|
|
62
62
|
fieldsToMergeOn: (options.fieldsToMergeOn ?? [this.primaryKeyFieldName]).map(x => this.dictionary[x] || x),
|
|
63
63
|
},
|
|
64
64
|
returnFieldsByFieldId: true,
|
|
65
|
+
typecast: options.typecast || false,
|
|
65
66
|
records: currentBatch.map(x => {
|
|
66
67
|
const recordId = x.$recordId;
|
|
67
68
|
const fieldsWithoutRecordId = { ...x };
|
|
@@ -73,6 +73,14 @@ class CentraHelper extends env_1.default {
|
|
|
73
73
|
errors.push(...userErrors.map((x) => ({ message: x.message, path: x.path })));
|
|
74
74
|
return { errors, limitExceeded: response.status === 429 };
|
|
75
75
|
}
|
|
76
|
+
if (resp.data && typeof resp.data === 'object') {
|
|
77
|
+
for (const key in resp.data) {
|
|
78
|
+
if (resp.data[key] && typeof resp.data[key] === 'object' && 'userErrors' in resp.data[key] && Array.isArray(resp.data[key].userErrors) && resp.data[key].userErrors.length > 0) {
|
|
79
|
+
errors.push(...resp.data[key].userErrors.map((x) => ({ message: x.message, path: x.path })));
|
|
80
|
+
return { errors, limitExceeded: response.status === 429 };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
76
84
|
}
|
|
77
85
|
if (response.status === 429) {
|
|
78
86
|
resp.limitExceeded = true;
|
|
@@ -323,7 +331,7 @@ class CentraHelper extends env_1.default {
|
|
|
323
331
|
} while (hasNextPage);
|
|
324
332
|
return result;
|
|
325
333
|
}
|
|
326
|
-
async fetchCentraMarkets(
|
|
334
|
+
async fetchCentraMarkets() {
|
|
327
335
|
const result = [];
|
|
328
336
|
const limit = 200;
|
|
329
337
|
let page = 0;
|
|
@@ -333,15 +341,15 @@ class CentraHelper extends env_1.default {
|
|
|
333
341
|
method: 'POST',
|
|
334
342
|
body: JSON.stringify({
|
|
335
343
|
query: `
|
|
336
|
-
query GetMarkets($limit: Int, $page: Int
|
|
337
|
-
markets(
|
|
344
|
+
query GetMarkets($limit: Int, $page: Int) {
|
|
345
|
+
markets(limit: $limit, page: $page) {
|
|
338
346
|
id
|
|
339
347
|
externalId
|
|
340
348
|
name
|
|
341
349
|
}
|
|
342
350
|
}
|
|
343
351
|
`,
|
|
344
|
-
variables: { page: page, limit: limit
|
|
352
|
+
variables: { page: page, limit: limit }
|
|
345
353
|
})
|
|
346
354
|
});
|
|
347
355
|
if (CentraHelper.isCentraErrors(data)) {
|
|
@@ -471,7 +479,7 @@ class CentraHelper extends env_1.default {
|
|
|
471
479
|
nextCursor = null;
|
|
472
480
|
}
|
|
473
481
|
if (data && data.data?.productConnection?.edges?.length) {
|
|
474
|
-
for (let i = data.data.productConnection.edges.length; i
|
|
482
|
+
for (let i = 0; i < data.data.productConnection.edges.length; i++) {
|
|
475
483
|
const { node } = data.data.productConnection.edges[i];
|
|
476
484
|
result[node.externalId] = node;
|
|
477
485
|
}
|
|
@@ -497,16 +505,15 @@ class CentraHelper extends env_1.default {
|
|
|
497
505
|
edges {
|
|
498
506
|
node {
|
|
499
507
|
id
|
|
500
|
-
externalId
|
|
501
508
|
status
|
|
502
|
-
|
|
509
|
+
uri
|
|
503
510
|
metaTitle
|
|
504
511
|
metaDescription
|
|
505
512
|
name
|
|
506
513
|
categories {
|
|
507
514
|
id
|
|
508
515
|
name
|
|
509
|
-
|
|
516
|
+
uri
|
|
510
517
|
isTopCategory
|
|
511
518
|
}
|
|
512
519
|
markets {
|
|
@@ -518,7 +525,7 @@ class CentraHelper extends env_1.default {
|
|
|
518
525
|
externalId
|
|
519
526
|
status
|
|
520
527
|
}
|
|
521
|
-
|
|
528
|
+
productVariants {
|
|
522
529
|
id
|
|
523
530
|
externalId
|
|
524
531
|
status
|
|
@@ -565,8 +572,8 @@ class CentraHelper extends env_1.default {
|
|
|
565
572
|
for (let i = 0; i < edges.length; i++) {
|
|
566
573
|
const { node } = edges[i];
|
|
567
574
|
if (inputIdType === 'variant') {
|
|
568
|
-
result[+node.
|
|
569
|
-
result[+node.
|
|
575
|
+
result[+node.productVariants[0].id] = [];
|
|
576
|
+
result[+node.productVariants[0].id].push(node);
|
|
570
577
|
}
|
|
571
578
|
else {
|
|
572
579
|
result[+node.product.id] = [];
|
|
@@ -790,59 +797,45 @@ class CentraHelper extends env_1.default {
|
|
|
790
797
|
}
|
|
791
798
|
return Object.assign({}, pricelistInCache, pricelistToSet);
|
|
792
799
|
}
|
|
793
|
-
async getCentraMarkets(
|
|
794
|
-
if (externalIds && !externalIds.length) {
|
|
795
|
-
return {};
|
|
796
|
-
}
|
|
800
|
+
async getCentraMarkets(alwaysFetch = false) {
|
|
797
801
|
let marketInCache = {};
|
|
798
|
-
let
|
|
802
|
+
let dedupedMarketNamesInCache = [];
|
|
799
803
|
let marketsToFetch = null;
|
|
800
804
|
if (!alwaysFetch) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
dedupedExternalIds = externalIds.filter((x, index, self) => self.indexOf(x) === index);
|
|
809
|
-
marketInCache = Object.fromEntries(Object.entries(await this.get(dedupedExternalIds.map(x => this.getCacheKeyForMarket(x)), 'env', {
|
|
805
|
+
const marketNamesInCache = (await this.get(this.getCacheKeyForMarkets(), 'env', {
|
|
806
|
+
isEphemeral: true,
|
|
807
|
+
encrypted: false,
|
|
808
|
+
}).then(x => x ? JSON.parse(x) : null));
|
|
809
|
+
if (marketNamesInCache) {
|
|
810
|
+
dedupedMarketNamesInCache = marketNamesInCache.filter((x, index, self) => self.indexOf(x) === index);
|
|
811
|
+
marketInCache = Object.fromEntries(Object.entries(await this.get(dedupedMarketNamesInCache.map(x => this.getCacheKeyForMarket(x)), 'env', {
|
|
810
812
|
isEphemeral: true,
|
|
811
813
|
encrypted: false,
|
|
812
814
|
})).map(([key, value]) => [key, value ? JSON.parse(value || 'null') : undefined]).filter(([_, value]) => value));
|
|
813
|
-
marketsToFetch =
|
|
815
|
+
marketsToFetch = dedupedMarketNamesInCache.filter(x => !marketInCache[x]);
|
|
814
816
|
}
|
|
815
817
|
}
|
|
816
818
|
const marketToSet = {};
|
|
817
819
|
if (!marketsToFetch || marketsToFetch.length) {
|
|
818
|
-
const markets = await this.fetchCentraMarkets(
|
|
820
|
+
const markets = await this.fetchCentraMarkets();
|
|
819
821
|
if (CentraHelper.isCentraErrors(markets)) {
|
|
820
|
-
|
|
821
|
-
for (const marketExternalId of marketsToFetch) {
|
|
822
|
-
marketToSet[marketExternalId] = new Error(`Failed to fetch market ${marketExternalId}: ${markets.errors.map((x) => x.message).join(', ')}`);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
else {
|
|
826
|
-
return new Error(`Failed to fetch markets: ${markets.errors.map((x) => x.message).join(', ')}`);
|
|
827
|
-
}
|
|
822
|
+
return new Error(`Failed to fetch markets: ${markets.errors.map((x) => x.message).join(', ')}`);
|
|
828
823
|
}
|
|
829
824
|
else {
|
|
830
825
|
for (const market of markets) {
|
|
831
|
-
marketToSet[market.
|
|
826
|
+
marketToSet[market.name] = market;
|
|
832
827
|
}
|
|
833
828
|
await this.set(Object.entries(marketToSet).filter(([_, value]) => !(value instanceof Error)).map(([key, value]) => ({ name: this.getCacheKeyForMarket(key), value: JSON.stringify(value) })), 'env', {
|
|
834
829
|
ephemeralMs: CACHE_EXPIRATION_MS,
|
|
835
830
|
encrypted: false,
|
|
836
831
|
});
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
});
|
|
845
|
-
}
|
|
832
|
+
await this.set([{
|
|
833
|
+
name: this.getCacheKeyForMarkets(),
|
|
834
|
+
value: JSON.stringify(Object.keys(marketToSet)),
|
|
835
|
+
}], 'env', {
|
|
836
|
+
ephemeralMs: CACHE_EXPIRATION_MS,
|
|
837
|
+
encrypted: false,
|
|
838
|
+
});
|
|
846
839
|
}
|
|
847
840
|
}
|
|
848
841
|
return Object.assign({}, marketInCache, marketToSet);
|
|
@@ -72,11 +72,6 @@ class DatoHelper extends runtime_1.default {
|
|
|
72
72
|
return response;
|
|
73
73
|
}
|
|
74
74
|
async createAssetFromUpload(uploadId, opts, uploadCollectionId) {
|
|
75
|
-
const normalizedTags = Array.isArray(opts.tags) && opts.tags.length > 0
|
|
76
|
-
? opts.tags
|
|
77
|
-
: ["integrations"];
|
|
78
|
-
const safeTitle = opts.title && opts.title.trim().length > 0 ? opts.title : "untitled";
|
|
79
|
-
const safeAlt = opts.alt && opts.alt.trim().length > 0 ? opts.alt : safeTitle;
|
|
80
75
|
const body = {
|
|
81
76
|
data: {
|
|
82
77
|
type: 'upload',
|
|
@@ -85,35 +80,13 @@ class DatoHelper extends runtime_1.default {
|
|
|
85
80
|
author: opts.author,
|
|
86
81
|
copyright: opts.copyright,
|
|
87
82
|
notes: opts.notes || null,
|
|
88
|
-
title: safeTitle,
|
|
89
|
-
alt: safeAlt,
|
|
90
83
|
default_field_metadata: {
|
|
91
|
-
"en-GB": {
|
|
92
|
-
title: safeTitle,
|
|
93
|
-
alt: safeAlt,
|
|
94
|
-
custom_data: {
|
|
95
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
96
|
-
tags: normalizedTags,
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
84
|
en: {
|
|
100
|
-
title:
|
|
101
|
-
alt:
|
|
102
|
-
custom_data: {
|
|
103
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
104
|
-
tags: normalizedTags,
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
"en-US": {
|
|
108
|
-
title: safeTitle,
|
|
109
|
-
alt: safeAlt,
|
|
110
|
-
custom_data: {
|
|
111
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
112
|
-
tags: normalizedTags,
|
|
113
|
-
}
|
|
85
|
+
title: opts.title,
|
|
86
|
+
alt: opts.alt,
|
|
114
87
|
}
|
|
115
88
|
},
|
|
116
|
-
tags:
|
|
89
|
+
tags: opts.tags || [],
|
|
117
90
|
},
|
|
118
91
|
},
|
|
119
92
|
};
|
|
@@ -182,119 +155,8 @@ class DatoHelper extends runtime_1.default {
|
|
|
182
155
|
this.logging.error(timeoutMsg);
|
|
183
156
|
throw new Error(timeoutMsg);
|
|
184
157
|
}
|
|
185
|
-
updateUpload = async (options) => {
|
|
186
|
-
try {
|
|
187
|
-
this.logging.log(`Starting update upload - ${JSON.stringify(options)}`);
|
|
188
|
-
if (!options.id)
|
|
189
|
-
throw new Error("updateUpload requires 'id' in options");
|
|
190
|
-
const safeTitle = options.title && options.title.trim().length > 0
|
|
191
|
-
? options.title.trim()
|
|
192
|
-
: options.filename?.trim().split(".")[0] || "untitled";
|
|
193
|
-
const safeAlt = options.alt && options.alt.trim().length > 0
|
|
194
|
-
? options.alt.trim()
|
|
195
|
-
: safeTitle;
|
|
196
|
-
const normalizedTags = Array.isArray(options.tags) && options.tags.length > 0
|
|
197
|
-
? options.tags
|
|
198
|
-
: ["integrations"];
|
|
199
|
-
const body = {
|
|
200
|
-
data: {
|
|
201
|
-
type: "upload",
|
|
202
|
-
id: options.id,
|
|
203
|
-
attributes: {
|
|
204
|
-
author: options.author,
|
|
205
|
-
copyright: options.copyright,
|
|
206
|
-
tags: normalizedTags,
|
|
207
|
-
notes: options.notes || null,
|
|
208
|
-
default_field_metadata: {
|
|
209
|
-
"en-GB": {
|
|
210
|
-
title: safeTitle,
|
|
211
|
-
alt: safeAlt,
|
|
212
|
-
custom_data: {
|
|
213
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
214
|
-
tags: normalizedTags,
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
en: {
|
|
218
|
-
title: safeTitle,
|
|
219
|
-
alt: safeAlt,
|
|
220
|
-
custom_data: {
|
|
221
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
222
|
-
tags: normalizedTags,
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
"en-US": {
|
|
226
|
-
title: safeTitle,
|
|
227
|
-
alt: safeAlt,
|
|
228
|
-
custom_data: {
|
|
229
|
-
source: normalizedTags[0] || "uploaded-by-integrations",
|
|
230
|
-
tags: normalizedTags,
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
};
|
|
237
|
-
if (options.uploadCollectionId) {
|
|
238
|
-
body.data.relationships = {
|
|
239
|
-
upload_collection: {
|
|
240
|
-
data: {
|
|
241
|
-
type: "upload_collection",
|
|
242
|
-
id: options.uploadCollectionId,
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
const response = await fetch(`${this.baseUrl}/uploads/${options.id}`, {
|
|
248
|
-
method: "PATCH",
|
|
249
|
-
headers: {
|
|
250
|
-
Authorization: `Bearer ${this.apiToken}`,
|
|
251
|
-
"X-Api-Version": "3",
|
|
252
|
-
"X-Environment": this.environment,
|
|
253
|
-
"Content-Type": "application/vnd.api+json",
|
|
254
|
-
Accept: "application/json",
|
|
255
|
-
},
|
|
256
|
-
body: JSON.stringify(body),
|
|
257
|
-
});
|
|
258
|
-
if (!response.ok) {
|
|
259
|
-
const errorText = await response.text();
|
|
260
|
-
this.logging.error(`Failed to update upload: ${response.statusText} - ${errorText}`);
|
|
261
|
-
throw new Error(`Failed to update upload: ${response.statusText} - ${errorText}`);
|
|
262
|
-
}
|
|
263
|
-
const updated = await response.json();
|
|
264
|
-
if (Array.isArray(updated.data) && updated.data[0]?.type === "api_error") {
|
|
265
|
-
const errorCode = updated.data[0].attributes?.code || "UNKNOWN_ERROR";
|
|
266
|
-
const errorMsg = `DatoCMS API error: ${errorCode}`;
|
|
267
|
-
this.logging.error(errorMsg);
|
|
268
|
-
throw new Error(errorMsg);
|
|
269
|
-
}
|
|
270
|
-
if (updated.data?.type === "job") {
|
|
271
|
-
this.logging.log(`Waiting for job completion: ${updated.data.id}`);
|
|
272
|
-
const jobPayload = await this.waitForJobCompletion(updated.data.id);
|
|
273
|
-
const assetId = jobPayload?.data?.id;
|
|
274
|
-
const assetUrl = jobPayload?.data?.attributes?.url;
|
|
275
|
-
if (!assetId || !assetUrl) {
|
|
276
|
-
throw new Error(`Job completed but payload missing expected fields: ${JSON.stringify(jobPayload)}`);
|
|
277
|
-
}
|
|
278
|
-
this.logging.log(`Job completed for upload: ${assetId}`);
|
|
279
|
-
return { success: true, assetId, upload: assetUrl };
|
|
280
|
-
}
|
|
281
|
-
if (updated.data?.type === "upload") {
|
|
282
|
-
const { id, attributes } = updated.data;
|
|
283
|
-
this.logging.log(`Upload updated successfully: ${id}`);
|
|
284
|
-
return { success: true, assetId: id, upload: attributes.url };
|
|
285
|
-
}
|
|
286
|
-
const errMsg = `Unexpected update response: ${JSON.stringify(updated)}`;
|
|
287
|
-
this.logging.error(errMsg);
|
|
288
|
-
throw new Error(errMsg);
|
|
289
|
-
}
|
|
290
|
-
catch (err) {
|
|
291
|
-
const msg = err?.message ?? JSON.stringify(err);
|
|
292
|
-
this.logging.error(`[updateUpload] failed: ${msg}`);
|
|
293
|
-
throw new Error(msg);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
158
|
async uploadFromUrl(options) {
|
|
297
|
-
const { url, filename, uploadCollectionId
|
|
159
|
+
const { url, filename, uploadCollectionId } = options;
|
|
298
160
|
this.logging.log(`Starting upload from URL: ${url}`);
|
|
299
161
|
const fileResponse = await fetch(url);
|
|
300
162
|
if (!fileResponse.ok) {
|
|
@@ -302,43 +164,9 @@ class DatoHelper extends runtime_1.default {
|
|
|
302
164
|
this.logging.error(errorMsg);
|
|
303
165
|
throw new Error(errorMsg);
|
|
304
166
|
}
|
|
305
|
-
let finalFilename = filename || path_1.default.basename(new URL(url).pathname) ||
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const urlObj = new URL(url);
|
|
309
|
-
const pathname = urlObj.pathname;
|
|
310
|
-
if (pathname.includes(".")) {
|
|
311
|
-
const urlExtension = path_1.default.extname(pathname);
|
|
312
|
-
if (urlExtension) {
|
|
313
|
-
finalFilename += urlExtension;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
if (!path_1.default.extname(finalFilename) && fileResponse.headers.has('content-type')) {
|
|
317
|
-
const ext = (0, mime_types_1.extension)(fileResponse.headers.get('content-type'));
|
|
318
|
-
if (typeof ext === "string" && ext.length > 0) {
|
|
319
|
-
finalFilename += `.${ext}`;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else if (!filename) {
|
|
324
|
-
if (!path_1.default.extname(finalFilename) && fileResponse.headers.has('content-type')) {
|
|
325
|
-
const ext = (0, mime_types_1.extension)(fileResponse.headers.get('content-type'));
|
|
326
|
-
if (typeof ext === "string" && ext.length > 0) {
|
|
327
|
-
finalFilename += `.${ext}`;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if (skipCreationIfAlreadyExists) {
|
|
332
|
-
const existing = await this.findUploadByFilename(finalFilename);
|
|
333
|
-
if (existing) {
|
|
334
|
-
this.logging.log(`Skipping upload: existing asset found for "${finalFilename}"`);
|
|
335
|
-
return {
|
|
336
|
-
success: true,
|
|
337
|
-
assetId: existing.id,
|
|
338
|
-
upload: existing.attributes.url,
|
|
339
|
-
skipped: true,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
167
|
+
let finalFilename = filename || path_1.default.basename(new URL(url).pathname) || 'bs-' + this.triggerId + '-' + new Date().getTime();
|
|
168
|
+
if (!path_1.default.extname(finalFilename) && fileResponse.headers.has('content-type')) {
|
|
169
|
+
finalFilename += `.${(0, mime_types_1.extension)(fileResponse.headers.get('content-type'))}`;
|
|
342
170
|
}
|
|
343
171
|
const uploadRequest = await this.requestUploadParameters(finalFilename);
|
|
344
172
|
const uploadId = uploadRequest.data.id;
|
|
@@ -355,7 +183,6 @@ class DatoHelper extends runtime_1.default {
|
|
|
355
183
|
success: true,
|
|
356
184
|
upload: assetPayload.data.attributes.url,
|
|
357
185
|
assetId: assetPayload.data.id,
|
|
358
|
-
skipped: false,
|
|
359
186
|
};
|
|
360
187
|
}
|
|
361
188
|
async uploadFromFile(options) {
|
|
@@ -437,14 +264,7 @@ class DatoHelper extends runtime_1.default {
|
|
|
437
264
|
}
|
|
438
265
|
async findUploadByFilename(filename) {
|
|
439
266
|
try {
|
|
440
|
-
|
|
441
|
-
this.logging.log(`findUploadByFilename called with invalid filename: ${String(filename)}`);
|
|
442
|
-
return null;
|
|
443
|
-
}
|
|
444
|
-
const normalizedTarget = filename.trim().toLowerCase().replace(/\.[^.]+$/, '');
|
|
445
|
-
const query = encodeURIComponent(normalizedTarget);
|
|
446
|
-
this.logging.log(`Searching uploads with query="${normalizedTarget}" for filename="${filename}"`);
|
|
447
|
-
const response = await fetch(`${this.baseUrl}/uploads?filter[query]=${query}&page[limit]=100`, {
|
|
267
|
+
const response = await fetch(`${this.baseUrl}/uploads?filter[filename]=${encodeURIComponent(filename)}`, {
|
|
448
268
|
headers: {
|
|
449
269
|
'Authorization': `Bearer ${this.apiToken}`,
|
|
450
270
|
'X-Api-Version': '3',
|
|
@@ -461,32 +281,10 @@ class DatoHelper extends runtime_1.default {
|
|
|
461
281
|
this.logging.error(`Failed to parse JSON in findUploadByFilename: ${err.message}`);
|
|
462
282
|
return null;
|
|
463
283
|
});
|
|
464
|
-
|
|
465
|
-
if (!uploads.length) {
|
|
466
|
-
this.logging.log(`No uploads returned for query="${normalizedTarget}"`);
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
const targetFull = filename.trim().toLowerCase();
|
|
470
|
-
const match = uploads.find((u) => {
|
|
471
|
-
const storedFull = u?.attributes?.filename?.toLowerCase();
|
|
472
|
-
if (!storedFull)
|
|
473
|
-
return false;
|
|
474
|
-
if (storedFull === targetFull)
|
|
475
|
-
return true;
|
|
476
|
-
const storedNormalized = storedFull.replace(/\.[^.]+$/, '');
|
|
477
|
-
if (storedNormalized === normalizedTarget)
|
|
478
|
-
return true;
|
|
479
|
-
return false;
|
|
480
|
-
});
|
|
481
|
-
if (match) {
|
|
482
|
-
this.logging.log(`Found existing upload for "${filename}" -> asset_id=${match.id}, storedFilename=${match.attributes?.filename}`);
|
|
483
|
-
return match;
|
|
484
|
-
}
|
|
485
|
-
this.logging.log(`No exact filename match found among ${uploads.length} uploads for "${filename}" (query="${normalizedTarget}")`);
|
|
486
|
-
return null;
|
|
284
|
+
return data?.data?.[0] || null;
|
|
487
285
|
}
|
|
488
286
|
catch (err) {
|
|
489
|
-
this.logging.error(`Error in findUploadByFilename: ${err
|
|
287
|
+
this.logging.error(`Error in findUploadByFilename: ${err.message}`);
|
|
490
288
|
return null;
|
|
491
289
|
}
|
|
492
290
|
}
|
|
@@ -601,37 +399,5 @@ class DatoHelper extends runtime_1.default {
|
|
|
601
399
|
throw err;
|
|
602
400
|
}
|
|
603
401
|
}
|
|
604
|
-
async updateProductSwatch(productId, uploadId) {
|
|
605
|
-
try {
|
|
606
|
-
const res = await fetch(`${this.baseUrl}/items/${productId}`, {
|
|
607
|
-
method: "PATCH",
|
|
608
|
-
headers: {
|
|
609
|
-
Authorization: `Bearer ${this.apiToken}`,
|
|
610
|
-
"X-Api-Version": "3",
|
|
611
|
-
"X-Environment": this.environment,
|
|
612
|
-
"Content-Type": "application/vnd.api+json",
|
|
613
|
-
Accept: "application/json",
|
|
614
|
-
},
|
|
615
|
-
body: JSON.stringify({
|
|
616
|
-
data: {
|
|
617
|
-
type: "item",
|
|
618
|
-
id: productId,
|
|
619
|
-
attributes: {
|
|
620
|
-
swatch: { upload_id: uploadId },
|
|
621
|
-
},
|
|
622
|
-
},
|
|
623
|
-
}),
|
|
624
|
-
});
|
|
625
|
-
if (!res.ok) {
|
|
626
|
-
const errorText = await res.text();
|
|
627
|
-
throw new Error(`Failed to update product swatch: ${res.status} ${res.statusText} - ${errorText}`);
|
|
628
|
-
}
|
|
629
|
-
return await res.json();
|
|
630
|
-
}
|
|
631
|
-
catch (err) {
|
|
632
|
-
this.logging.error(`updateProductSwatch failed: ${err.message}`);
|
|
633
|
-
throw err;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
402
|
}
|
|
637
403
|
exports.default = DatoHelper;
|
|
@@ -44,6 +44,7 @@ declare class AirtableHelper<T extends Record<string, string>, K extends keyof T
|
|
|
44
44
|
}>, options?: {
|
|
45
45
|
fieldsToMergeOn?: Array<keyof T>;
|
|
46
46
|
primaryKeyWritable?: boolean;
|
|
47
|
+
typecast?: boolean;
|
|
47
48
|
}, callIdx?: number, collectedResult?: {
|
|
48
49
|
updatedRecords: Array<string>;
|
|
49
50
|
createdRecords: Array<string>;
|
|
@@ -19,19 +19,18 @@ export type BasicCentraProduct = {
|
|
|
19
19
|
export type BasicCentraDisplay = {
|
|
20
20
|
id: number;
|
|
21
21
|
name: string;
|
|
22
|
-
externalId: string;
|
|
23
22
|
status: string;
|
|
24
|
-
|
|
23
|
+
uri: string;
|
|
25
24
|
metaTitle: string;
|
|
26
25
|
metaDescription: string;
|
|
27
26
|
categories: {
|
|
28
27
|
id: number;
|
|
29
28
|
name: string;
|
|
30
|
-
|
|
29
|
+
uri: string;
|
|
31
30
|
isTopCategory: boolean;
|
|
32
31
|
}[];
|
|
33
32
|
markets: BasicCentraMarket[];
|
|
34
|
-
|
|
33
|
+
productVariants: Array<{
|
|
35
34
|
id: number;
|
|
36
35
|
externalId: string;
|
|
37
36
|
status: string;
|
|
@@ -77,7 +76,6 @@ export type BasicCentraCountry = {
|
|
|
77
76
|
export type BasicCentraMarket = {
|
|
78
77
|
id: number;
|
|
79
78
|
name: string;
|
|
80
|
-
externalId: string;
|
|
81
79
|
};
|
|
82
80
|
export type BasicCentraVariant = {
|
|
83
81
|
id: number;
|
|
@@ -158,14 +156,14 @@ export default class CentraHelper extends EnvEngine {
|
|
|
158
156
|
fetchCentraWarehouses(externalIds?: string[] | undefined | null): Promise<CentraErrors | Array<BasicCentraWarehouse>>;
|
|
159
157
|
fetchCentraCampaigns(names?: string[] | undefined | null): Promise<CentraErrors | Record<string, BasicCentraCampaign | Error>>;
|
|
160
158
|
fetchPricelists(names?: string[] | undefined | null): Promise<CentraErrors | Array<BasicPricelist>>;
|
|
161
|
-
fetchCentraMarkets(
|
|
159
|
+
fetchCentraMarkets(): Promise<CentraErrors | Array<BasicCentraMarket>>;
|
|
162
160
|
fetchCentraSizeCharts(externalIds?: string[] | undefined | null): Promise<CentraErrors | Array<BasicCentraSizeChart>>;
|
|
163
161
|
private fetchCentraProducts;
|
|
164
162
|
private fetchCentraDisplays;
|
|
165
163
|
private fetchCentraVariants;
|
|
166
164
|
getCentraWarehouses(externalIds?: string[] | null | undefined, alwaysFetch?: boolean): Promise<Error | Record<string, Error | BasicCentraWarehouse>>;
|
|
167
165
|
getCentraPricelists(names?: string[] | null | undefined, alwaysFetch?: boolean): Promise<Error | Record<string, Error | BasicPricelist>>;
|
|
168
|
-
getCentraMarkets(
|
|
166
|
+
getCentraMarkets(alwaysFetch?: boolean): Promise<Error | Record<string, Error | BasicCentraMarket>>;
|
|
169
167
|
getCentraCountries(iso2Codes?: string[] | null | undefined, alwaysFetch?: boolean): Promise<Error | Record<string, Error | BasicCentraCountry>>;
|
|
170
168
|
getCentraSizeCharts(externalIds?: string[] | null | undefined, alwaysFetch?: boolean): Promise<Error | Record<string, Error | BasicCentraSizeChart>>;
|
|
171
169
|
getCentraProducts(styleIds: string[]): Promise<Error | Record<string, Error | BasicCentraProduct>>;
|
|
@@ -8,16 +8,6 @@ interface UploadResult {
|
|
|
8
8
|
success: boolean;
|
|
9
9
|
upload: string;
|
|
10
10
|
assetId?: string;
|
|
11
|
-
skipped?: boolean;
|
|
12
|
-
}
|
|
13
|
-
interface UploadReturn {
|
|
14
|
-
id: string;
|
|
15
|
-
type: string;
|
|
16
|
-
attributes: {
|
|
17
|
-
url: string;
|
|
18
|
-
filename: string;
|
|
19
|
-
[key: string]: any;
|
|
20
|
-
};
|
|
21
11
|
}
|
|
22
12
|
export default class DatoHelper extends Runtime {
|
|
23
13
|
private apiToken;
|
|
@@ -29,21 +19,6 @@ export default class DatoHelper extends Runtime {
|
|
|
29
19
|
private createAssetFromUpload;
|
|
30
20
|
private checkJobResult;
|
|
31
21
|
private waitForJobCompletion;
|
|
32
|
-
updateUpload: (options: {
|
|
33
|
-
id: string;
|
|
34
|
-
filename?: string;
|
|
35
|
-
tags: string[];
|
|
36
|
-
notes?: string;
|
|
37
|
-
title: string;
|
|
38
|
-
alt: string;
|
|
39
|
-
author: string;
|
|
40
|
-
copyright: string;
|
|
41
|
-
uploadCollectionId?: string;
|
|
42
|
-
}) => Promise<{
|
|
43
|
-
success: boolean;
|
|
44
|
-
assetId: string;
|
|
45
|
-
upload: string;
|
|
46
|
-
}>;
|
|
47
22
|
uploadFromUrl(options: {
|
|
48
23
|
url: string;
|
|
49
24
|
copyright: string;
|
|
@@ -78,11 +53,10 @@ export default class DatoHelper extends Runtime {
|
|
|
78
53
|
quality?: number;
|
|
79
54
|
format?: 'jpg' | 'pjpg' | 'png' | 'webp' | 'avif' | 'gif' | 'jxl' | 'jp2' | 'jxr' | 'json' | 'blurhash' | (string & {});
|
|
80
55
|
}): string;
|
|
81
|
-
findUploadByFilename(filename: string): Promise<
|
|
56
|
+
findUploadByFilename(filename: string): Promise<any>;
|
|
82
57
|
getItemTypeId(apiKey: string): Promise<string>;
|
|
83
58
|
getProductBySku(sku: string): Promise<any>;
|
|
84
59
|
createProduct(sku: string, productTypeId: string): Promise<any>;
|
|
85
60
|
updateProductGallery(productId: string, gallery: any[]): Promise<any>;
|
|
86
|
-
updateProductSwatch(productId: string, uploadId: string): Promise<any>;
|
|
87
61
|
}
|
|
88
62
|
export {};
|