@squadbase/connectors 0.0.12 → 0.0.14
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/chunk-4K4NERCT.js +212 -0
- package/dist/index.js +316 -286
- package/dist/sdk.d.ts +343 -3
- package/dist/sdk.js +668 -11
- package/package.json +3 -4
- package/dist/chunk-E5AVUXWJ.js +0 -93
package/dist/sdk.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parameters,
|
|
3
|
-
parameters2
|
|
4
|
-
|
|
3
|
+
parameters2,
|
|
4
|
+
parameters3,
|
|
5
|
+
parameters4,
|
|
6
|
+
parameters5,
|
|
7
|
+
parameters6
|
|
8
|
+
} from "./chunk-4K4NERCT.js";
|
|
5
9
|
|
|
6
10
|
// src/connectors/kintone/sdk/index.ts
|
|
7
11
|
function createClient(params) {
|
|
8
|
-
const baseUrl = params[
|
|
9
|
-
const username = params[
|
|
10
|
-
const password = params[
|
|
12
|
+
const baseUrl = params[parameters3.baseUrl.slug];
|
|
13
|
+
const username = params[parameters3.username.slug];
|
|
14
|
+
const password = params[parameters3.password.slug];
|
|
11
15
|
if (!baseUrl || !username || !password) {
|
|
12
16
|
const required = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
parameters3.baseUrl.slug,
|
|
18
|
+
parameters3.username.slug,
|
|
19
|
+
parameters3.password.slug
|
|
16
20
|
];
|
|
17
21
|
const missing = required.filter((s) => !params[s]);
|
|
18
22
|
throw new Error(
|
|
@@ -74,15 +78,668 @@ function createClient(params) {
|
|
|
74
78
|
|
|
75
79
|
// src/connectors/openai/sdk/index.ts
|
|
76
80
|
function createClient2(params) {
|
|
77
|
-
const apiKey = params[
|
|
81
|
+
const apiKey = params[parameters6.apiKey.slug];
|
|
78
82
|
if (!apiKey) {
|
|
79
83
|
throw new Error(
|
|
80
|
-
`openai: missing required parameter: ${
|
|
84
|
+
`openai: missing required parameter: ${parameters6.apiKey.slug}`
|
|
81
85
|
);
|
|
82
86
|
}
|
|
83
87
|
return { apiKey };
|
|
84
88
|
}
|
|
89
|
+
|
|
90
|
+
// src/connectors/airtable/sdk/index.ts
|
|
91
|
+
var BASE_URL = "https://api.airtable.com/v0";
|
|
92
|
+
function createClient3(params) {
|
|
93
|
+
const baseId = params[parameters.baseId.slug];
|
|
94
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
95
|
+
if (!baseId || !apiKey) {
|
|
96
|
+
const required = [parameters.baseId.slug, parameters.apiKey.slug];
|
|
97
|
+
const missing = required.filter((s) => !params[s]);
|
|
98
|
+
throw new Error(
|
|
99
|
+
`airtable: missing required parameters: ${missing.join(", ")}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
function request(path, init) {
|
|
103
|
+
const resolvedPath = path.replace(/\{baseId\}/g, baseId);
|
|
104
|
+
const url = `${BASE_URL}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
|
|
105
|
+
const headers = new Headers(init?.headers);
|
|
106
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
107
|
+
return fetch(url, { ...init, headers });
|
|
108
|
+
}
|
|
109
|
+
async function listRecords(tableIdOrName, options) {
|
|
110
|
+
const searchParams = new URLSearchParams();
|
|
111
|
+
if (options?.fields) {
|
|
112
|
+
for (const field of options.fields) {
|
|
113
|
+
searchParams.append("fields[]", field);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (options?.filterByFormula) {
|
|
117
|
+
searchParams.set("filterByFormula", options.filterByFormula);
|
|
118
|
+
}
|
|
119
|
+
if (options?.maxRecords != null) {
|
|
120
|
+
searchParams.set("maxRecords", String(options.maxRecords));
|
|
121
|
+
}
|
|
122
|
+
if (options?.sort) {
|
|
123
|
+
for (let i = 0; i < options.sort.length; i++) {
|
|
124
|
+
searchParams.set(`sort[${i}][field]`, options.sort[i].field);
|
|
125
|
+
if (options.sort[i].direction) {
|
|
126
|
+
searchParams.set(
|
|
127
|
+
`sort[${i}][direction]`,
|
|
128
|
+
options.sort[i].direction
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (options?.pageSize != null) {
|
|
134
|
+
searchParams.set("pageSize", String(options.pageSize));
|
|
135
|
+
}
|
|
136
|
+
if (options?.view) {
|
|
137
|
+
searchParams.set("view", options.view);
|
|
138
|
+
}
|
|
139
|
+
if (options?.offset) {
|
|
140
|
+
searchParams.set("offset", options.offset);
|
|
141
|
+
}
|
|
142
|
+
const qs = searchParams.toString();
|
|
143
|
+
const path = `/${baseId}/${encodeURIComponent(tableIdOrName)}${qs ? `?${qs}` : ""}`;
|
|
144
|
+
const response = await request(path);
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
const body = await response.text();
|
|
147
|
+
throw new Error(
|
|
148
|
+
`airtable: listRecords failed (${response.status}): ${body}`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return await response.json();
|
|
152
|
+
}
|
|
153
|
+
async function getRecord(tableIdOrName, recordId) {
|
|
154
|
+
const path = `/${baseId}/${encodeURIComponent(tableIdOrName)}/${encodeURIComponent(recordId)}`;
|
|
155
|
+
const response = await request(path);
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
const body = await response.text();
|
|
158
|
+
throw new Error(
|
|
159
|
+
`airtable: getRecord failed (${response.status}): ${body}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return await response.json();
|
|
163
|
+
}
|
|
164
|
+
async function createRecords(tableIdOrName, records, options) {
|
|
165
|
+
const payload = { records };
|
|
166
|
+
if (options?.typecast != null) {
|
|
167
|
+
payload.typecast = options.typecast;
|
|
168
|
+
}
|
|
169
|
+
const path = `/${baseId}/${encodeURIComponent(tableIdOrName)}`;
|
|
170
|
+
const response = await request(path, {
|
|
171
|
+
method: "POST",
|
|
172
|
+
headers: { "Content-Type": "application/json" },
|
|
173
|
+
body: JSON.stringify(payload)
|
|
174
|
+
});
|
|
175
|
+
if (!response.ok) {
|
|
176
|
+
const body = await response.text();
|
|
177
|
+
throw new Error(
|
|
178
|
+
`airtable: createRecords failed (${response.status}): ${body}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return await response.json();
|
|
182
|
+
}
|
|
183
|
+
async function updateRecords(tableIdOrName, records, options) {
|
|
184
|
+
const payload = { records };
|
|
185
|
+
if (options?.typecast != null) {
|
|
186
|
+
payload.typecast = options.typecast;
|
|
187
|
+
}
|
|
188
|
+
const path = `/${baseId}/${encodeURIComponent(tableIdOrName)}`;
|
|
189
|
+
const response = await request(path, {
|
|
190
|
+
method: "PATCH",
|
|
191
|
+
headers: { "Content-Type": "application/json" },
|
|
192
|
+
body: JSON.stringify(payload)
|
|
193
|
+
});
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
const body = await response.text();
|
|
196
|
+
throw new Error(
|
|
197
|
+
`airtable: updateRecords failed (${response.status}): ${body}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
return await response.json();
|
|
201
|
+
}
|
|
202
|
+
async function listTables() {
|
|
203
|
+
const path = `/meta/bases/${baseId}/tables`;
|
|
204
|
+
const response = await request(path);
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
const body = await response.text();
|
|
207
|
+
throw new Error(
|
|
208
|
+
`airtable: listTables failed (${response.status}): ${body}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return await response.json();
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
request,
|
|
215
|
+
listRecords,
|
|
216
|
+
getRecord,
|
|
217
|
+
createRecords,
|
|
218
|
+
updateRecords,
|
|
219
|
+
listTables
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/connectors/google-analytics/sdk/index.ts
|
|
224
|
+
import * as crypto from "crypto";
|
|
225
|
+
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
226
|
+
var BASE_URL2 = "https://analyticsdata.googleapis.com/v1beta/";
|
|
227
|
+
var SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
|
|
228
|
+
function base64url(input) {
|
|
229
|
+
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
230
|
+
return buf.toString("base64url");
|
|
231
|
+
}
|
|
232
|
+
function buildJwt(clientEmail, privateKey, nowSec) {
|
|
233
|
+
const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
234
|
+
const payload = base64url(
|
|
235
|
+
JSON.stringify({
|
|
236
|
+
iss: clientEmail,
|
|
237
|
+
scope: SCOPE,
|
|
238
|
+
aud: TOKEN_URL,
|
|
239
|
+
iat: nowSec,
|
|
240
|
+
exp: nowSec + 3600
|
|
241
|
+
})
|
|
242
|
+
);
|
|
243
|
+
const signingInput = `${header}.${payload}`;
|
|
244
|
+
const sign = crypto.createSign("RSA-SHA256");
|
|
245
|
+
sign.update(signingInput);
|
|
246
|
+
sign.end();
|
|
247
|
+
const signature = base64url(sign.sign(privateKey));
|
|
248
|
+
return `${signingInput}.${signature}`;
|
|
249
|
+
}
|
|
250
|
+
function createClient4(params) {
|
|
251
|
+
const serviceAccountKeyJsonBase64 = params[parameters2.serviceAccountKeyJsonBase64.slug];
|
|
252
|
+
const propertyId = params[parameters2.propertyId.slug];
|
|
253
|
+
if (!serviceAccountKeyJsonBase64 || !propertyId) {
|
|
254
|
+
const required = [
|
|
255
|
+
parameters2.serviceAccountKeyJsonBase64.slug,
|
|
256
|
+
parameters2.propertyId.slug
|
|
257
|
+
];
|
|
258
|
+
const missing = required.filter((s) => !params[s]);
|
|
259
|
+
throw new Error(
|
|
260
|
+
`google-analytics: missing required parameters: ${missing.join(", ")}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
let serviceAccountKey;
|
|
264
|
+
try {
|
|
265
|
+
const decoded = Buffer.from(
|
|
266
|
+
serviceAccountKeyJsonBase64,
|
|
267
|
+
"base64"
|
|
268
|
+
).toString("utf-8");
|
|
269
|
+
serviceAccountKey = JSON.parse(decoded);
|
|
270
|
+
} catch {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"google-analytics: failed to decode service account key JSON from base64"
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
if (!serviceAccountKey.client_email || !serviceAccountKey.private_key) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
"google-analytics: service account key JSON must contain client_email and private_key"
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
let cachedToken = null;
|
|
281
|
+
let tokenExpiresAt = 0;
|
|
282
|
+
async function getAccessToken() {
|
|
283
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
284
|
+
if (cachedToken && nowSec < tokenExpiresAt - 60) {
|
|
285
|
+
return cachedToken;
|
|
286
|
+
}
|
|
287
|
+
const jwt = buildJwt(
|
|
288
|
+
serviceAccountKey.client_email,
|
|
289
|
+
serviceAccountKey.private_key,
|
|
290
|
+
nowSec
|
|
291
|
+
);
|
|
292
|
+
const response = await fetch(TOKEN_URL, {
|
|
293
|
+
method: "POST",
|
|
294
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
295
|
+
body: new URLSearchParams({
|
|
296
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
297
|
+
assertion: jwt
|
|
298
|
+
})
|
|
299
|
+
});
|
|
300
|
+
if (!response.ok) {
|
|
301
|
+
const text = await response.text();
|
|
302
|
+
throw new Error(
|
|
303
|
+
`google-analytics: token exchange failed (${response.status}): ${text}`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const data = await response.json();
|
|
307
|
+
cachedToken = data.access_token;
|
|
308
|
+
tokenExpiresAt = nowSec + data.expires_in;
|
|
309
|
+
return cachedToken;
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
async request(path, init) {
|
|
313
|
+
const accessToken = await getAccessToken();
|
|
314
|
+
const resolvedPath = path.replace(/\{propertyId\}/g, propertyId);
|
|
315
|
+
const url = `${BASE_URL2.replace(/\/+$/, "")}/${resolvedPath.replace(/^\/+/, "")}`;
|
|
316
|
+
const headers = new Headers(init?.headers);
|
|
317
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
318
|
+
return fetch(url, { ...init, headers });
|
|
319
|
+
},
|
|
320
|
+
async runReport(request) {
|
|
321
|
+
const response = await this.request(
|
|
322
|
+
`properties/${propertyId}:runReport`,
|
|
323
|
+
{
|
|
324
|
+
method: "POST",
|
|
325
|
+
headers: { "Content-Type": "application/json" },
|
|
326
|
+
body: JSON.stringify(request)
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
if (!response.ok) {
|
|
330
|
+
const text = await response.text();
|
|
331
|
+
throw new Error(
|
|
332
|
+
`google-analytics: runReport failed (${response.status}): ${text}`
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
const data = await response.json();
|
|
336
|
+
return {
|
|
337
|
+
rows: data.rows ?? [],
|
|
338
|
+
rowCount: data.rowCount ?? 0
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
async getMetadata() {
|
|
342
|
+
const response = await this.request(
|
|
343
|
+
`properties/${propertyId}/metadata`,
|
|
344
|
+
{ method: "GET" }
|
|
345
|
+
);
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
const text = await response.text();
|
|
348
|
+
throw new Error(
|
|
349
|
+
`google-analytics: getMetadata failed (${response.status}): ${text}`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
return await response.json();
|
|
353
|
+
},
|
|
354
|
+
async runRealtimeReport(request) {
|
|
355
|
+
const response = await this.request(
|
|
356
|
+
`properties/${propertyId}:runRealtimeReport`,
|
|
357
|
+
{
|
|
358
|
+
method: "POST",
|
|
359
|
+
headers: { "Content-Type": "application/json" },
|
|
360
|
+
body: JSON.stringify(request)
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
if (!response.ok) {
|
|
364
|
+
const text = await response.text();
|
|
365
|
+
throw new Error(
|
|
366
|
+
`google-analytics: runRealtimeReport failed (${response.status}): ${text}`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
const data = await response.json();
|
|
370
|
+
return {
|
|
371
|
+
rows: data.rows ?? [],
|
|
372
|
+
rowCount: data.rowCount ?? 0
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/connectors/wix-store/sdk/index.ts
|
|
379
|
+
function createClient5(params) {
|
|
380
|
+
const accountId = params[parameters4.accountId.slug];
|
|
381
|
+
const siteId = params[parameters4.siteId.slug];
|
|
382
|
+
const apiKey = params[parameters4.apiKey.slug];
|
|
383
|
+
if (!accountId || !siteId || !apiKey) {
|
|
384
|
+
const required = [
|
|
385
|
+
parameters4.accountId.slug,
|
|
386
|
+
parameters4.siteId.slug,
|
|
387
|
+
parameters4.apiKey.slug
|
|
388
|
+
];
|
|
389
|
+
const missing = required.filter((s) => !params[s]);
|
|
390
|
+
throw new Error(
|
|
391
|
+
`wix-store: missing required parameters: ${missing.join(", ")}`
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
const baseUrl = "https://www.wixapis.com";
|
|
395
|
+
function authHeaders(extra) {
|
|
396
|
+
const headers = new Headers(extra);
|
|
397
|
+
headers.set("Authorization", apiKey);
|
|
398
|
+
headers.set("wix-site-id", siteId);
|
|
399
|
+
return headers;
|
|
400
|
+
}
|
|
401
|
+
async function assertOk(res, label) {
|
|
402
|
+
if (!res.ok) {
|
|
403
|
+
const body = await res.text().catch(() => "(unreadable body)");
|
|
404
|
+
throw new Error(
|
|
405
|
+
`wix-store ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
request(path, init) {
|
|
411
|
+
const url = `${baseUrl}${path}`;
|
|
412
|
+
const headers = new Headers(init?.headers);
|
|
413
|
+
headers.set("Authorization", apiKey);
|
|
414
|
+
headers.set("wix-site-id", siteId);
|
|
415
|
+
return fetch(url, { ...init, headers });
|
|
416
|
+
},
|
|
417
|
+
async queryProducts(options) {
|
|
418
|
+
const query = {};
|
|
419
|
+
if (options?.filter) query.filter = options.filter;
|
|
420
|
+
if (options?.sort) query.sort = options.sort;
|
|
421
|
+
if (options?.paging) query.paging = options.paging;
|
|
422
|
+
const res = await fetch(`${baseUrl}/stores/v1/products/query`, {
|
|
423
|
+
method: "POST",
|
|
424
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
425
|
+
body: JSON.stringify({ query })
|
|
426
|
+
});
|
|
427
|
+
await assertOk(res, "queryProducts");
|
|
428
|
+
const json = await res.json();
|
|
429
|
+
return {
|
|
430
|
+
products: json.products ?? [],
|
|
431
|
+
totalResults: json.totalResults ?? 0
|
|
432
|
+
};
|
|
433
|
+
},
|
|
434
|
+
async getProduct(productId) {
|
|
435
|
+
const res = await fetch(
|
|
436
|
+
`${baseUrl}/stores/v1/products/${encodeURIComponent(productId)}`,
|
|
437
|
+
{ method: "GET", headers: authHeaders() }
|
|
438
|
+
);
|
|
439
|
+
await assertOk(res, "getProduct");
|
|
440
|
+
const json = await res.json();
|
|
441
|
+
return { product: json.product };
|
|
442
|
+
},
|
|
443
|
+
async queryOrders(options) {
|
|
444
|
+
const search = {};
|
|
445
|
+
if (options?.filter) search.filter = options.filter;
|
|
446
|
+
if (options?.sort) search.sort = options.sort;
|
|
447
|
+
if (options?.cursorPaging) search.cursorPaging = options.cursorPaging;
|
|
448
|
+
const res = await fetch(`${baseUrl}/ecom/v1/orders/search`, {
|
|
449
|
+
method: "POST",
|
|
450
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
451
|
+
body: JSON.stringify({ search })
|
|
452
|
+
});
|
|
453
|
+
await assertOk(res, "queryOrders");
|
|
454
|
+
const json = await res.json();
|
|
455
|
+
return {
|
|
456
|
+
orders: json.orders ?? [],
|
|
457
|
+
pagingMetadata: json.pagingMetadata
|
|
458
|
+
};
|
|
459
|
+
},
|
|
460
|
+
async getOrder(orderId) {
|
|
461
|
+
const res = await fetch(
|
|
462
|
+
`${baseUrl}/ecom/v1/orders/${encodeURIComponent(orderId)}`,
|
|
463
|
+
{ method: "GET", headers: authHeaders() }
|
|
464
|
+
);
|
|
465
|
+
await assertOk(res, "getOrder");
|
|
466
|
+
const json = await res.json();
|
|
467
|
+
return { order: json.order };
|
|
468
|
+
},
|
|
469
|
+
async queryCollections(options) {
|
|
470
|
+
const query = {};
|
|
471
|
+
if (options?.filter) query.filter = options.filter;
|
|
472
|
+
if (options?.sort) query.sort = options.sort;
|
|
473
|
+
if (options?.paging) query.paging = options.paging;
|
|
474
|
+
const res = await fetch(`${baseUrl}/stores/v1/collections/query`, {
|
|
475
|
+
method: "POST",
|
|
476
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
477
|
+
body: JSON.stringify({ query })
|
|
478
|
+
});
|
|
479
|
+
await assertOk(res, "queryCollections");
|
|
480
|
+
const json = await res.json();
|
|
481
|
+
return {
|
|
482
|
+
collections: json.collections ?? []
|
|
483
|
+
};
|
|
484
|
+
},
|
|
485
|
+
async queryInventory(options) {
|
|
486
|
+
const query = {};
|
|
487
|
+
if (options?.filter) query.filter = options.filter;
|
|
488
|
+
if (options?.paging) query.paging = options.paging;
|
|
489
|
+
const res = await fetch(`${baseUrl}/stores/v2/inventoryItems/query`, {
|
|
490
|
+
method: "POST",
|
|
491
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
492
|
+
body: JSON.stringify({ query })
|
|
493
|
+
});
|
|
494
|
+
await assertOk(res, "queryInventory");
|
|
495
|
+
const json = await res.json();
|
|
496
|
+
return {
|
|
497
|
+
inventoryItems: json.inventoryItems ?? [],
|
|
498
|
+
totalResults: json.totalResults ?? 0
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/connectors/dbt/sdk/index.ts
|
|
505
|
+
function createClient6(params) {
|
|
506
|
+
const host = params[parameters5.host.slug];
|
|
507
|
+
const prodEnvId = params[parameters5.prodEnvId.slug];
|
|
508
|
+
const token = params[parameters5.token.slug];
|
|
509
|
+
if (!host || !prodEnvId || !token) {
|
|
510
|
+
const required = [
|
|
511
|
+
parameters5.host.slug,
|
|
512
|
+
parameters5.prodEnvId.slug,
|
|
513
|
+
parameters5.token.slug
|
|
514
|
+
];
|
|
515
|
+
const missing = required.filter((s) => !params[s]);
|
|
516
|
+
throw new Error(
|
|
517
|
+
`dbt: missing required parameters: ${missing.join(", ")}`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
const baseUrl = `https://${host.replace(/\/+$/, "")}`;
|
|
521
|
+
const environmentId = Number(prodEnvId);
|
|
522
|
+
function resolveGraphqlEndpoint() {
|
|
523
|
+
if (host.includes("emea")) return "https://metadata.emea.dbt.com/graphql";
|
|
524
|
+
if (host.includes(".au.")) return "https://metadata.au.dbt.com/graphql";
|
|
525
|
+
return "https://metadata.cloud.getdbt.com/graphql";
|
|
526
|
+
}
|
|
527
|
+
async function graphqlRequest(graphqlQuery, variables) {
|
|
528
|
+
const mergedVariables = {
|
|
529
|
+
environmentId,
|
|
530
|
+
...variables
|
|
531
|
+
};
|
|
532
|
+
const response = await fetch(resolveGraphqlEndpoint(), {
|
|
533
|
+
method: "POST",
|
|
534
|
+
headers: {
|
|
535
|
+
"Content-Type": "application/json",
|
|
536
|
+
Authorization: `Bearer ${token}`
|
|
537
|
+
},
|
|
538
|
+
body: JSON.stringify({
|
|
539
|
+
query: graphqlQuery,
|
|
540
|
+
variables: mergedVariables
|
|
541
|
+
})
|
|
542
|
+
});
|
|
543
|
+
if (!response.ok) {
|
|
544
|
+
const body = await response.text().catch(() => "(unreadable body)");
|
|
545
|
+
throw new Error(
|
|
546
|
+
`dbt Discovery API error: ${response.status} ${response.statusText} \u2014 ${body}`
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
const json = await response.json();
|
|
550
|
+
if (json.errors && json.errors.length > 0) {
|
|
551
|
+
throw new Error(
|
|
552
|
+
`dbt GraphQL error: ${json.errors.map((e) => e.message).join("; ")}`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
return json.data ?? {};
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
request(path, init) {
|
|
559
|
+
const resolvedPath = path.replace(
|
|
560
|
+
/\{environmentId\}/g,
|
|
561
|
+
prodEnvId
|
|
562
|
+
);
|
|
563
|
+
const url = `${baseUrl}${resolvedPath}`;
|
|
564
|
+
const headers = new Headers(init?.headers);
|
|
565
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
566
|
+
return fetch(url, { ...init, headers });
|
|
567
|
+
},
|
|
568
|
+
query(graphqlQuery, variables) {
|
|
569
|
+
return graphqlRequest(graphqlQuery, variables);
|
|
570
|
+
},
|
|
571
|
+
async getModels(options) {
|
|
572
|
+
const first = options?.limit ?? 500;
|
|
573
|
+
const data = await graphqlRequest(
|
|
574
|
+
`query ($environmentId: BigInt!, $first: Int!) {
|
|
575
|
+
environment(id: $environmentId) {
|
|
576
|
+
applied {
|
|
577
|
+
models(first: $first) {
|
|
578
|
+
edges {
|
|
579
|
+
node {
|
|
580
|
+
uniqueId
|
|
581
|
+
name
|
|
582
|
+
description
|
|
583
|
+
materializedType
|
|
584
|
+
database
|
|
585
|
+
schema
|
|
586
|
+
alias
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}`,
|
|
593
|
+
{ first }
|
|
594
|
+
);
|
|
595
|
+
const env = data.environment;
|
|
596
|
+
const applied = env?.applied;
|
|
597
|
+
const models = applied?.models;
|
|
598
|
+
const edges = models?.edges ?? [];
|
|
599
|
+
return edges.map((edge) => edge.node);
|
|
600
|
+
},
|
|
601
|
+
async getModelByUniqueId(uniqueId) {
|
|
602
|
+
const data = await graphqlRequest(
|
|
603
|
+
`query ($environmentId: BigInt!, $uniqueIds: [String!]) {
|
|
604
|
+
environment(id: $environmentId) {
|
|
605
|
+
applied {
|
|
606
|
+
models(first: 1, filter: { uniqueIds: $uniqueIds }) {
|
|
607
|
+
edges {
|
|
608
|
+
node {
|
|
609
|
+
uniqueId
|
|
610
|
+
name
|
|
611
|
+
description
|
|
612
|
+
materializedType
|
|
613
|
+
database
|
|
614
|
+
schema
|
|
615
|
+
alias
|
|
616
|
+
catalog {
|
|
617
|
+
columns {
|
|
618
|
+
name
|
|
619
|
+
type
|
|
620
|
+
description
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}`,
|
|
629
|
+
{ uniqueIds: [uniqueId] }
|
|
630
|
+
);
|
|
631
|
+
const env = data.environment;
|
|
632
|
+
const applied = env?.applied;
|
|
633
|
+
const models = applied?.models;
|
|
634
|
+
const edges = models?.edges ?? [];
|
|
635
|
+
return edges.length > 0 ? edges[0].node : null;
|
|
636
|
+
},
|
|
637
|
+
async getSources(options) {
|
|
638
|
+
const first = options?.limit ?? 500;
|
|
639
|
+
const data = await graphqlRequest(
|
|
640
|
+
`query ($environmentId: BigInt!, $first: Int!) {
|
|
641
|
+
environment(id: $environmentId) {
|
|
642
|
+
applied {
|
|
643
|
+
sources(first: $first) {
|
|
644
|
+
edges {
|
|
645
|
+
node {
|
|
646
|
+
uniqueId
|
|
647
|
+
name
|
|
648
|
+
description
|
|
649
|
+
database
|
|
650
|
+
schema
|
|
651
|
+
identifier
|
|
652
|
+
sourceName
|
|
653
|
+
loader
|
|
654
|
+
freshness {
|
|
655
|
+
freshnessStatus
|
|
656
|
+
maxLoadedAt
|
|
657
|
+
freshnessChecked
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}`,
|
|
665
|
+
{ first }
|
|
666
|
+
);
|
|
667
|
+
const env = data.environment;
|
|
668
|
+
const applied = env?.applied;
|
|
669
|
+
const sources = applied?.sources;
|
|
670
|
+
const edges = sources?.edges ?? [];
|
|
671
|
+
return edges.map((edge) => edge.node);
|
|
672
|
+
},
|
|
673
|
+
async getTests(options) {
|
|
674
|
+
const first = options?.limit ?? 500;
|
|
675
|
+
const data = await graphqlRequest(
|
|
676
|
+
`query ($environmentId: BigInt!, $first: Int!) {
|
|
677
|
+
environment(id: $environmentId) {
|
|
678
|
+
applied {
|
|
679
|
+
tests(first: $first) {
|
|
680
|
+
edges {
|
|
681
|
+
node {
|
|
682
|
+
uniqueId
|
|
683
|
+
name
|
|
684
|
+
columnName
|
|
685
|
+
testType
|
|
686
|
+
lastKnownResult
|
|
687
|
+
executionInfo {
|
|
688
|
+
lastRunStatus
|
|
689
|
+
executionTime
|
|
690
|
+
lastRunGeneratedAt
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}`,
|
|
698
|
+
{ first }
|
|
699
|
+
);
|
|
700
|
+
const env = data.environment;
|
|
701
|
+
const applied = env?.applied;
|
|
702
|
+
const tests = applied?.tests;
|
|
703
|
+
const edges = tests?.edges ?? [];
|
|
704
|
+
return edges.map((edge) => edge.node);
|
|
705
|
+
},
|
|
706
|
+
async getMetrics(options) {
|
|
707
|
+
const first = options?.limit ?? 500;
|
|
708
|
+
const data = await graphqlRequest(
|
|
709
|
+
`query ($environmentId: BigInt!, $first: Int!) {
|
|
710
|
+
environment(id: $environmentId) {
|
|
711
|
+
definition {
|
|
712
|
+
metrics(first: $first) {
|
|
713
|
+
edges {
|
|
714
|
+
node {
|
|
715
|
+
uniqueId
|
|
716
|
+
name
|
|
717
|
+
description
|
|
718
|
+
type
|
|
719
|
+
label
|
|
720
|
+
filter
|
|
721
|
+
formula
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}`,
|
|
728
|
+
{ first }
|
|
729
|
+
);
|
|
730
|
+
const env = data.environment;
|
|
731
|
+
const definition = env?.definition;
|
|
732
|
+
const metrics = definition?.metrics;
|
|
733
|
+
const edges = metrics?.edges ?? [];
|
|
734
|
+
return edges.map((edge) => edge.node);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
}
|
|
85
738
|
export {
|
|
739
|
+
createClient3 as airtable,
|
|
740
|
+
createClient6 as dbt,
|
|
741
|
+
createClient4 as googleAnalytics,
|
|
86
742
|
createClient as kintone,
|
|
87
|
-
createClient2 as openai
|
|
743
|
+
createClient2 as openai,
|
|
744
|
+
createClient5 as wixStore
|
|
88
745
|
};
|