@shushed/helpers 0.0.200-v2-20251128093319 → 0.0.200
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/index.d.ts +34970 -0
- package/dist/index.js +113017 -0
- package/dist/package.json +3 -6
- package/package.json +4 -7
- package/dist/cjs/dist-dereferenced/asset.js +0 -4
- package/dist/cjs/dist-dereferenced/category.js +0 -4
- package/dist/cjs/dist-dereferenced/country.js +0 -4
- package/dist/cjs/dist-dereferenced/currency.js +0 -4
- package/dist/cjs/dist-dereferenced/customer-segment.js +0 -4
- package/dist/cjs/dist-dereferenced/development-colour.js +0 -4
- package/dist/cjs/dist-dereferenced/index.js +0 -69
- package/dist/cjs/dist-dereferenced/marketing-preferences.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/ean-change.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/index.js +0 -50
- package/dist/cjs/dist-dereferenced/messages/order/delivered.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/order/index.js +0 -18
- package/dist/cjs/dist-dereferenced/messages/order/new.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/order/processed.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/order/return-initiated.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/order/returned.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/order/shipped.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/price-change.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/product-category.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/product-draft.js +0 -4
- package/dist/cjs/dist-dereferenced/messages/product.js +0 -4
- package/dist/cjs/dist-dereferenced/money.js +0 -4
- package/dist/cjs/dist-dereferenced/order/address.js +0 -4
- package/dist/cjs/dist-dereferenced/order/customer.js +0 -4
- package/dist/cjs/dist-dereferenced/order/index.js +0 -51
- package/dist/cjs/dist-dereferenced/order/item.js +0 -4
- package/dist/cjs/dist-dereferenced/order/orderMain.js +0 -4
- package/dist/cjs/dist-dereferenced/order/payment.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/index.js +0 -45
- package/dist/cjs/dist-dereferenced/order/shipment/item/index.js +0 -11
- package/dist/cjs/dist-dereferenced/order/shipment/item/itemMain.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/item/returned.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/pos/index.js +0 -13
- package/dist/cjs/dist-dereferenced/order/shipment/pos/outbound.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/pos/posMain.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/pos/return.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/shipmentMain.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/shipped/index.js +0 -13
- package/dist/cjs/dist-dereferenced/order/shipment/shipped/outbound.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/shipped/return.js +0 -4
- package/dist/cjs/dist-dereferenced/order/shipment/shipped/shippedMain.js +0 -4
- package/dist/cjs/dist-dereferenced/price.js +0 -4
- package/dist/cjs/dist-dereferenced/product-category.js +0 -4
- package/dist/cjs/dist-dereferenced/product-draft.js +0 -4
- package/dist/cjs/dist-dereferenced/product.js +0 -4
- package/dist/cjs/dist-dereferenced/stock.js +0 -4
- package/dist/cjs/dist-dereferenced/total.js +0 -4
- package/dist/cjs/dist-types/asset.js +0 -2
- package/dist/cjs/dist-types/category.js +0 -2
- package/dist/cjs/dist-types/country.js +0 -2
- package/dist/cjs/dist-types/currency.js +0 -2
- package/dist/cjs/dist-types/customer-segment.js +0 -2
- package/dist/cjs/dist-types/development-colour.js +0 -2
- package/dist/cjs/dist-types/index.js +0 -38
- package/dist/cjs/dist-types/marketing-preferences.js +0 -2
- package/dist/cjs/dist-types/messages/ean-change.js +0 -2
- package/dist/cjs/dist-types/messages/index.js +0 -37
- package/dist/cjs/dist-types/messages/order/delivered.js +0 -2
- package/dist/cjs/dist-types/messages/order/index.js +0 -2
- package/dist/cjs/dist-types/messages/order/new.js +0 -2
- package/dist/cjs/dist-types/messages/order/processed.js +0 -2
- package/dist/cjs/dist-types/messages/order/return-initiated.js +0 -2
- package/dist/cjs/dist-types/messages/order/returned.js +0 -2
- package/dist/cjs/dist-types/messages/order/shipped.js +0 -2
- package/dist/cjs/dist-types/messages/price-change.js +0 -2
- package/dist/cjs/dist-types/messages/product-category.js +0 -2
- package/dist/cjs/dist-types/messages/product-draft.js +0 -2
- package/dist/cjs/dist-types/messages/product.js +0 -2
- package/dist/cjs/dist-types/money.js +0 -2
- package/dist/cjs/dist-types/order/address.js +0 -2
- package/dist/cjs/dist-types/order/customer.js +0 -2
- package/dist/cjs/dist-types/order/index.js +0 -37
- package/dist/cjs/dist-types/order/item.js +0 -2
- package/dist/cjs/dist-types/order/orderMain.js +0 -2
- package/dist/cjs/dist-types/order/payment.js +0 -2
- package/dist/cjs/dist-types/order/shipment/index.js +0 -39
- package/dist/cjs/dist-types/order/shipment/item/index.js +0 -2
- package/dist/cjs/dist-types/order/shipment/item/itemMain.js +0 -2
- package/dist/cjs/dist-types/order/shipment/item/returned.js +0 -2
- package/dist/cjs/dist-types/order/shipment/pos/index.js +0 -2
- package/dist/cjs/dist-types/order/shipment/pos/outbound.js +0 -2
- package/dist/cjs/dist-types/order/shipment/pos/posMain.js +0 -2
- package/dist/cjs/dist-types/order/shipment/pos/return.js +0 -2
- package/dist/cjs/dist-types/order/shipment/shipmentMain.js +0 -2
- package/dist/cjs/dist-types/order/shipment/shipped/index.js +0 -2
- package/dist/cjs/dist-types/order/shipment/shipped/outbound.js +0 -2
- package/dist/cjs/dist-types/order/shipment/shipped/return.js +0 -2
- package/dist/cjs/dist-types/order/shipment/shipped/shippedMain.js +0 -2
- package/dist/cjs/dist-types/price.js +0 -2
- package/dist/cjs/dist-types/product-category.js +0 -2
- package/dist/cjs/dist-types/product-draft.js +0 -2
- package/dist/cjs/dist-types/product.js +0 -2
- package/dist/cjs/dist-types/stock.js +0 -2
- package/dist/cjs/dist-types/total.js +0 -2
- package/dist/cjs/index.js +0 -39
- package/dist/cjs/src-public/airtable.js +0 -590
- package/dist/cjs/src-public/bigquery.js +0 -59
- package/dist/cjs/src-public/cloudtasks.js +0 -207
- package/dist/cjs/src-public/dato.js +0 -680
- package/dist/cjs/src-public/env.js +0 -897
- package/dist/cjs/src-public/getEventTime.js +0 -28
- package/dist/cjs/src-public/index.js +0 -50
- package/dist/cjs/src-public/ipValidation.js +0 -167
- package/dist/cjs/src-public/jwks.js +0 -108
- package/dist/cjs/src-public/pubsub.js +0 -423
- package/dist/cjs/src-public/rateLimit.js +0 -140
- package/dist/cjs/src-public/redisClient.js +0 -44
- package/dist/cjs/src-public/runtime.js +0 -141
- package/dist/cjs/src-public/sanitize.js +0 -25
- package/dist/cjs/src-public/scheduler.js +0 -247
- package/dist/cjs/src-public/secret.js +0 -16
- package/dist/cjs/src-public/setHeaders.js +0 -16
- package/dist/cjs/src-public/types.js +0 -2
- package/dist/cjs/src-public/utils.js +0 -454
- package/dist/cjs/src-public/validate.js +0 -40
- package/dist/types/dist-dereferenced/asset.d.ts +0 -51
- package/dist/types/dist-dereferenced/category.d.ts +0 -58
- package/dist/types/dist-dereferenced/country.d.ts +0 -8
- package/dist/types/dist-dereferenced/currency.d.ts +0 -8
- package/dist/types/dist-dereferenced/customer-segment.d.ts +0 -26
- package/dist/types/dist-dereferenced/development-colour.d.ts +0 -114
- package/dist/types/dist-dereferenced/index.d.ts +0 -16
- package/dist/types/dist-dereferenced/marketing-preferences.d.ts +0 -31
- package/dist/types/dist-dereferenced/messages/ean-change.d.ts +0 -17
- package/dist/types/dist-dereferenced/messages/index.d.ts +0 -6
- package/dist/types/dist-dereferenced/messages/order/delivered.d.ts +0 -3414
- package/dist/types/dist-dereferenced/messages/order/index.d.ts +0 -6
- package/dist/types/dist-dereferenced/messages/order/new.d.ts +0 -3414
- package/dist/types/dist-dereferenced/messages/order/processed.d.ts +0 -3408
- package/dist/types/dist-dereferenced/messages/order/return-initiated.d.ts +0 -3414
- package/dist/types/dist-dereferenced/messages/order/returned.d.ts +0 -3413
- package/dist/types/dist-dereferenced/messages/order/shipped.d.ts +0 -3412
- package/dist/types/dist-dereferenced/messages/price-change.d.ts +0 -67
- package/dist/types/dist-dereferenced/messages/product-category.d.ts +0 -33
- package/dist/types/dist-dereferenced/messages/product-draft.d.ts +0 -589
- package/dist/types/dist-dereferenced/messages/product.d.ts +0 -628
- package/dist/types/dist-dereferenced/money.d.ts +0 -41
- package/dist/types/dist-dereferenced/order/address.d.ts +0 -98
- package/dist/types/dist-dereferenced/order/customer.d.ts +0 -309
- package/dist/types/dist-dereferenced/order/index.d.ts +0 -3404
- package/dist/types/dist-dereferenced/order/item.d.ts +0 -336
- package/dist/types/dist-dereferenced/order/orderMain.d.ts +0 -3399
- package/dist/types/dist-dereferenced/order/payment.d.ts +0 -94
- package/dist/types/dist-dereferenced/order/shipment/index.d.ts +0 -253
- package/dist/types/dist-dereferenced/order/shipment/item/index.d.ts +0 -19
- package/dist/types/dist-dereferenced/order/shipment/item/itemMain.d.ts +0 -18
- package/dist/types/dist-dereferenced/order/shipment/item/returned.d.ts +0 -34
- package/dist/types/dist-dereferenced/order/shipment/pos/index.d.ts +0 -282
- package/dist/types/dist-dereferenced/order/shipment/pos/outbound.d.ts +0 -320
- package/dist/types/dist-dereferenced/order/shipment/pos/posMain.d.ts +0 -280
- package/dist/types/dist-dereferenced/order/shipment/pos/return.d.ts +0 -331
- package/dist/types/dist-dereferenced/order/shipment/shipmentMain.d.ts +0 -250
- package/dist/types/dist-dereferenced/order/shipment/shipped/index.d.ts +0 -288
- package/dist/types/dist-dereferenced/order/shipment/shipped/outbound.d.ts +0 -286
- package/dist/types/dist-dereferenced/order/shipment/shipped/return.d.ts +0 -287
- package/dist/types/dist-dereferenced/order/shipment/shipped/shippedMain.d.ts +0 -286
- package/dist/types/dist-dereferenced/price.d.ts +0 -58
- package/dist/types/dist-dereferenced/product-category.d.ts +0 -24
- package/dist/types/dist-dereferenced/product-draft.d.ts +0 -580
- package/dist/types/dist-dereferenced/product.d.ts +0 -619
- package/dist/types/dist-dereferenced/stock.d.ts +0 -74
- package/dist/types/dist-dereferenced/total.d.ts +0 -172
- package/dist/types/dist-types/asset.d.ts +0 -16
- package/dist/types/dist-types/category.d.ts +0 -20
- package/dist/types/dist-types/country.d.ts +0 -2
- package/dist/types/dist-types/currency.d.ts +0 -2
- package/dist/types/dist-types/customer-segment.d.ts +0 -6
- package/dist/types/dist-types/development-colour.d.ts +0 -31
- package/dist/types/dist-types/index.d.ts +0 -16
- package/dist/types/dist-types/marketing-preferences.d.ts +0 -9
- package/dist/types/dist-types/messages/ean-change.d.ts +0 -5
- package/dist/types/dist-types/messages/index.d.ts +0 -6
- package/dist/types/dist-types/messages/order/delivered.d.ts +0 -292
- package/dist/types/dist-types/messages/order/index.d.ts +0 -6
- package/dist/types/dist-types/messages/order/new.d.ts +0 -292
- package/dist/types/dist-types/messages/order/processed.d.ts +0 -292
- package/dist/types/dist-types/messages/order/return-initiated.d.ts +0 -292
- package/dist/types/dist-types/messages/order/returned.d.ts +0 -293
- package/dist/types/dist-types/messages/order/shipped.d.ts +0 -293
- package/dist/types/dist-types/messages/price-change.d.ts +0 -16
- package/dist/types/dist-types/messages/product-category.d.ts +0 -7
- package/dist/types/dist-types/messages/product-draft.d.ts +0 -136
- package/dist/types/dist-types/messages/product.d.ts +0 -144
- package/dist/types/dist-types/money.d.ts +0 -11
- package/dist/types/dist-types/order/address.d.ts +0 -27
- package/dist/types/dist-types/order/customer.d.ts +0 -81
- package/dist/types/dist-types/order/index.d.ts +0 -8
- package/dist/types/dist-types/order/item.d.ts +0 -85
- package/dist/types/dist-types/order/orderMain.d.ts +0 -289
- package/dist/types/dist-types/order/payment.d.ts +0 -26
- package/dist/types/dist-types/order/shipment/index.d.ts +0 -6
- package/dist/types/dist-types/order/shipment/item/index.d.ts +0 -4
- package/dist/types/dist-types/order/shipment/item/itemMain.d.ts +0 -6
- package/dist/types/dist-types/order/shipment/item/returned.d.ts +0 -11
- package/dist/types/dist-types/order/shipment/pos/index.d.ts +0 -5
- package/dist/types/dist-types/order/shipment/pos/outbound.d.ts +0 -76
- package/dist/types/dist-types/order/shipment/pos/posMain.d.ts +0 -71
- package/dist/types/dist-types/order/shipment/pos/return.d.ts +0 -75
- package/dist/types/dist-types/order/shipment/shipmentMain.d.ts +0 -62
- package/dist/types/dist-types/order/shipment/shipped/index.d.ts +0 -5
- package/dist/types/dist-types/order/shipment/shipped/outbound.d.ts +0 -68
- package/dist/types/dist-types/order/shipment/shipped/return.d.ts +0 -68
- package/dist/types/dist-types/order/shipment/shipped/shippedMain.d.ts +0 -69
- package/dist/types/dist-types/price.d.ts +0 -15
- package/dist/types/dist-types/product-category.d.ts +0 -6
- package/dist/types/dist-types/product-draft.d.ts +0 -135
- package/dist/types/dist-types/product.d.ts +0 -143
- package/dist/types/dist-types/stock.d.ts +0 -19
- package/dist/types/dist-types/total.d.ts +0 -44
- package/dist/types/index.d.ts +0 -3
- package/dist/types/src-public/airtable.d.ts +0 -220
- package/dist/types/src-public/bigquery.d.ts +0 -17
- package/dist/types/src-public/cloudtasks.d.ts +0 -74
- package/dist/types/src-public/dato.d.ts +0 -95
- package/dist/types/src-public/env.d.ts +0 -144
- package/dist/types/src-public/getEventTime.d.ts +0 -1
- package/dist/types/src-public/index.d.ts +0 -16
- package/dist/types/src-public/ipValidation.d.ts +0 -15
- package/dist/types/src-public/jwks.d.ts +0 -15
- package/dist/types/src-public/pubsub.d.ts +0 -95
- package/dist/types/src-public/rateLimit.d.ts +0 -21
- package/dist/types/src-public/redisClient.d.ts +0 -6
- package/dist/types/src-public/runtime.d.ts +0 -57
- package/dist/types/src-public/sanitize.d.ts +0 -4
- package/dist/types/src-public/scheduler.d.ts +0 -71
- package/dist/types/src-public/secret.d.ts +0 -6
- package/dist/types/src-public/setHeaders.d.ts +0 -13
- package/dist/types/src-public/types.d.ts +0 -264
- package/dist/types/src-public/utils.d.ts +0 -101
- package/dist/types/src-public/validate.d.ts +0 -9
|
@@ -1,590 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
-
const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
|
|
8
|
-
const runtime_1 = __importDefault(require("./runtime"));
|
|
9
|
-
class AirtableHelper extends runtime_1.default {
|
|
10
|
-
baseId;
|
|
11
|
-
tableId;
|
|
12
|
-
apiKey;
|
|
13
|
-
dictionary;
|
|
14
|
-
primaryKeyFieldName;
|
|
15
|
-
primaryKeyWritable = true;
|
|
16
|
-
constructor(opts, airtableOpts) {
|
|
17
|
-
super(opts);
|
|
18
|
-
this.baseId = airtableOpts.baseId;
|
|
19
|
-
this.tableId = airtableOpts.tableId;
|
|
20
|
-
this.apiKey = airtableOpts.apiKey;
|
|
21
|
-
this.primaryKeyFieldName = airtableOpts.primaryKeyFieldName;
|
|
22
|
-
this.dictionary = airtableOpts.dictionary;
|
|
23
|
-
if (typeof airtableOpts.primaryKeyWritable !== 'undefined') {
|
|
24
|
-
this.primaryKeyWritable = airtableOpts.primaryKeyWritable;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
static translateFields(dictionary, y) {
|
|
28
|
-
const nextFields = {};
|
|
29
|
-
for (const k in dictionary) {
|
|
30
|
-
const v = dictionary[k];
|
|
31
|
-
nextFields[k] = y.fields[v];
|
|
32
|
-
}
|
|
33
|
-
const nextObj = Object.assign({}, y, {
|
|
34
|
-
fields: nextFields
|
|
35
|
-
});
|
|
36
|
-
return nextObj;
|
|
37
|
-
}
|
|
38
|
-
async createIfNotExist(payload) {
|
|
39
|
-
const existingRecord = await this.getExistingRecord(payload);
|
|
40
|
-
if (!existingRecord) {
|
|
41
|
-
return this.createRecord(this.primaryKeyWritable === false ? AirtableHelper.removePrimaryKey(payload, this.primaryKeyFieldName) : payload);
|
|
42
|
-
}
|
|
43
|
-
return existingRecord;
|
|
44
|
-
}
|
|
45
|
-
async updateMultiple(payload, options = {}, callIdx = 0, collectedResult = {
|
|
46
|
-
updatedRecords: [],
|
|
47
|
-
createdRecords: [],
|
|
48
|
-
records: []
|
|
49
|
-
}) {
|
|
50
|
-
let response = null;
|
|
51
|
-
const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}`;
|
|
52
|
-
const currentBatch = payload.slice(callIdx * 10, (callIdx + 1) * 10);
|
|
53
|
-
try {
|
|
54
|
-
response = await fetch(`${tableUrl}`, {
|
|
55
|
-
method: "PATCH",
|
|
56
|
-
headers: {
|
|
57
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
58
|
-
"Content-Type": "application/json",
|
|
59
|
-
},
|
|
60
|
-
body: JSON.stringify({
|
|
61
|
-
performUpsert: {
|
|
62
|
-
fieldsToMergeOn: (options.fieldsToMergeOn ?? [this.primaryKeyFieldName]).map(x => this.dictionary[x] || x),
|
|
63
|
-
},
|
|
64
|
-
returnFieldsByFieldId: true,
|
|
65
|
-
records: currentBatch.map(x => {
|
|
66
|
-
const recordId = x.$recordId;
|
|
67
|
-
const fieldsWithoutRecordId = { ...x };
|
|
68
|
-
delete fieldsWithoutRecordId.$recordId;
|
|
69
|
-
const record = {
|
|
70
|
-
fields: AirtableHelper.convertToDictionary(this.dictionary, this.primaryKeyWritable === false
|
|
71
|
-
? AirtableHelper.removePrimaryKey(fieldsWithoutRecordId, this.primaryKeyFieldName)
|
|
72
|
-
: fieldsWithoutRecordId),
|
|
73
|
-
};
|
|
74
|
-
if (recordId) {
|
|
75
|
-
record.id = recordId;
|
|
76
|
-
}
|
|
77
|
-
return record;
|
|
78
|
-
})
|
|
79
|
-
}),
|
|
80
|
-
});
|
|
81
|
-
if (!response.ok && response) {
|
|
82
|
-
const text = await response.text().catch(() => `${response?.status || 'unknown'}`);
|
|
83
|
-
throw new Error(text);
|
|
84
|
-
}
|
|
85
|
-
const resp = (await response.json());
|
|
86
|
-
const nextCollectedResult = {
|
|
87
|
-
updatedRecords: collectedResult.updatedRecords.concat(resp.updatedRecords),
|
|
88
|
-
createdRecords: collectedResult.createdRecords.concat(resp.createdRecords),
|
|
89
|
-
records: collectedResult.records.concat(resp.records.map(x => AirtableHelper.translateFields(this.dictionary, x)))
|
|
90
|
-
};
|
|
91
|
-
if (payload.length > (callIdx + 1) * 10) {
|
|
92
|
-
return this.updateMultiple(payload, options, callIdx + 1, nextCollectedResult);
|
|
93
|
-
}
|
|
94
|
-
return nextCollectedResult;
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
const errorMessage = `Failed to update records in ${this.tableId} table (baseId: ${this.baseId}). Status: ${response?.status || 'unknown'}. Error: ${err.message}`;
|
|
98
|
-
const batchErrors = currentBatch.map(() => new Error(errorMessage));
|
|
99
|
-
const nextCollectedResult = {
|
|
100
|
-
updatedRecords: collectedResult.updatedRecords,
|
|
101
|
-
createdRecords: collectedResult.createdRecords,
|
|
102
|
-
records: collectedResult.records.concat(batchErrors)
|
|
103
|
-
};
|
|
104
|
-
if (payload.length > (callIdx + 1) * 10) {
|
|
105
|
-
return this.updateMultiple(payload, options, callIdx + 1, nextCollectedResult);
|
|
106
|
-
}
|
|
107
|
-
return nextCollectedResult;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
async upsert(payload) {
|
|
111
|
-
const existingRecord = await this.getExistingRecord(payload);
|
|
112
|
-
if (existingRecord) {
|
|
113
|
-
return this.updateRecord(existingRecord.id, payload);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
return this.createRecord(this.primaryKeyWritable === false ? AirtableHelper.removePrimaryKey(payload, this.primaryKeyFieldName) : payload);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
static removePrimaryKey(x, primaryKeyFieldId) {
|
|
120
|
-
delete x[primaryKeyFieldId];
|
|
121
|
-
return x;
|
|
122
|
-
}
|
|
123
|
-
static convertToDictionary(dictionary, x) {
|
|
124
|
-
const nextObj = {};
|
|
125
|
-
for (const k in x) {
|
|
126
|
-
if (typeof x[k] !== 'undefined' && dictionary[k]) {
|
|
127
|
-
nextObj[dictionary[k]] = x[k];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return nextObj;
|
|
131
|
-
}
|
|
132
|
-
async createRecord(payload) {
|
|
133
|
-
let response = null;
|
|
134
|
-
const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}`;
|
|
135
|
-
try {
|
|
136
|
-
response = await fetch(`${tableUrl}`, {
|
|
137
|
-
method: "POST",
|
|
138
|
-
headers: {
|
|
139
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
140
|
-
"Content-Type": "application/json",
|
|
141
|
-
},
|
|
142
|
-
body: JSON.stringify({
|
|
143
|
-
typecast: true,
|
|
144
|
-
returnFieldsByFieldId: true,
|
|
145
|
-
fields: AirtableHelper.convertToDictionary(this.dictionary, this.primaryKeyWritable === false ? AirtableHelper.removePrimaryKey(payload, this.primaryKeyFieldName) : payload),
|
|
146
|
-
}),
|
|
147
|
-
});
|
|
148
|
-
if (!response.ok && response) {
|
|
149
|
-
const text = await response.text().catch(() => `${response?.status || 'unknown'}`);
|
|
150
|
-
throw new Error(text);
|
|
151
|
-
}
|
|
152
|
-
const resp = await response.json();
|
|
153
|
-
return AirtableHelper.translateFields(this.dictionary, resp);
|
|
154
|
-
}
|
|
155
|
-
catch (err) {
|
|
156
|
-
throw new Error(`Failed to create record in the ${this.tableId} table and the baseId ${this.baseId}. Status Code: ${response?.status}. Error: ${err.message}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
async updateRecord(recordId, payload) {
|
|
160
|
-
let response = null;
|
|
161
|
-
const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}`;
|
|
162
|
-
try {
|
|
163
|
-
response = await fetch(`${tableUrl}/${recordId}`, {
|
|
164
|
-
method: "PATCH",
|
|
165
|
-
headers: {
|
|
166
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
167
|
-
"Content-Type": "application/json",
|
|
168
|
-
},
|
|
169
|
-
body: JSON.stringify({
|
|
170
|
-
typecast: true,
|
|
171
|
-
returnFieldsByFieldId: true,
|
|
172
|
-
fields: AirtableHelper.removePrimaryKey(AirtableHelper.convertToDictionary(this.dictionary, payload), this.dictionary[this.primaryKeyFieldName]),
|
|
173
|
-
}),
|
|
174
|
-
});
|
|
175
|
-
if (!response.ok && response) {
|
|
176
|
-
const text = await response.text().catch(() => `${response?.status || 'unknown'}`);
|
|
177
|
-
throw new Error(text);
|
|
178
|
-
}
|
|
179
|
-
const resp = await response.json();
|
|
180
|
-
return AirtableHelper.translateFields(this.dictionary, resp);
|
|
181
|
-
}
|
|
182
|
-
catch (err) {
|
|
183
|
-
throw new Error(`Failed to update record: ${recordId} in the ${this.tableId} table and the baseId ${this.baseId} with payload ${JSON.stringify(payload)}. Status Code: ${response?.status || 'unknown'}. Error: ${err.message}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
async getExistingRecord(payload) {
|
|
187
|
-
const formula = `${this.dictionary[this.primaryKeyFieldName]} = "${payload[this.primaryKeyFieldName]}"`;
|
|
188
|
-
return (await this.getExistingRecords(formula))?.[0] || null;
|
|
189
|
-
}
|
|
190
|
-
async getExistingRecordById(id) {
|
|
191
|
-
let responseRecords = null;
|
|
192
|
-
const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}`;
|
|
193
|
-
try {
|
|
194
|
-
responseRecords = await fetch(`${tableUrl}/${id}`, {
|
|
195
|
-
method: 'GET',
|
|
196
|
-
headers: {
|
|
197
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
198
|
-
"Content-Type": "application/json",
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
if (!responseRecords.ok && responseRecords) {
|
|
202
|
-
const text = await responseRecords.text().catch(() => `${responseRecords?.status || 'unknown'}`);
|
|
203
|
-
throw new Error(text);
|
|
204
|
-
}
|
|
205
|
-
const data = await responseRecords.json();
|
|
206
|
-
return AirtableHelper.translateFields(this.dictionary, data);
|
|
207
|
-
}
|
|
208
|
-
catch (err) {
|
|
209
|
-
throw new Error(`Failed to obtain records with the id: ${id} from the ${this.tableId} table and the baseId ${this.baseId}. Status Code: ${responseRecords?.status || 'unknown'}. Error: ${err.message}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
async getExistingRecords(formula = '') {
|
|
213
|
-
const allRecords = [];
|
|
214
|
-
let offset = undefined;
|
|
215
|
-
const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}/listRecords`;
|
|
216
|
-
do {
|
|
217
|
-
let responseRecords = null;
|
|
218
|
-
const params = {
|
|
219
|
-
filterByFormula: formula,
|
|
220
|
-
pageSize: 100,
|
|
221
|
-
returnFieldsByFieldId: true,
|
|
222
|
-
fields: Object.values(this.dictionary).filter((x, idx, arr) => arr.indexOf(x) === idx),
|
|
223
|
-
};
|
|
224
|
-
if (offset) {
|
|
225
|
-
params.offset = `${offset}`;
|
|
226
|
-
}
|
|
227
|
-
try {
|
|
228
|
-
responseRecords = await fetch(tableUrl, {
|
|
229
|
-
method: 'POST',
|
|
230
|
-
body: JSON.stringify(params),
|
|
231
|
-
headers: {
|
|
232
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
233
|
-
"Content-Type": "application/json",
|
|
234
|
-
},
|
|
235
|
-
});
|
|
236
|
-
if (!responseRecords.ok && responseRecords) {
|
|
237
|
-
const text = await responseRecords.text().catch(() => `${responseRecords?.status || 'unknown'}`);
|
|
238
|
-
throw new Error(text);
|
|
239
|
-
}
|
|
240
|
-
const data = await responseRecords.json();
|
|
241
|
-
const records = data?.records || [];
|
|
242
|
-
allRecords.push(...records);
|
|
243
|
-
offset = data?.offset;
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
const formulaMsg = formula ? `with the formula ${formula}` : 'from all records';
|
|
247
|
-
throw new Error(`Failed to obtain records ${formulaMsg} from the ${this.tableId} table and the baseId ${this.baseId}. Status Code: ${responseRecords?.status || 'unknown'}. Error: ${err.message}`);
|
|
248
|
-
}
|
|
249
|
-
} while (offset);
|
|
250
|
-
return allRecords.map(x => AirtableHelper.translateFields(this.dictionary, x));
|
|
251
|
-
}
|
|
252
|
-
async getExistingRecordsByKeys(keys) {
|
|
253
|
-
const result = new Map();
|
|
254
|
-
if (keys.length === 0) {
|
|
255
|
-
return result;
|
|
256
|
-
}
|
|
257
|
-
const escapeFormulaValue = (value) => {
|
|
258
|
-
return value.replace(/"/g, '\\"');
|
|
259
|
-
};
|
|
260
|
-
const batchSize = 50;
|
|
261
|
-
for (let i = 0; i < keys.length; i += batchSize) {
|
|
262
|
-
const batch = keys.slice(i, i + batchSize);
|
|
263
|
-
const orConditions = batch.map(key => `${this.dictionary[this.primaryKeyFieldName]} = "${escapeFormulaValue(key)}"`).join(', ');
|
|
264
|
-
const formula = `OR(${orConditions})`;
|
|
265
|
-
const records = await this.getExistingRecords(formula);
|
|
266
|
-
for (const record of records) {
|
|
267
|
-
const key = record.fields[this.primaryKeyFieldName];
|
|
268
|
-
result.set(key, record);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
async pingWebhook(webhook) {
|
|
274
|
-
let resp;
|
|
275
|
-
try {
|
|
276
|
-
resp = await fetch(`https://api.airtable.com/v0/bases/${this.baseId}/webhooks/${webhook.webhook.id}/payloads`, {
|
|
277
|
-
method: 'GET',
|
|
278
|
-
headers: {
|
|
279
|
-
'Authorization': 'Bearer ' + this.apiKey,
|
|
280
|
-
'Content-Type': 'application/json',
|
|
281
|
-
'Accept': 'application/json',
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
if (!resp.ok) {
|
|
285
|
-
const text = await resp.text().catch(_e => `${resp.statusText || resp.status}`);
|
|
286
|
-
this.logging.error(`Requesting notification from the webhookId: ${webhook.webhook.id} failed`, text);
|
|
287
|
-
throw new Error(text);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
catch (err) {
|
|
291
|
-
this.logging.error('Failed to ping airtable webhook with message: ', err.message);
|
|
292
|
-
}
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
async getPayloads(opts) {
|
|
296
|
-
let resp;
|
|
297
|
-
let unprocessedResult = null;
|
|
298
|
-
let nextToProcess = null;
|
|
299
|
-
let collectedRecords = [];
|
|
300
|
-
const urlParsed = new URL(opts.url);
|
|
301
|
-
urlParsed.searchParams.set('returnFieldsByFieldId', '1');
|
|
302
|
-
this.logging.log(`Fetching records from ${urlParsed.toString()}`);
|
|
303
|
-
try {
|
|
304
|
-
resp = await fetch(`${urlParsed.toString()}`, {
|
|
305
|
-
method: 'GET',
|
|
306
|
-
headers: {
|
|
307
|
-
'Authorization': 'Bearer ' + this.apiKey,
|
|
308
|
-
'Content-Type': 'application/json',
|
|
309
|
-
'Accept': 'application/json',
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
if (!resp.ok) {
|
|
313
|
-
const text = await resp.text().catch(_e => `${resp.statusText || resp.status}`);
|
|
314
|
-
throw new Error(text);
|
|
315
|
-
}
|
|
316
|
-
const res = await resp.json();
|
|
317
|
-
if (!res.fields && res.offset) {
|
|
318
|
-
const nextUrl = new URL(opts.url);
|
|
319
|
-
nextUrl.searchParams.set('offset', res.offset);
|
|
320
|
-
nextToProcess = {
|
|
321
|
-
url: nextUrl.toString()
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
this.logging.log(`Collected ${collectedRecords.length} records`);
|
|
325
|
-
if (!res.fields && res.records) {
|
|
326
|
-
collectedRecords = res.records.map((x) => AirtableHelper.translateFields(this.dictionary, x));
|
|
327
|
-
}
|
|
328
|
-
else if (res.fields) {
|
|
329
|
-
collectedRecords.push(AirtableHelper.translateFields(this.dictionary, res));
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
catch (err) {
|
|
333
|
-
this.logging.error(`Requesting notification from the table: ${this.tableId} failed`, err.message);
|
|
334
|
-
unprocessedResult = {
|
|
335
|
-
url: opts.url,
|
|
336
|
-
$$error: err.message
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
return {
|
|
340
|
-
result: collectedRecords,
|
|
341
|
-
unprocessed: unprocessedResult,
|
|
342
|
-
nextToProcess: nextToProcess
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
async listPayloads(input, startingCursor) {
|
|
346
|
-
this.logging.log(`Requesting notification from the webhookId: ${JSON.stringify(input)} of type ${typeof input} with cursor: ${startingCursor}`);
|
|
347
|
-
let unprocessedResult = null;
|
|
348
|
-
let nextToProcess = null;
|
|
349
|
-
let collectedRecords = [];
|
|
350
|
-
let resp = null;
|
|
351
|
-
try {
|
|
352
|
-
resp = await fetch(`https://api.airtable.com/v0/bases/${this.baseId}/webhooks/${input.webhook.id}/payloads`, {
|
|
353
|
-
method: 'GET',
|
|
354
|
-
headers: {
|
|
355
|
-
'Authorization': 'Bearer ' + this.apiKey,
|
|
356
|
-
'Content-Type': 'application/json',
|
|
357
|
-
'Accept': 'application/json',
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
if (!resp.ok) {
|
|
361
|
-
const text = await resp.text().catch(_e => `${resp.statusText || resp.status}`);
|
|
362
|
-
this.logging.error(`Requesting notification from the webhookId: ${input.webhook.id} failed`, text);
|
|
363
|
-
throw new Error(text);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
catch (e) {
|
|
367
|
-
unprocessedResult = {
|
|
368
|
-
webhook: {
|
|
369
|
-
id: input.webhook.id
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
let nextCursor = null;
|
|
374
|
-
if (!unprocessedResult) {
|
|
375
|
-
const res = (await resp.json());
|
|
376
|
-
nextCursor = res.cursor;
|
|
377
|
-
this.logging.log(`Received ${res.payloads.length} records from the table: ${this.tableId}.`);
|
|
378
|
-
for (const payload of res.payloads) {
|
|
379
|
-
const changes = payload.changedTablesById[this.tableId];
|
|
380
|
-
const airtableCreated = Object.entries(changes?.createdRecordsById || {}).map(([k, v]) => ({
|
|
381
|
-
id: k,
|
|
382
|
-
fields: AirtableHelper.translateFields(this.dictionary, { fields: (v.cellValuesByFieldId || {}) }).fields,
|
|
383
|
-
created_at: v.createdTime || payload.timestamp,
|
|
384
|
-
last_modified_at: v.createdTime || payload.timestamp,
|
|
385
|
-
previous_fields: null
|
|
386
|
-
}));
|
|
387
|
-
const airtableChanged = Object.entries(changes?.changedRecordsById || {}).map(([k, v]) => ({
|
|
388
|
-
id: k,
|
|
389
|
-
fields: AirtableHelper.translateFields(this.dictionary, {
|
|
390
|
-
fields: Object.assign({}, v.unchanged?.cellValuesByFieldId, v.current?.cellValuesByFieldId)
|
|
391
|
-
}).fields,
|
|
392
|
-
last_modified_at: payload.timestamp
|
|
393
|
-
}));
|
|
394
|
-
const airtableDestroyed = (changes?.destroyedRecordIds || []).map((x) => {
|
|
395
|
-
return {
|
|
396
|
-
id: x,
|
|
397
|
-
fields: {},
|
|
398
|
-
last_modified_at: payload.timestamp,
|
|
399
|
-
deleted_at: payload.timestamp
|
|
400
|
-
};
|
|
401
|
-
});
|
|
402
|
-
collectedRecords = collectedRecords.concat(airtableCreated, airtableChanged, airtableDestroyed);
|
|
403
|
-
}
|
|
404
|
-
if (res['mightHaveMore']) {
|
|
405
|
-
this.logging.log(`The response might have next page. Last cursor: ${res['cursor']}`);
|
|
406
|
-
nextToProcess = {
|
|
407
|
-
webhook: {
|
|
408
|
-
id: input.webhook.id
|
|
409
|
-
},
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
return {
|
|
414
|
-
cursor: nextCursor || startingCursor,
|
|
415
|
-
result: collectedRecords,
|
|
416
|
-
unprocessed: unprocessedResult,
|
|
417
|
-
nextToProcess: nextToProcess
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
async getWebhooks() {
|
|
421
|
-
const url = `https://api.airtable.com/v0/bases/${this.baseId}/webhooks`;
|
|
422
|
-
const options = {
|
|
423
|
-
method: 'GET',
|
|
424
|
-
headers: { authorization: 'Bearer ' + this.apiKey }
|
|
425
|
-
};
|
|
426
|
-
try {
|
|
427
|
-
const response = await fetch(url, options);
|
|
428
|
-
if (!response.ok) {
|
|
429
|
-
throw new Error(`Invalid response: ${await response.text().catch(() => response.status)}`);
|
|
430
|
-
}
|
|
431
|
-
const data = await response.json();
|
|
432
|
-
return data.webhooks;
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
this.logging.error(`Failed to fetch existing subscriptions. with the error: ${error.message}`, url, options);
|
|
436
|
-
throw new Error(`Failed to fetch existing subscriptions. with the error: ${error.message}`);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
async enableOrPauseWebhook({ webhookId, pause }) {
|
|
440
|
-
const url = `https://api.airtable.com/v0/bases/${this.baseId}/webhooks/${webhookId}/enableNotifications`;
|
|
441
|
-
const options = {
|
|
442
|
-
method: 'POST',
|
|
443
|
-
headers: { authorization: 'Bearer ' + this.apiKey, 'Content-Type': 'application/json; charset=UTF-8' },
|
|
444
|
-
body: JSON.stringify({
|
|
445
|
-
enable: !pause
|
|
446
|
-
})
|
|
447
|
-
};
|
|
448
|
-
try {
|
|
449
|
-
const response = await fetch(url, options);
|
|
450
|
-
if (!response.ok) {
|
|
451
|
-
throw new Error(`Invalid response: ${await response.text().catch(() => response.status)}`);
|
|
452
|
-
}
|
|
453
|
-
const data = await response.json();
|
|
454
|
-
return data;
|
|
455
|
-
}
|
|
456
|
-
catch (error) {
|
|
457
|
-
this.logging.error(`Failed to create subscriptions. with the error: ${error.message}`, url, options);
|
|
458
|
-
throw new Error(`Failed to create subscriptions. with the error: ${error.message}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
async pause() {
|
|
462
|
-
const wh = await this.getWebhook();
|
|
463
|
-
if (wh) {
|
|
464
|
-
return this.enableOrPauseWebhook({
|
|
465
|
-
webhookId: wh.id,
|
|
466
|
-
pause: true
|
|
467
|
-
}).then((wh) => ({
|
|
468
|
-
webhookId: wh.id,
|
|
469
|
-
}));
|
|
470
|
-
}
|
|
471
|
-
return {
|
|
472
|
-
webhookId: null
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
async resume() {
|
|
476
|
-
const wh = await this.getWebhook();
|
|
477
|
-
if (wh) {
|
|
478
|
-
return this.enableOrPauseWebhook({
|
|
479
|
-
webhookId: wh.id,
|
|
480
|
-
pause: false
|
|
481
|
-
}).then((wh) => ({
|
|
482
|
-
webhookId: wh.id,
|
|
483
|
-
}));
|
|
484
|
-
}
|
|
485
|
-
return {
|
|
486
|
-
webhookId: null
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
async getWebhook() {
|
|
490
|
-
const webhooks = await this.getWebhooks();
|
|
491
|
-
for (const x of webhooks) {
|
|
492
|
-
if (x.notificationUrl === this.createNotificationUrl()) {
|
|
493
|
-
return x;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
createNotificationUrl() {
|
|
499
|
-
return `${this.runtimeUrl}/executeWorkflow/${this.workflowId}/${this.triggerId}?request-from-airtable=1&baseId=${this.baseId}&tableId=${this.tableId}`;
|
|
500
|
-
}
|
|
501
|
-
async isValidSignature(secret, payload, signature) {
|
|
502
|
-
const macSecretDecoded = Buffer.from(secret, 'base64');
|
|
503
|
-
const body = Buffer.from(payload, 'utf8');
|
|
504
|
-
const hmac = crypto_1.default.createHmac('sha256', macSecretDecoded);
|
|
505
|
-
hmac.update(body.toString(), 'ascii');
|
|
506
|
-
const expectedContentHmac = 'hmac-sha256=' + hmac.digest('hex');
|
|
507
|
-
return expectedContentHmac === signature;
|
|
508
|
-
}
|
|
509
|
-
async deleteWebhook(x) {
|
|
510
|
-
if (!x) {
|
|
511
|
-
const webhooks = await this.getWebhooks();
|
|
512
|
-
for (const x of webhooks) {
|
|
513
|
-
if (x.notificationUrl === this.createNotificationUrl()) {
|
|
514
|
-
await this.deleteWebhook(x.id);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
return true;
|
|
518
|
-
}
|
|
519
|
-
const url = `https://api.airtable.com/v0/bases/${this.baseId}/webhooks/${x}`;
|
|
520
|
-
try {
|
|
521
|
-
const response = await fetch(url, {
|
|
522
|
-
method: 'DELETE',
|
|
523
|
-
headers: { authorization: `Bearer ${this.apiKey}` },
|
|
524
|
-
});
|
|
525
|
-
if (!response.ok) {
|
|
526
|
-
throw new Error(`${await response.text().catch(() => response.status)}`);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
catch (error) {
|
|
530
|
-
throw new Error(`Failed to delete subscriptions with the error: ${error.message}`);
|
|
531
|
-
}
|
|
532
|
-
return true;
|
|
533
|
-
}
|
|
534
|
-
async webhookHasChanged() {
|
|
535
|
-
const existingWebhook = await this.getWebhook();
|
|
536
|
-
const fieldIds = Object.values(this.dictionary).filter((x, idx, arr) => arr.indexOf(x) === idx);
|
|
537
|
-
if (existingWebhook?.specification.options.filters.recordChangeScope === this.tableId
|
|
538
|
-
&& (0, lodash_isequal_1.default)(existingWebhook?.specification.options.filters.watchDataInFieldIds, fieldIds)
|
|
539
|
-
&& (0, lodash_isequal_1.default)(existingWebhook?.specification.options.includes?.includeCellValuesInFieldIds, fieldIds)
|
|
540
|
-
&& existingWebhook.specification.options.includes?.includePreviousCellValues) {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
return true;
|
|
544
|
-
}
|
|
545
|
-
async updateOrCreateWebhook() {
|
|
546
|
-
const existingWebhook = await this.getWebhook();
|
|
547
|
-
const fieldIds = Object.values(this.dictionary).filter((x, idx, arr) => arr.indexOf(x) === idx);
|
|
548
|
-
if (existingWebhook?.specification.options.filters.recordChangeScope === this.tableId
|
|
549
|
-
&& (0, lodash_isequal_1.default)(existingWebhook?.specification.options.filters.watchDataInFieldIds, fieldIds)
|
|
550
|
-
&& (0, lodash_isequal_1.default)(existingWebhook?.specification.options.includes?.includeCellValuesInFieldIds, fieldIds)
|
|
551
|
-
&& existingWebhook.specification.options.includes?.includePreviousCellValues) {
|
|
552
|
-
return existingWebhook;
|
|
553
|
-
}
|
|
554
|
-
await this.deleteWebhook(existingWebhook?.id);
|
|
555
|
-
const url = `https://api.airtable.com/v0/bases/${this.baseId}/webhooks`;
|
|
556
|
-
const options = {
|
|
557
|
-
method: 'POST',
|
|
558
|
-
headers: { authorization: 'Bearer ' + this.apiKey, 'Content-Type': 'application/json; charset=UTF-8' },
|
|
559
|
-
body: JSON.stringify({
|
|
560
|
-
notificationUrl: this.createNotificationUrl(),
|
|
561
|
-
specification: {
|
|
562
|
-
options: {
|
|
563
|
-
filters: {
|
|
564
|
-
dataTypes: ["tableData"],
|
|
565
|
-
recordChangeScope: this.tableId,
|
|
566
|
-
watchDataInFieldIds: fieldIds,
|
|
567
|
-
},
|
|
568
|
-
includes: {
|
|
569
|
-
includePreviousCellValues: true,
|
|
570
|
-
includeCellValuesInFieldIds: fieldIds
|
|
571
|
-
}
|
|
572
|
-
},
|
|
573
|
-
}
|
|
574
|
-
})
|
|
575
|
-
};
|
|
576
|
-
try {
|
|
577
|
-
const response = await fetch(url, options);
|
|
578
|
-
if (!response.ok) {
|
|
579
|
-
throw new Error(`Invalid response: ${await response.text().catch(() => response.status)}`);
|
|
580
|
-
}
|
|
581
|
-
const data = await response.json();
|
|
582
|
-
return data;
|
|
583
|
-
}
|
|
584
|
-
catch (error) {
|
|
585
|
-
this.logging.error(`Failed to create subscriptions. with the error: ${error.message}`, url, options);
|
|
586
|
-
throw new Error(`Failed to create subscriptions. with the error: ${error.message}`);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
exports.default = AirtableHelper;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const runtime_1 = __importDefault(require("./runtime"));
|
|
7
|
-
;
|
|
8
|
-
class BigQueryHelper extends runtime_1.default {
|
|
9
|
-
bigQuery;
|
|
10
|
-
constructor(opts, bigQuery) {
|
|
11
|
-
super(opts);
|
|
12
|
-
this.bigQuery = bigQuery;
|
|
13
|
-
}
|
|
14
|
-
async createOrUpdate(opts) {
|
|
15
|
-
const { datasetId, tableName, incomingSchema } = opts;
|
|
16
|
-
const dataset = this.bigQuery.dataset(datasetId);
|
|
17
|
-
const table = dataset.table(tableName);
|
|
18
|
-
const fullTableId = `${this.bigQuery.projectId}.${datasetId}.${tableName}`;
|
|
19
|
-
const [tableExists] = await table.exists();
|
|
20
|
-
if (!tableExists) {
|
|
21
|
-
await dataset.createTable(tableName, {
|
|
22
|
-
schema: {
|
|
23
|
-
fields: incomingSchema,
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
return fullTableId;
|
|
27
|
-
}
|
|
28
|
-
const [metadata] = await table.getMetadata();
|
|
29
|
-
const existingSchema = metadata.schema.fields;
|
|
30
|
-
const alterStatements = [];
|
|
31
|
-
const existingColumnsMap = new Map(existingSchema.map(col => [col.name.toLowerCase(), col]));
|
|
32
|
-
const incomingColumnsMap = new Map(incomingSchema.map(col => [col.name.toLowerCase(), col]));
|
|
33
|
-
const currentDate = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
34
|
-
for (const incomingCol of incomingSchema) {
|
|
35
|
-
const existingCol = existingColumnsMap.get(incomingCol.name.toLowerCase());
|
|
36
|
-
if (!existingCol) {
|
|
37
|
-
alterStatements.push(`ALTER TABLE \`${fullTableId}\` ADD COLUMN \`${incomingCol.name}\` ${incomingCol.type}${incomingCol.mode === 'REPEATED' ? ' REPEATED' : ''};`);
|
|
38
|
-
}
|
|
39
|
-
else if (existingCol.type !== incomingCol.type ||
|
|
40
|
-
(incomingCol.mode && existingCol.mode !== incomingCol.mode)) {
|
|
41
|
-
const renamed = `${incomingCol.name}${currentDate}`;
|
|
42
|
-
alterStatements.push(`ALTER TABLE \`${fullTableId}\` RENAME COLUMN \`${incomingCol.name}\` TO \`${renamed}\`;`);
|
|
43
|
-
alterStatements.push(`ALTER TABLE \`${fullTableId}\` ADD COLUMN \`${incomingCol.name}\` ${incomingCol.type}${incomingCol.mode === 'REPEATED' ? ' REPEATED' : ''};`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
for (const existingCol of existingSchema) {
|
|
47
|
-
if (!incomingColumnsMap.has(existingCol.name.toLowerCase())) {
|
|
48
|
-
const renamed = `${existingCol.name}${currentDate}`;
|
|
49
|
-
alterStatements.push(`ALTER TABLE \`${fullTableId}\` RENAME COLUMN \`${existingCol.name}\` TO \`${renamed}\`;`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
for (const sql of alterStatements) {
|
|
53
|
-
console.log(`Executing SQL: ${sql}`);
|
|
54
|
-
await this.bigQuery.query({ query: sql });
|
|
55
|
-
}
|
|
56
|
-
return fullTableId;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.default = BigQueryHelper;
|