@tangle-network/agent-integrations 0.53.24 → 0.53.26
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/catalog.js +4 -4
- package/dist/{chunk-KIPIGOZD.js → chunk-M4AXWKHK.js} +2 -2
- package/dist/{chunk-ASAV5XL6.js → chunk-WSRMGVHS.js} +3 -3
- package/dist/{chunk-YWNB5M5K.js → chunk-XZL47RBS.js} +990 -112
- package/dist/{chunk-YWNB5M5K.js.map → chunk-XZL47RBS.js.map} +1 -1
- package/dist/{chunk-BZIOH6KJ.js → chunk-ZR55ERGY.js} +54 -2
- package/dist/chunk-ZR55ERGY.js.map +1 -0
- package/dist/connectors/adapters/index.d.ts +5 -1
- package/dist/connectors/adapters/index.js +5 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +6 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -4
- package/dist/mcp.js +4 -4
- package/dist/registry.js +4 -4
- package/dist/runtime.js +4 -4
- package/dist/specs.js +3 -3
- package/docs/integration-execution-audit.md +12 -10
- package/docs/integration-execution-matrix.json +38 -28
- package/package.json +1 -1
- package/dist/chunk-BZIOH6KJ.js.map +0 -1
- /package/dist/{chunk-KIPIGOZD.js.map → chunk-M4AXWKHK.js.map} +0 -0
- /package/dist/{chunk-ASAV5XL6.js.map → chunk-WSRMGVHS.js.map} +0 -0
|
@@ -82,7 +82,9 @@ __export(adapters_exports, {
|
|
|
82
82
|
azureAdConnector: () => azureAdConnector,
|
|
83
83
|
azureBlobStorageConnector: () => azureBlobStorageConnector,
|
|
84
84
|
azureCommunicationServicesConnector: () => azureCommunicationServicesConnector,
|
|
85
|
+
azureEventGridConnector: () => azureEventGridConnector,
|
|
85
86
|
azureOpenaiConnector: () => azureOpenaiConnector,
|
|
87
|
+
azureServiceBusConnector: () => azureServiceBusConnector,
|
|
86
88
|
backblazeConnector: () => backblazeConnector,
|
|
87
89
|
bamboohrConnector: () => bamboohrConnector,
|
|
88
90
|
bannerbearConnector: () => bannerbearConnector,
|
|
@@ -786,11 +788,11 @@ function declarativeRestConnector(spec) {
|
|
|
786
788
|
const op = readOperation(spec, inv.capabilityName, "read");
|
|
787
789
|
const response = await executeRestRequest(spec, op.request, inv, requiredArgsOf(op.parameters));
|
|
788
790
|
if (response.outcome === "rate-limited") {
|
|
789
|
-
const
|
|
791
|
+
const retryAfterMs7 = response.retryAfterMs ?? DEFAULT_RETRY_AFTER_MS;
|
|
790
792
|
throw new ProviderRateLimited(
|
|
791
|
-
`${spec.displayName} ${inv.capabilityName} rate limit (429); retry after ${
|
|
793
|
+
`${spec.displayName} ${inv.capabilityName} rate limit (429); retry after ${retryAfterMs7}ms`,
|
|
792
794
|
inv.source.id,
|
|
793
|
-
{ status: 429, body: response.data, retryAfterMs:
|
|
795
|
+
{ status: 429, body: response.data, retryAfterMs: retryAfterMs7 }
|
|
794
796
|
);
|
|
795
797
|
}
|
|
796
798
|
if (response.outcome === "conflict") {
|
|
@@ -11928,11 +11930,11 @@ async function azureRequest(credentials, inv, method, pathSegments, query2 = new
|
|
|
11928
11930
|
throw new CredentialsExpired(`Azure Blob Storage rejected credentials (${response.status})`, inv.source.id);
|
|
11929
11931
|
}
|
|
11930
11932
|
if (response.status === 429 || response.status === 503) {
|
|
11931
|
-
const
|
|
11933
|
+
const retryAfterMs7 = retryAfter(response.headers.get("retry-after"));
|
|
11932
11934
|
throw new ProviderRateLimited(
|
|
11933
|
-
`Azure Blob Storage rate limit (${response.status}); retry after ${
|
|
11935
|
+
`Azure Blob Storage rate limit (${response.status}); retry after ${retryAfterMs7}ms`,
|
|
11934
11936
|
inv.source.id,
|
|
11935
|
-
{ status: response.status, retryAfterMs:
|
|
11937
|
+
{ status: response.status, retryAfterMs: retryAfterMs7 }
|
|
11936
11938
|
);
|
|
11937
11939
|
}
|
|
11938
11940
|
if (!response.ok) {
|
|
@@ -12205,6 +12207,878 @@ function numberOrUndefined(value) {
|
|
|
12205
12207
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
12206
12208
|
}
|
|
12207
12209
|
|
|
12210
|
+
// src/connectors/adapters/azure-event-grid.ts
|
|
12211
|
+
import { createHash as createHash3, timingSafeEqual } from "crypto";
|
|
12212
|
+
var API_VERSION2 = "2018-01-01";
|
|
12213
|
+
var MAX_BATCH_BYTES = 1024 * 1024;
|
|
12214
|
+
var MAX_EVENTS = 5e3;
|
|
12215
|
+
var EVENT_GRID_SUFFIXES = [
|
|
12216
|
+
".eventgrid.azure.net",
|
|
12217
|
+
".eventgrid.azure.us",
|
|
12218
|
+
".eventgrid.azure.cn"
|
|
12219
|
+
];
|
|
12220
|
+
var azureEventGridConnector = {
|
|
12221
|
+
manifest: {
|
|
12222
|
+
kind: "azure-event-grid",
|
|
12223
|
+
displayName: "Azure Event Grid",
|
|
12224
|
+
description: "Publish Event Grid and CloudEvents batches to customer topics and authenticate inbound subscription validation and event delivery.",
|
|
12225
|
+
auth: {
|
|
12226
|
+
kind: "api-key",
|
|
12227
|
+
hint: "JSON containing endpoint, accessKey, and deliverySecret. endpoint is the Azure custom topic or domain /api/events URL. Configure deliverySecret as the static x-tangle-eventgrid-secret delivery header on each Event Grid subscription."
|
|
12228
|
+
},
|
|
12229
|
+
category: "webhook",
|
|
12230
|
+
defaultConsistencyModel: "advisory",
|
|
12231
|
+
rateLimit: { requests: 600, windowMs: 6e4, scope: "data-source" },
|
|
12232
|
+
capabilities: [
|
|
12233
|
+
mutationCapability2(
|
|
12234
|
+
"events.publish",
|
|
12235
|
+
"Publish a bounded batch using the native Azure Event Grid event schema.",
|
|
12236
|
+
"Events require id, eventType, subject, eventTime, dataVersion, and data."
|
|
12237
|
+
),
|
|
12238
|
+
mutationCapability2(
|
|
12239
|
+
"cloudEvents.publish",
|
|
12240
|
+
"Publish a bounded CloudEvents 1.0 batch.",
|
|
12241
|
+
"CloudEvents require id, source, type, specversion=1.0, and data."
|
|
12242
|
+
)
|
|
12243
|
+
]
|
|
12244
|
+
},
|
|
12245
|
+
async executeMutation(inv) {
|
|
12246
|
+
const credentials = parseCredentials(inv.source.credentials, inv.source.id);
|
|
12247
|
+
const events = inv.capabilityName === "events.publish" ? eventGridEvents(inv.args.events) : inv.capabilityName === "cloudEvents.publish" ? cloudEvents(inv.args.events) : void 0;
|
|
12248
|
+
if (!events) throw new Error(`azure-event-grid: unknown mutation capability ${inv.capabilityName}`);
|
|
12249
|
+
const body = JSON.stringify(events);
|
|
12250
|
+
if (Buffer.byteLength(body) > MAX_BATCH_BYTES) {
|
|
12251
|
+
throw new Error(`Azure Event Grid batch exceeds ${MAX_BATCH_BYTES} bytes`);
|
|
12252
|
+
}
|
|
12253
|
+
const response = await fetch(publishUrl(credentials.endpoint), {
|
|
12254
|
+
method: "POST",
|
|
12255
|
+
headers: {
|
|
12256
|
+
"aeg-sas-key": credentials.accessKey,
|
|
12257
|
+
"content-type": inv.capabilityName === "cloudEvents.publish" ? "application/cloudevents-batch+json; charset=utf-8" : "application/json; charset=utf-8",
|
|
12258
|
+
accept: "application/json"
|
|
12259
|
+
},
|
|
12260
|
+
body
|
|
12261
|
+
});
|
|
12262
|
+
const responseBody = await readBoundedText(response, 256 * 1024);
|
|
12263
|
+
if (!response.ok) throwEventGridError(response, responseBody, inv);
|
|
12264
|
+
return {
|
|
12265
|
+
status: "committed",
|
|
12266
|
+
data: { accepted: true, count: events.length, requestId: response.headers.get("x-ms-request-id") ?? void 0 },
|
|
12267
|
+
committedAt: Date.now(),
|
|
12268
|
+
idempotentReplay: false
|
|
12269
|
+
};
|
|
12270
|
+
},
|
|
12271
|
+
verifySignature({ headers, source }) {
|
|
12272
|
+
let credentials;
|
|
12273
|
+
try {
|
|
12274
|
+
credentials = parseCredentials(source.credentials, source.id);
|
|
12275
|
+
} catch {
|
|
12276
|
+
return { valid: false, reason: "Azure Event Grid credentials are invalid" };
|
|
12277
|
+
}
|
|
12278
|
+
const provided = headerValue(headers, "x-tangle-eventgrid-secret");
|
|
12279
|
+
if (!provided) return { valid: false, reason: "Missing x-tangle-eventgrid-secret delivery header" };
|
|
12280
|
+
const expectedDigest = createHash3("sha256").update(credentials.deliverySecret).digest();
|
|
12281
|
+
const providedDigest = createHash3("sha256").update(provided).digest();
|
|
12282
|
+
return timingSafeEqual(expectedDigest, providedDigest) ? { valid: true } : { valid: false, reason: "Invalid x-tangle-eventgrid-secret delivery header" };
|
|
12283
|
+
},
|
|
12284
|
+
async handleInboundEvent({ rawBody }) {
|
|
12285
|
+
if (Buffer.byteLength(rawBody) > MAX_BATCH_BYTES) {
|
|
12286
|
+
throw new Error(`Azure Event Grid delivery exceeds ${MAX_BATCH_BYTES} bytes`);
|
|
12287
|
+
}
|
|
12288
|
+
let parsed;
|
|
12289
|
+
try {
|
|
12290
|
+
parsed = JSON.parse(rawBody);
|
|
12291
|
+
} catch {
|
|
12292
|
+
throw new Error("Azure Event Grid delivery body must be valid JSON");
|
|
12293
|
+
}
|
|
12294
|
+
const entries = Array.isArray(parsed) ? parsed : [parsed];
|
|
12295
|
+
if (entries.length > MAX_EVENTS) throw new Error(`Azure Event Grid delivery exceeds ${MAX_EVENTS} events`);
|
|
12296
|
+
const validation = entries.find((entry) => isValidationEvent(entry));
|
|
12297
|
+
if (validation && isRecord(validation.data) && typeof validation.data.validationCode === "string") {
|
|
12298
|
+
return {
|
|
12299
|
+
events: [],
|
|
12300
|
+
response: { status: 200, body: { validationResponse: validation.data.validationCode } }
|
|
12301
|
+
};
|
|
12302
|
+
}
|
|
12303
|
+
return {
|
|
12304
|
+
events: entries.map((entry, index) => inboundEvent(entry, index))
|
|
12305
|
+
};
|
|
12306
|
+
},
|
|
12307
|
+
async test(source) {
|
|
12308
|
+
try {
|
|
12309
|
+
parseCredentials(source.credentials, source.id);
|
|
12310
|
+
return { ok: true };
|
|
12311
|
+
} catch (error) {
|
|
12312
|
+
return { ok: false, reason: error instanceof Error ? error.message : "Azure Event Grid credentials are invalid" };
|
|
12313
|
+
}
|
|
12314
|
+
}
|
|
12315
|
+
};
|
|
12316
|
+
function mutationCapability2(name, description, eventDescription) {
|
|
12317
|
+
return {
|
|
12318
|
+
name,
|
|
12319
|
+
class: "mutation",
|
|
12320
|
+
description,
|
|
12321
|
+
parameters: {
|
|
12322
|
+
type: "object",
|
|
12323
|
+
properties: {
|
|
12324
|
+
events: {
|
|
12325
|
+
type: "array",
|
|
12326
|
+
minItems: 1,
|
|
12327
|
+
maxItems: MAX_EVENTS,
|
|
12328
|
+
description: eventDescription
|
|
12329
|
+
}
|
|
12330
|
+
},
|
|
12331
|
+
required: ["events"]
|
|
12332
|
+
},
|
|
12333
|
+
cas: "none",
|
|
12334
|
+
externalEffect: true
|
|
12335
|
+
};
|
|
12336
|
+
}
|
|
12337
|
+
function parseCredentials(credentials, dataSourceId) {
|
|
12338
|
+
if (credentials.kind !== "api-key") {
|
|
12339
|
+
throw new CredentialsExpired("Azure Event Grid requires a credential JSON bundle", dataSourceId);
|
|
12340
|
+
}
|
|
12341
|
+
let parsed;
|
|
12342
|
+
try {
|
|
12343
|
+
parsed = JSON.parse(credentials.apiKey);
|
|
12344
|
+
} catch {
|
|
12345
|
+
throw new CredentialsExpired("Azure Event Grid credentials must be valid JSON", dataSourceId);
|
|
12346
|
+
}
|
|
12347
|
+
if (!isRecord(parsed)) throw new CredentialsExpired("Azure Event Grid credentials must be a JSON object", dataSourceId);
|
|
12348
|
+
const endpointValue = credentialString(parsed.endpoint, "endpoint", dataSourceId);
|
|
12349
|
+
const accessKey = credentialString(parsed.accessKey, "accessKey", dataSourceId);
|
|
12350
|
+
const deliverySecret = credentialString(parsed.deliverySecret, "deliverySecret", dataSourceId);
|
|
12351
|
+
let endpoint;
|
|
12352
|
+
try {
|
|
12353
|
+
endpoint = new URL(endpointValue);
|
|
12354
|
+
} catch {
|
|
12355
|
+
throw new CredentialsExpired("Azure Event Grid endpoint is invalid", dataSourceId);
|
|
12356
|
+
}
|
|
12357
|
+
if (endpoint.protocol !== "https:" || endpoint.username || endpoint.password || endpoint.port || endpoint.search || endpoint.hash || endpoint.pathname.replace(/\/$/, "").toLowerCase() !== "/api/events" || !EVENT_GRID_SUFFIXES.some((suffix) => endpoint.hostname.endsWith(suffix))) {
|
|
12358
|
+
throw new CredentialsExpired("Azure Event Grid endpoint must be a public Azure custom topic or domain /api/events URL", dataSourceId);
|
|
12359
|
+
}
|
|
12360
|
+
if (!canonicalBase64(accessKey) || Buffer.from(accessKey, "base64").length < 16) {
|
|
12361
|
+
throw new CredentialsExpired("Azure Event Grid accessKey must be a valid base64 topic key", dataSourceId);
|
|
12362
|
+
}
|
|
12363
|
+
if (deliverySecret.length < 32 || deliverySecret.length > 4096) {
|
|
12364
|
+
throw new CredentialsExpired("Azure Event Grid deliverySecret must contain 32 to 4096 characters", dataSourceId);
|
|
12365
|
+
}
|
|
12366
|
+
endpoint.pathname = "/api/events";
|
|
12367
|
+
return { endpoint, accessKey, deliverySecret };
|
|
12368
|
+
}
|
|
12369
|
+
function publishUrl(endpoint) {
|
|
12370
|
+
const url = new URL(endpoint);
|
|
12371
|
+
url.searchParams.set("api-version", API_VERSION2);
|
|
12372
|
+
return url;
|
|
12373
|
+
}
|
|
12374
|
+
function eventGridEvents(value) {
|
|
12375
|
+
const entries = eventArray(value);
|
|
12376
|
+
return entries.map((entry, index) => {
|
|
12377
|
+
const result = {
|
|
12378
|
+
id: requiredString4(entry.id, `events[${index}].id`),
|
|
12379
|
+
eventType: requiredString4(entry.eventType, `events[${index}].eventType`),
|
|
12380
|
+
subject: requiredString4(entry.subject, `events[${index}].subject`),
|
|
12381
|
+
eventTime: isoDate(entry.eventTime, `events[${index}].eventTime`),
|
|
12382
|
+
dataVersion: requiredString4(entry.dataVersion, `events[${index}].dataVersion`),
|
|
12383
|
+
data: requiredJsonValue(entry.data, `events[${index}].data`)
|
|
12384
|
+
};
|
|
12385
|
+
if (entry.topic !== void 0) result.topic = requiredString4(entry.topic, `events[${index}].topic`);
|
|
12386
|
+
return result;
|
|
12387
|
+
});
|
|
12388
|
+
}
|
|
12389
|
+
function cloudEvents(value) {
|
|
12390
|
+
const entries = eventArray(value);
|
|
12391
|
+
return entries.map((entry, index) => {
|
|
12392
|
+
if (entry.specversion !== "1.0") throw new Error(`events[${index}].specversion must be 1.0`);
|
|
12393
|
+
const result = {
|
|
12394
|
+
specversion: "1.0",
|
|
12395
|
+
id: requiredString4(entry.id, `events[${index}].id`),
|
|
12396
|
+
source: requiredString4(entry.source, `events[${index}].source`),
|
|
12397
|
+
type: requiredString4(entry.type, `events[${index}].type`),
|
|
12398
|
+
data: requiredJsonValue(entry.data, `events[${index}].data`)
|
|
12399
|
+
};
|
|
12400
|
+
if (entry.subject !== void 0) result.subject = requiredString4(entry.subject, `events[${index}].subject`);
|
|
12401
|
+
if (entry.time !== void 0) result.time = isoDate(entry.time, `events[${index}].time`);
|
|
12402
|
+
if (entry.datacontenttype !== void 0) result.datacontenttype = requiredString4(entry.datacontenttype, `events[${index}].datacontenttype`);
|
|
12403
|
+
if (entry.dataschema !== void 0) result.dataschema = requiredString4(entry.dataschema, `events[${index}].dataschema`);
|
|
12404
|
+
return result;
|
|
12405
|
+
});
|
|
12406
|
+
}
|
|
12407
|
+
function eventArray(value) {
|
|
12408
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > MAX_EVENTS) {
|
|
12409
|
+
throw new Error(`events must contain 1 to ${MAX_EVENTS} entries`);
|
|
12410
|
+
}
|
|
12411
|
+
return value.map((entry, index) => {
|
|
12412
|
+
if (!isRecord(entry)) throw new Error(`events[${index}] must be an object`);
|
|
12413
|
+
return entry;
|
|
12414
|
+
});
|
|
12415
|
+
}
|
|
12416
|
+
function inboundEvent(entry, index) {
|
|
12417
|
+
if (!isRecord(entry)) throw new Error(`Azure Event Grid delivery entry ${index} must be an object`);
|
|
12418
|
+
const eventType = typeof entry.eventType === "string" ? entry.eventType : typeof entry.type === "string" ? entry.type : "azure.event-grid.event";
|
|
12419
|
+
return {
|
|
12420
|
+
eventType,
|
|
12421
|
+
providerEventId: typeof entry.id === "string" ? entry.id : void 0,
|
|
12422
|
+
payload: entry
|
|
12423
|
+
};
|
|
12424
|
+
}
|
|
12425
|
+
function isValidationEvent(value) {
|
|
12426
|
+
return isRecord(value) && value.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent";
|
|
12427
|
+
}
|
|
12428
|
+
function throwEventGridError(response, body, inv) {
|
|
12429
|
+
const redacted = body.replace(/[A-Za-z0-9+/]{32,}={0,2}/g, "[redacted]").slice(0, 500);
|
|
12430
|
+
if (response.status === 401) {
|
|
12431
|
+
throw new CredentialsExpired("Azure Event Grid rejected the topic access key", inv.source.id, {
|
|
12432
|
+
status: response.status,
|
|
12433
|
+
body: redacted
|
|
12434
|
+
});
|
|
12435
|
+
}
|
|
12436
|
+
if (response.status === 403) {
|
|
12437
|
+
throw new ProviderConfigError("Azure Event Grid topic policy rejected publishing", inv.source.id, {
|
|
12438
|
+
status: response.status,
|
|
12439
|
+
body: redacted
|
|
12440
|
+
});
|
|
12441
|
+
}
|
|
12442
|
+
if (response.status === 429 || response.status === 503) {
|
|
12443
|
+
throw new ProviderRateLimited("Azure Event Grid is throttling publishes", inv.source.id, {
|
|
12444
|
+
status: response.status,
|
|
12445
|
+
body: redacted,
|
|
12446
|
+
retryAfterMs: retryAfterMs3(response.headers.get("retry-after"))
|
|
12447
|
+
});
|
|
12448
|
+
}
|
|
12449
|
+
throw new Error(`Azure Event Grid publish failed with HTTP ${response.status}: ${redacted}`);
|
|
12450
|
+
}
|
|
12451
|
+
async function readBoundedText(response, limit) {
|
|
12452
|
+
const declared = Number(response.headers.get("content-length"));
|
|
12453
|
+
if (Number.isFinite(declared) && declared > limit) throw new Error(`Azure Event Grid response exceeds ${limit} bytes`);
|
|
12454
|
+
if (!response.body) return "";
|
|
12455
|
+
const reader = response.body.getReader();
|
|
12456
|
+
const chunks = [];
|
|
12457
|
+
let size = 0;
|
|
12458
|
+
while (true) {
|
|
12459
|
+
const { done, value } = await reader.read();
|
|
12460
|
+
if (done) break;
|
|
12461
|
+
size += value.byteLength;
|
|
12462
|
+
if (size > limit) {
|
|
12463
|
+
await reader.cancel();
|
|
12464
|
+
throw new Error(`Azure Event Grid response exceeds ${limit} bytes`);
|
|
12465
|
+
}
|
|
12466
|
+
chunks.push(value);
|
|
12467
|
+
}
|
|
12468
|
+
const body = new Uint8Array(size);
|
|
12469
|
+
let offset = 0;
|
|
12470
|
+
for (const chunk of chunks) {
|
|
12471
|
+
body.set(chunk, offset);
|
|
12472
|
+
offset += chunk.byteLength;
|
|
12473
|
+
}
|
|
12474
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(body);
|
|
12475
|
+
}
|
|
12476
|
+
function headerValue(headers, name) {
|
|
12477
|
+
const match = Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
|
|
12478
|
+
return Array.isArray(match) ? match[0] : match;
|
|
12479
|
+
}
|
|
12480
|
+
function credentialString(value, field, dataSourceId) {
|
|
12481
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
12482
|
+
throw new CredentialsExpired(`Azure Event Grid ${field} is missing`, dataSourceId);
|
|
12483
|
+
}
|
|
12484
|
+
return value.trim();
|
|
12485
|
+
}
|
|
12486
|
+
function requiredString4(value, field) {
|
|
12487
|
+
if (typeof value !== "string" || value.trim() === "" || value.length > 4096) {
|
|
12488
|
+
throw new Error(`${field} must be a non-empty string no longer than 4096 characters`);
|
|
12489
|
+
}
|
|
12490
|
+
return value;
|
|
12491
|
+
}
|
|
12492
|
+
function isoDate(value, field) {
|
|
12493
|
+
const parsed = requiredString4(value, field);
|
|
12494
|
+
const date = new Date(parsed);
|
|
12495
|
+
if (!Number.isFinite(date.getTime())) throw new Error(`${field} must be an ISO 8601 timestamp`);
|
|
12496
|
+
return date.toISOString();
|
|
12497
|
+
}
|
|
12498
|
+
function requiredJsonValue(value, field) {
|
|
12499
|
+
if (value === void 0) throw new Error(`${field} is required`);
|
|
12500
|
+
try {
|
|
12501
|
+
if (JSON.stringify(value) === void 0) throw new Error("not JSON");
|
|
12502
|
+
} catch {
|
|
12503
|
+
throw new Error(`${field} must be JSON-serializable`);
|
|
12504
|
+
}
|
|
12505
|
+
return value;
|
|
12506
|
+
}
|
|
12507
|
+
function canonicalBase64(value) {
|
|
12508
|
+
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value) && Buffer.from(value, "base64").toString("base64").replace(/=+$/, "") === value.replace(/=+$/, "");
|
|
12509
|
+
}
|
|
12510
|
+
function retryAfterMs3(value) {
|
|
12511
|
+
if (!value) return 6e4;
|
|
12512
|
+
const seconds = Number(value);
|
|
12513
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
12514
|
+
const date = Date.parse(value);
|
|
12515
|
+
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
|
|
12516
|
+
}
|
|
12517
|
+
function isRecord(value) {
|
|
12518
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12519
|
+
}
|
|
12520
|
+
|
|
12521
|
+
// src/connectors/adapters/azure-service-bus.ts
|
|
12522
|
+
import { createHmac as createHmac3 } from "crypto";
|
|
12523
|
+
var MANAGEMENT_API_VERSION = "2017-04";
|
|
12524
|
+
var MAX_RESPONSE_BYTES2 = 8 * 1024 * 1024;
|
|
12525
|
+
var MAX_MESSAGE_BYTES = 256 * 1024;
|
|
12526
|
+
var SERVICE_BUS_SUFFIXES = [
|
|
12527
|
+
".servicebus.windows.net",
|
|
12528
|
+
".servicebus.usgovcloudapi.net",
|
|
12529
|
+
".servicebus.chinacloudapi.cn",
|
|
12530
|
+
".servicebus.cloudapi.de"
|
|
12531
|
+
];
|
|
12532
|
+
var azureServiceBusConnector = {
|
|
12533
|
+
manifest: {
|
|
12534
|
+
kind: "azure-service-bus",
|
|
12535
|
+
displayName: "Azure Service Bus",
|
|
12536
|
+
description: "Send and receive Azure Service Bus queue and topic messages and discover queue, topic, and subscription entities with a customer-owned SAS connection string.",
|
|
12537
|
+
auth: {
|
|
12538
|
+
kind: "api-key",
|
|
12539
|
+
hint: "Azure Service Bus connection string containing Endpoint, SharedAccessKeyName, and SharedAccessKey. EntityPath is supported and restricts this connection to that queue or topic."
|
|
12540
|
+
},
|
|
12541
|
+
category: "webhook",
|
|
12542
|
+
// The REST receive-and-delete operation destructively consumes a message,
|
|
12543
|
+
// and message delivery is at-least-once. Acceptance is not proof that a
|
|
12544
|
+
// downstream consumer processed the payload exactly once.
|
|
12545
|
+
defaultConsistencyModel: "advisory",
|
|
12546
|
+
rateLimit: { requests: 600, windowMs: 6e4, scope: "data-source" },
|
|
12547
|
+
capabilities: [
|
|
12548
|
+
readCapability2("queues.list", "List queues visible to a namespace-level Manage policy.", listProperties()),
|
|
12549
|
+
readCapability2("queues.get", "Get one queue description and message counts.", {
|
|
12550
|
+
queue: { type: "string" }
|
|
12551
|
+
}, ["queue"]),
|
|
12552
|
+
readCapability2("topics.list", "List topics visible to a namespace-level Manage policy.", listProperties()),
|
|
12553
|
+
readCapability2("topics.get", "Get one topic description and message counts.", {
|
|
12554
|
+
topic: { type: "string" }
|
|
12555
|
+
}, ["topic"]),
|
|
12556
|
+
readCapability2("subscriptions.list", "List subscriptions for one topic.", {
|
|
12557
|
+
topic: { type: "string" },
|
|
12558
|
+
...listProperties()
|
|
12559
|
+
}, ["topic"]),
|
|
12560
|
+
readCapability2("subscriptions.get", "Get one topic subscription description and message counts.", {
|
|
12561
|
+
topic: { type: "string" },
|
|
12562
|
+
subscription: { type: "string" }
|
|
12563
|
+
}, ["topic", "subscription"]),
|
|
12564
|
+
mutationCapability3("queues.send", "Send a UTF-8 or base64 message to a queue.", sendProperties("queue"), ["queue", "content"]),
|
|
12565
|
+
mutationCapability3("topics.send", "Publish a UTF-8 or base64 message to a topic.", sendProperties("topic"), ["topic", "content"]),
|
|
12566
|
+
mutationCapability3("queues.receiveDelete", "Receive and permanently delete the next queue message.", {
|
|
12567
|
+
queue: { type: "string" },
|
|
12568
|
+
timeoutSeconds: { type: "integer", minimum: 0, maximum: 55 }
|
|
12569
|
+
}, ["queue"]),
|
|
12570
|
+
mutationCapability3("subscriptions.receiveDelete", "Receive and permanently delete the next message from a topic subscription.", {
|
|
12571
|
+
topic: { type: "string" },
|
|
12572
|
+
subscription: { type: "string" },
|
|
12573
|
+
timeoutSeconds: { type: "integer", minimum: 0, maximum: 55 }
|
|
12574
|
+
}, ["topic", "subscription"]),
|
|
12575
|
+
mutationCapability3("queues.deadLetters.receiveDelete", "Receive and permanently delete the next queue dead-letter message.", {
|
|
12576
|
+
queue: { type: "string" },
|
|
12577
|
+
timeoutSeconds: { type: "integer", minimum: 0, maximum: 55 }
|
|
12578
|
+
}, ["queue"]),
|
|
12579
|
+
mutationCapability3("subscriptions.deadLetters.receiveDelete", "Receive and permanently delete the next subscription dead-letter message.", {
|
|
12580
|
+
topic: { type: "string" },
|
|
12581
|
+
subscription: { type: "string" },
|
|
12582
|
+
timeoutSeconds: { type: "integer", minimum: 0, maximum: 55 }
|
|
12583
|
+
}, ["topic", "subscription"])
|
|
12584
|
+
]
|
|
12585
|
+
},
|
|
12586
|
+
async executeRead(inv) {
|
|
12587
|
+
const credentials = parseConnectionString(inv.source.credentials, inv.source.id);
|
|
12588
|
+
let path;
|
|
12589
|
+
let list2 = false;
|
|
12590
|
+
switch (inv.capabilityName) {
|
|
12591
|
+
case "queues.list":
|
|
12592
|
+
requireNamespacePolicy(credentials, "queues.list");
|
|
12593
|
+
path = "$Resources/Queues";
|
|
12594
|
+
list2 = true;
|
|
12595
|
+
break;
|
|
12596
|
+
case "queues.get":
|
|
12597
|
+
path = entityName(inv.args.queue, "queue");
|
|
12598
|
+
enforceEntityPath(credentials, path);
|
|
12599
|
+
break;
|
|
12600
|
+
case "topics.list":
|
|
12601
|
+
requireNamespacePolicy(credentials, "topics.list");
|
|
12602
|
+
path = "$Resources/Topics";
|
|
12603
|
+
list2 = true;
|
|
12604
|
+
break;
|
|
12605
|
+
case "topics.get":
|
|
12606
|
+
path = entityName(inv.args.topic, "topic");
|
|
12607
|
+
enforceEntityPath(credentials, path);
|
|
12608
|
+
break;
|
|
12609
|
+
case "subscriptions.list": {
|
|
12610
|
+
const topic = entityName(inv.args.topic, "topic");
|
|
12611
|
+
enforceEntityPath(credentials, topic);
|
|
12612
|
+
path = `${topic}/Subscriptions/`;
|
|
12613
|
+
list2 = true;
|
|
12614
|
+
break;
|
|
12615
|
+
}
|
|
12616
|
+
case "subscriptions.get": {
|
|
12617
|
+
const topic = entityName(inv.args.topic, "topic");
|
|
12618
|
+
enforceEntityPath(credentials, topic);
|
|
12619
|
+
path = `${topic}/Subscriptions/${entityName(inv.args.subscription, "subscription")}`;
|
|
12620
|
+
break;
|
|
12621
|
+
}
|
|
12622
|
+
default:
|
|
12623
|
+
throw new Error(`azure-service-bus: unknown read capability ${inv.capabilityName}`);
|
|
12624
|
+
}
|
|
12625
|
+
const query2 = list2 ? managementListQuery(inv.args) : new URLSearchParams({ "api-version": MANAGEMENT_API_VERSION });
|
|
12626
|
+
const result = await serviceBusRequest(
|
|
12627
|
+
credentials,
|
|
12628
|
+
inv,
|
|
12629
|
+
"GET",
|
|
12630
|
+
path,
|
|
12631
|
+
query2
|
|
12632
|
+
);
|
|
12633
|
+
const xml = decodeUtf82(result.body);
|
|
12634
|
+
const data4 = list2 ? parseAtomFeed(xml) : parseAtomEntry(xml);
|
|
12635
|
+
return { data: data4, fetchedAt: Date.now() };
|
|
12636
|
+
},
|
|
12637
|
+
async executeMutation(inv) {
|
|
12638
|
+
const credentials = parseConnectionString(inv.source.credentials, inv.source.id);
|
|
12639
|
+
let data4;
|
|
12640
|
+
switch (inv.capabilityName) {
|
|
12641
|
+
case "queues.send":
|
|
12642
|
+
data4 = await sendMessage(credentials, inv, entityName(inv.args.queue, "queue"));
|
|
12643
|
+
break;
|
|
12644
|
+
case "topics.send":
|
|
12645
|
+
data4 = await sendMessage(credentials, inv, entityName(inv.args.topic, "topic"));
|
|
12646
|
+
break;
|
|
12647
|
+
case "queues.receiveDelete":
|
|
12648
|
+
data4 = await receiveAndDelete(credentials, inv, entityName(inv.args.queue, "queue"));
|
|
12649
|
+
break;
|
|
12650
|
+
case "subscriptions.receiveDelete":
|
|
12651
|
+
data4 = await receiveAndDelete(
|
|
12652
|
+
credentials,
|
|
12653
|
+
inv,
|
|
12654
|
+
`${entityName(inv.args.topic, "topic")}/subscriptions/${entityName(inv.args.subscription, "subscription")}`
|
|
12655
|
+
);
|
|
12656
|
+
break;
|
|
12657
|
+
case "queues.deadLetters.receiveDelete":
|
|
12658
|
+
data4 = await receiveAndDelete(
|
|
12659
|
+
credentials,
|
|
12660
|
+
inv,
|
|
12661
|
+
`${entityName(inv.args.queue, "queue")}/$DeadLetterQueue`
|
|
12662
|
+
);
|
|
12663
|
+
break;
|
|
12664
|
+
case "subscriptions.deadLetters.receiveDelete":
|
|
12665
|
+
data4 = await receiveAndDelete(
|
|
12666
|
+
credentials,
|
|
12667
|
+
inv,
|
|
12668
|
+
`${entityName(inv.args.topic, "topic")}/subscriptions/${entityName(inv.args.subscription, "subscription")}/$DeadLetterQueue`
|
|
12669
|
+
);
|
|
12670
|
+
break;
|
|
12671
|
+
default:
|
|
12672
|
+
throw new Error(`azure-service-bus: unknown mutation capability ${inv.capabilityName}`);
|
|
12673
|
+
}
|
|
12674
|
+
return {
|
|
12675
|
+
status: "committed",
|
|
12676
|
+
data: data4,
|
|
12677
|
+
committedAt: Date.now(),
|
|
12678
|
+
idempotentReplay: false
|
|
12679
|
+
};
|
|
12680
|
+
},
|
|
12681
|
+
async test(source) {
|
|
12682
|
+
try {
|
|
12683
|
+
parseConnectionString(source.credentials, source.id);
|
|
12684
|
+
return { ok: true };
|
|
12685
|
+
} catch (error) {
|
|
12686
|
+
return { ok: false, reason: error instanceof Error ? error.message : "Azure Service Bus connection string is invalid" };
|
|
12687
|
+
}
|
|
12688
|
+
}
|
|
12689
|
+
};
|
|
12690
|
+
function readCapability2(name, description, properties, required = []) {
|
|
12691
|
+
return {
|
|
12692
|
+
name,
|
|
12693
|
+
class: "read",
|
|
12694
|
+
description,
|
|
12695
|
+
parameters: { type: "object", properties, ...required.length ? { required } : {} }
|
|
12696
|
+
};
|
|
12697
|
+
}
|
|
12698
|
+
function mutationCapability3(name, description, properties, required) {
|
|
12699
|
+
return {
|
|
12700
|
+
name,
|
|
12701
|
+
class: "mutation",
|
|
12702
|
+
description,
|
|
12703
|
+
parameters: { type: "object", properties, required },
|
|
12704
|
+
cas: "none",
|
|
12705
|
+
externalEffect: true
|
|
12706
|
+
};
|
|
12707
|
+
}
|
|
12708
|
+
function sendProperties(entity) {
|
|
12709
|
+
return {
|
|
12710
|
+
[entity]: { type: "string" },
|
|
12711
|
+
content: { type: "string", description: "UTF-8 text or canonical base64 message body." },
|
|
12712
|
+
encoding: { type: "string", enum: ["utf-8", "base64"], default: "utf-8" },
|
|
12713
|
+
contentType: { type: "string" },
|
|
12714
|
+
brokerProperties: {
|
|
12715
|
+
type: "object",
|
|
12716
|
+
description: "Allowed broker properties such as MessageId, CorrelationId, Label, SessionId, TimeToLive, and ScheduledEnqueueTimeUtc."
|
|
12717
|
+
},
|
|
12718
|
+
applicationProperties: {
|
|
12719
|
+
type: "object",
|
|
12720
|
+
description: "Application property headers with string, number, or boolean values."
|
|
12721
|
+
}
|
|
12722
|
+
};
|
|
12723
|
+
}
|
|
12724
|
+
function listProperties() {
|
|
12725
|
+
return {
|
|
12726
|
+
skip: { type: "integer", minimum: 0 },
|
|
12727
|
+
top: { type: "integer", minimum: 1, maximum: 1e3 }
|
|
12728
|
+
};
|
|
12729
|
+
}
|
|
12730
|
+
function managementListQuery(args) {
|
|
12731
|
+
const query2 = new URLSearchParams({ "api-version": MANAGEMENT_API_VERSION });
|
|
12732
|
+
if (args.skip !== void 0) query2.set("$skip", String(boundedInteger(args.skip, "skip", 0, 1e6)));
|
|
12733
|
+
if (args.top !== void 0) query2.set("$top", String(boundedInteger(args.top, "top", 1, 1e3)));
|
|
12734
|
+
return query2;
|
|
12735
|
+
}
|
|
12736
|
+
function parseConnectionString(credentials, dataSourceId) {
|
|
12737
|
+
if (credentials.kind !== "api-key") {
|
|
12738
|
+
throw new CredentialsExpired("Azure Service Bus requires a connection string", dataSourceId);
|
|
12739
|
+
}
|
|
12740
|
+
const values = /* @__PURE__ */ new Map();
|
|
12741
|
+
for (const part of credentials.apiKey.split(";")) {
|
|
12742
|
+
if (!part.trim()) continue;
|
|
12743
|
+
const separator = part.indexOf("=");
|
|
12744
|
+
if (separator <= 0) {
|
|
12745
|
+
throw new CredentialsExpired("Azure Service Bus connection string is malformed", dataSourceId);
|
|
12746
|
+
}
|
|
12747
|
+
const name = part.slice(0, separator).trim().toLowerCase();
|
|
12748
|
+
if (values.has(name)) {
|
|
12749
|
+
throw new CredentialsExpired(`Azure Service Bus connection string repeats ${name}`, dataSourceId);
|
|
12750
|
+
}
|
|
12751
|
+
values.set(name, part.slice(separator + 1).trim());
|
|
12752
|
+
}
|
|
12753
|
+
const endpointValue = values.get("endpoint");
|
|
12754
|
+
const keyName = values.get("sharedaccesskeyname");
|
|
12755
|
+
const keyValue = values.get("sharedaccesskey");
|
|
12756
|
+
if (!endpointValue || !keyName || !keyValue) {
|
|
12757
|
+
throw new CredentialsExpired("Azure Service Bus connection string is missing Endpoint, SharedAccessKeyName, or SharedAccessKey", dataSourceId);
|
|
12758
|
+
}
|
|
12759
|
+
let endpoint;
|
|
12760
|
+
try {
|
|
12761
|
+
endpoint = new URL(endpointValue.replace(/^sb:/i, "https:"));
|
|
12762
|
+
} catch {
|
|
12763
|
+
throw new CredentialsExpired("Azure Service Bus Endpoint is invalid", dataSourceId);
|
|
12764
|
+
}
|
|
12765
|
+
if (endpoint.protocol !== "https:" || endpoint.username || endpoint.password || endpoint.port || endpoint.search || endpoint.hash || endpoint.pathname !== "/" || !SERVICE_BUS_SUFFIXES.some((suffix) => endpoint.hostname.endsWith(suffix))) {
|
|
12766
|
+
throw new CredentialsExpired("Azure Service Bus Endpoint must be a public Azure Service Bus namespace", dataSourceId);
|
|
12767
|
+
}
|
|
12768
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/.test(keyName)) {
|
|
12769
|
+
throw new CredentialsExpired("Azure Service Bus SharedAccessKeyName is invalid", dataSourceId);
|
|
12770
|
+
}
|
|
12771
|
+
let key;
|
|
12772
|
+
try {
|
|
12773
|
+
key = Buffer.from(keyValue, "base64");
|
|
12774
|
+
} catch {
|
|
12775
|
+
throw new CredentialsExpired("Azure Service Bus SharedAccessKey is invalid base64", dataSourceId);
|
|
12776
|
+
}
|
|
12777
|
+
if (key.length < 16 || key.toString("base64").replace(/=+$/, "") !== keyValue.replace(/=+$/, "")) {
|
|
12778
|
+
throw new CredentialsExpired("Azure Service Bus SharedAccessKey is invalid base64", dataSourceId);
|
|
12779
|
+
}
|
|
12780
|
+
const entityPathValue = values.get("entitypath");
|
|
12781
|
+
const entityPath = entityPathValue ? entityName(entityPathValue, "EntityPath") : void 0;
|
|
12782
|
+
return { endpoint, keyName, key, entityPath };
|
|
12783
|
+
}
|
|
12784
|
+
async function sendMessage(credentials, inv, entityPath) {
|
|
12785
|
+
enforceEntityPath(credentials, entityPath);
|
|
12786
|
+
const content = requiredString5(inv.args.content, "content", true);
|
|
12787
|
+
const encoding = inv.args.encoding === void 0 ? "utf-8" : enumValue(inv.args.encoding, "encoding", ["utf-8", "base64"]);
|
|
12788
|
+
const body = encoding === "base64" ? strictBase64(content) : Buffer.from(content, "utf8");
|
|
12789
|
+
if (body.byteLength > MAX_MESSAGE_BYTES) {
|
|
12790
|
+
throw new Error(`Azure Service Bus message exceeds ${MAX_MESSAGE_BYTES} bytes`);
|
|
12791
|
+
}
|
|
12792
|
+
const headers = {
|
|
12793
|
+
"content-type": inv.args.contentType === void 0 ? "application/octet-stream" : requiredHeaderValue(inv.args.contentType, "contentType")
|
|
12794
|
+
};
|
|
12795
|
+
const brokerProperties = allowedBrokerProperties(inv.args.brokerProperties);
|
|
12796
|
+
if (brokerProperties) {
|
|
12797
|
+
const serializedBrokerProperties = JSON.stringify(brokerProperties);
|
|
12798
|
+
if (Buffer.byteLength(serializedBrokerProperties) > 16 * 1024) {
|
|
12799
|
+
throw new Error("brokerProperties exceeds 16384 bytes");
|
|
12800
|
+
}
|
|
12801
|
+
headers.BrokerProperties = serializedBrokerProperties;
|
|
12802
|
+
}
|
|
12803
|
+
Object.assign(headers, applicationPropertyHeaders(inv.args.applicationProperties));
|
|
12804
|
+
const result = await serviceBusRequest(credentials, inv, "POST", `${entityPath}/messages`, void 0, headers, body);
|
|
12805
|
+
return {
|
|
12806
|
+
accepted: true,
|
|
12807
|
+
entityPath,
|
|
12808
|
+
size: body.byteLength,
|
|
12809
|
+
location: result.response.headers.get("location") ?? void 0
|
|
12810
|
+
};
|
|
12811
|
+
}
|
|
12812
|
+
async function receiveAndDelete(credentials, inv, entityPath) {
|
|
12813
|
+
enforceEntityPath(credentials, entityPath);
|
|
12814
|
+
const timeoutSeconds = inv.args.timeoutSeconds === void 0 ? 0 : boundedInteger(inv.args.timeoutSeconds, "timeoutSeconds", 0, 55);
|
|
12815
|
+
const result = await serviceBusRequest(
|
|
12816
|
+
credentials,
|
|
12817
|
+
inv,
|
|
12818
|
+
"DELETE",
|
|
12819
|
+
`${entityPath}/messages/head`,
|
|
12820
|
+
new URLSearchParams({ timeout: String(timeoutSeconds) }),
|
|
12821
|
+
void 0,
|
|
12822
|
+
void 0,
|
|
12823
|
+
[200, 204]
|
|
12824
|
+
);
|
|
12825
|
+
if (result.response.status === 204) return { message: null };
|
|
12826
|
+
const brokerPropertiesHeader = result.response.headers.get("brokerproperties");
|
|
12827
|
+
let brokerProperties;
|
|
12828
|
+
if (brokerPropertiesHeader) {
|
|
12829
|
+
try {
|
|
12830
|
+
brokerProperties = JSON.parse(brokerPropertiesHeader);
|
|
12831
|
+
} catch {
|
|
12832
|
+
throw new Error("Azure Service Bus returned invalid BrokerProperties JSON");
|
|
12833
|
+
}
|
|
12834
|
+
}
|
|
12835
|
+
return {
|
|
12836
|
+
message: {
|
|
12837
|
+
body: Buffer.from(result.body).toString("base64"),
|
|
12838
|
+
encoding: "base64",
|
|
12839
|
+
contentType: result.response.headers.get("content-type") ?? "application/octet-stream",
|
|
12840
|
+
brokerProperties,
|
|
12841
|
+
applicationProperties: responseApplicationProperties(result.response.headers)
|
|
12842
|
+
}
|
|
12843
|
+
};
|
|
12844
|
+
}
|
|
12845
|
+
async function serviceBusRequest(credentials, inv, method, path, query2, headers = {}, body, acceptedStatuses = [200, 201, 202, 204]) {
|
|
12846
|
+
const url = new URL(path.split("/").map(encodePathSegment2).join("/"), credentials.endpoint);
|
|
12847
|
+
if (query2) url.search = query2.toString();
|
|
12848
|
+
const resourceUri = `${url.origin}${url.pathname}`;
|
|
12849
|
+
const expiry = Math.floor(Date.now() / 1e3) + 300;
|
|
12850
|
+
const encodedResourceUri = encodeURIComponent(resourceUri);
|
|
12851
|
+
const signature = createHmac3("sha256", credentials.key).update(`${encodedResourceUri}
|
|
12852
|
+
${expiry}`, "utf8").digest("base64");
|
|
12853
|
+
const authorization = `SharedAccessSignature sr=${encodedResourceUri}&sig=${encodeURIComponent(signature)}&se=${expiry}&skn=${encodeURIComponent(credentials.keyName)}`;
|
|
12854
|
+
const response = await fetch(url, {
|
|
12855
|
+
method,
|
|
12856
|
+
headers: { authorization, accept: "application/atom+xml, application/xml, */*", ...headers },
|
|
12857
|
+
body: body === void 0 ? void 0 : Uint8Array.from(body).buffer
|
|
12858
|
+
});
|
|
12859
|
+
const responseBody = await readBounded(response, MAX_RESPONSE_BYTES2);
|
|
12860
|
+
if (acceptedStatuses.includes(response.status)) return { response, body: responseBody };
|
|
12861
|
+
const text = decodeUtf82(responseBody);
|
|
12862
|
+
if (response.status === 401) {
|
|
12863
|
+
throw new CredentialsExpired("Azure Service Bus rejected the shared access signature", inv.source.id, {
|
|
12864
|
+
status: response.status,
|
|
12865
|
+
body: redactProviderText(text)
|
|
12866
|
+
});
|
|
12867
|
+
}
|
|
12868
|
+
if (response.status === 403) {
|
|
12869
|
+
throw new ProviderConfigError("Azure Service Bus policy lacks permission for this operation", inv.source.id, {
|
|
12870
|
+
status: response.status,
|
|
12871
|
+
body: redactProviderText(text)
|
|
12872
|
+
});
|
|
12873
|
+
}
|
|
12874
|
+
if (response.status === 429 || response.status === 503) {
|
|
12875
|
+
throw new ProviderRateLimited("Azure Service Bus is throttling requests", inv.source.id, {
|
|
12876
|
+
status: response.status,
|
|
12877
|
+
body: redactProviderText(text),
|
|
12878
|
+
retryAfterMs: retryAfterMs4(response.headers.get("retry-after"))
|
|
12879
|
+
});
|
|
12880
|
+
}
|
|
12881
|
+
throw new Error(`Azure Service Bus request failed with HTTP ${response.status}: ${redactProviderText(text).slice(0, 500)}`);
|
|
12882
|
+
}
|
|
12883
|
+
function encodePathSegment2(segment) {
|
|
12884
|
+
if (segment === "$Resources" || segment === "$DeadLetterQueue") return segment;
|
|
12885
|
+
return encodeURIComponent(segment);
|
|
12886
|
+
}
|
|
12887
|
+
function entityName(value, field) {
|
|
12888
|
+
const name = requiredString5(value, field);
|
|
12889
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._~-]{0,259}$/.test(name)) {
|
|
12890
|
+
throw new Error(`${field} must be a valid Azure Service Bus entity name`);
|
|
12891
|
+
}
|
|
12892
|
+
return name;
|
|
12893
|
+
}
|
|
12894
|
+
function requireNamespacePolicy(credentials, capability) {
|
|
12895
|
+
if (credentials.entityPath) {
|
|
12896
|
+
throw new Error(`${capability} requires a namespace-level connection string without EntityPath`);
|
|
12897
|
+
}
|
|
12898
|
+
}
|
|
12899
|
+
function enforceEntityPath(credentials, requestedPath) {
|
|
12900
|
+
if (!credentials.entityPath) return;
|
|
12901
|
+
const normalized = requestedPath.toLowerCase();
|
|
12902
|
+
const allowed = credentials.entityPath.toLowerCase();
|
|
12903
|
+
if (normalized !== allowed && normalized !== `${allowed}/$deadletterqueue` && !normalized.startsWith(`${allowed}/subscriptions/`)) {
|
|
12904
|
+
throw new Error(`Connection string EntityPath restricts access to ${credentials.entityPath}`);
|
|
12905
|
+
}
|
|
12906
|
+
}
|
|
12907
|
+
var BROKER_PROPERTY_NAMES = /* @__PURE__ */ new Set([
|
|
12908
|
+
"CorrelationId",
|
|
12909
|
+
"SessionId",
|
|
12910
|
+
"Label",
|
|
12911
|
+
"MessageId",
|
|
12912
|
+
"ReplyTo",
|
|
12913
|
+
"ReplyToSessionId",
|
|
12914
|
+
"To",
|
|
12915
|
+
"TimeToLive",
|
|
12916
|
+
"ScheduledEnqueueTimeUtc",
|
|
12917
|
+
"PartitionKey",
|
|
12918
|
+
"ViaPartitionKey",
|
|
12919
|
+
"ForcePersistence"
|
|
12920
|
+
]);
|
|
12921
|
+
function allowedBrokerProperties(value) {
|
|
12922
|
+
if (value === void 0) return void 0;
|
|
12923
|
+
if (!isRecord2(value)) throw new Error("brokerProperties must be an object");
|
|
12924
|
+
const entries = Object.entries(value);
|
|
12925
|
+
if (entries.length > BROKER_PROPERTY_NAMES.size) throw new Error("brokerProperties contains too many fields");
|
|
12926
|
+
const result = {};
|
|
12927
|
+
for (const [key, property] of entries) {
|
|
12928
|
+
if (!BROKER_PROPERTY_NAMES.has(key)) throw new Error(`brokerProperties.${key} is not allowed`);
|
|
12929
|
+
if (!["string", "number", "boolean"].includes(typeof property) || !Number.isFinite(typeof property === "number" ? property : 0)) {
|
|
12930
|
+
throw new Error(`brokerProperties.${key} must be a finite string, number, or boolean`);
|
|
12931
|
+
}
|
|
12932
|
+
if (typeof property === "string") requiredHeaderValue(property, `brokerProperties.${key}`);
|
|
12933
|
+
result[key] = property;
|
|
12934
|
+
}
|
|
12935
|
+
return result;
|
|
12936
|
+
}
|
|
12937
|
+
var RESERVED_HEADERS = /* @__PURE__ */ new Set([
|
|
12938
|
+
"authorization",
|
|
12939
|
+
"brokerproperties",
|
|
12940
|
+
"content-length",
|
|
12941
|
+
"content-type",
|
|
12942
|
+
"host"
|
|
12943
|
+
]);
|
|
12944
|
+
function applicationPropertyHeaders(value) {
|
|
12945
|
+
if (value === void 0) return {};
|
|
12946
|
+
if (!isRecord2(value)) throw new Error("applicationProperties must be an object");
|
|
12947
|
+
const entries = Object.entries(value);
|
|
12948
|
+
if (entries.length > 64) throw new Error("applicationProperties cannot contain more than 64 entries");
|
|
12949
|
+
const result = {};
|
|
12950
|
+
let size = 0;
|
|
12951
|
+
for (const [key, property] of entries) {
|
|
12952
|
+
if (!/^[A-Za-z][A-Za-z0-9-]{0,63}$/.test(key) || RESERVED_HEADERS.has(key.toLowerCase()) || key.toLowerCase().startsWith("x-ms-")) {
|
|
12953
|
+
throw new Error(`applicationProperties.${key} is not a safe header name`);
|
|
12954
|
+
}
|
|
12955
|
+
if (!["string", "number", "boolean"].includes(typeof property)) {
|
|
12956
|
+
throw new Error(`applicationProperties.${key} must be a string, number, or boolean`);
|
|
12957
|
+
}
|
|
12958
|
+
if (typeof property === "number" && !Number.isFinite(property)) {
|
|
12959
|
+
throw new Error(`applicationProperties.${key} must be finite`);
|
|
12960
|
+
}
|
|
12961
|
+
const headerValue2 = requiredHeaderValue(String(property), `applicationProperties.${key}`);
|
|
12962
|
+
size += Buffer.byteLength(key) + Buffer.byteLength(headerValue2);
|
|
12963
|
+
if (size > 32 * 1024) throw new Error("applicationProperties exceeds 32768 bytes");
|
|
12964
|
+
result[key] = headerValue2;
|
|
12965
|
+
}
|
|
12966
|
+
return result;
|
|
12967
|
+
}
|
|
12968
|
+
function responseApplicationProperties(headers) {
|
|
12969
|
+
const result = {};
|
|
12970
|
+
for (const [key, value] of headers.entries()) {
|
|
12971
|
+
if (!RESERVED_HEADERS.has(key.toLowerCase()) && !key.toLowerCase().startsWith("x-ms-") && key.toLowerCase() !== "date" && key.toLowerCase() !== "server" && key.toLowerCase() !== "transfer-encoding") result[key] = value;
|
|
12972
|
+
}
|
|
12973
|
+
return result;
|
|
12974
|
+
}
|
|
12975
|
+
function parseAtomFeed(xml) {
|
|
12976
|
+
const nextLink = xml.match(/<link\b(?=[^>]*\brel=["']next["'])(?=[^>]*\bhref=["']([^"']+)["'])[^>]*\/?>/i)?.[1];
|
|
12977
|
+
return {
|
|
12978
|
+
entries: [...xml.matchAll(/<entry\b[^>]*>([\s\S]*?)<\/entry>/gi)].map((match) => parseAtomEntry(match[0])),
|
|
12979
|
+
...nextLink ? { nextLink: decodeXml2(nextLink) } : {}
|
|
12980
|
+
};
|
|
12981
|
+
}
|
|
12982
|
+
function parseAtomEntry(xml) {
|
|
12983
|
+
const title = xmlValue(xml, "title");
|
|
12984
|
+
const id2 = xmlValue(xml, "id");
|
|
12985
|
+
const updated = xmlValue(xml, "updated");
|
|
12986
|
+
const properties = {};
|
|
12987
|
+
for (const match of xml.matchAll(/<(?:[A-Za-z0-9]+:)?([A-Za-z][A-Za-z0-9]*)\b[^>]*>([^<]*)<\/(?:[A-Za-z0-9]+:)?\1>/g)) {
|
|
12988
|
+
const key = match[1];
|
|
12989
|
+
if (["title", "id", "updated"].includes(key.toLowerCase())) continue;
|
|
12990
|
+
const raw = decodeXml2(match[2]);
|
|
12991
|
+
properties[key] = xmlScalar(raw);
|
|
12992
|
+
}
|
|
12993
|
+
return { title, id: id2, updated, properties };
|
|
12994
|
+
}
|
|
12995
|
+
function xmlValue(xml, tag) {
|
|
12996
|
+
const match = xml.match(new RegExp(`<(?:[A-Za-z0-9]+:)?${tag}\\b[^>]*>([^<]*)<\\/(?:[A-Za-z0-9]+:)?${tag}>`, "i"));
|
|
12997
|
+
return match ? decodeXml2(match[1]) : void 0;
|
|
12998
|
+
}
|
|
12999
|
+
function xmlScalar(value) {
|
|
13000
|
+
if (value === "true") return true;
|
|
13001
|
+
if (value === "false") return false;
|
|
13002
|
+
if (/^-?\d+$/.test(value)) {
|
|
13003
|
+
const parsed = Number(value);
|
|
13004
|
+
if (Number.isSafeInteger(parsed)) return parsed;
|
|
13005
|
+
}
|
|
13006
|
+
return value;
|
|
13007
|
+
}
|
|
13008
|
+
function decodeXml2(value) {
|
|
13009
|
+
return value.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
13010
|
+
}
|
|
13011
|
+
async function readBounded(response, limit) {
|
|
13012
|
+
const declared = Number(response.headers.get("content-length"));
|
|
13013
|
+
if (Number.isFinite(declared) && declared > limit) throw new Error(`Azure Service Bus response exceeds ${limit} bytes`);
|
|
13014
|
+
if (!response.body) return new Uint8Array();
|
|
13015
|
+
const reader = response.body.getReader();
|
|
13016
|
+
const chunks = [];
|
|
13017
|
+
let size = 0;
|
|
13018
|
+
while (true) {
|
|
13019
|
+
const { done, value } = await reader.read();
|
|
13020
|
+
if (done) break;
|
|
13021
|
+
size += value.byteLength;
|
|
13022
|
+
if (size > limit) {
|
|
13023
|
+
await reader.cancel();
|
|
13024
|
+
throw new Error(`Azure Service Bus response exceeds ${limit} bytes`);
|
|
13025
|
+
}
|
|
13026
|
+
chunks.push(value);
|
|
13027
|
+
}
|
|
13028
|
+
const body = new Uint8Array(size);
|
|
13029
|
+
let offset = 0;
|
|
13030
|
+
for (const chunk of chunks) {
|
|
13031
|
+
body.set(chunk, offset);
|
|
13032
|
+
offset += chunk.byteLength;
|
|
13033
|
+
}
|
|
13034
|
+
return body;
|
|
13035
|
+
}
|
|
13036
|
+
function strictBase64(value) {
|
|
13037
|
+
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
13038
|
+
throw new Error("content must be canonical base64 when encoding=base64");
|
|
13039
|
+
}
|
|
13040
|
+
return Buffer.from(value, "base64");
|
|
13041
|
+
}
|
|
13042
|
+
function requiredString5(value, field, allowEmpty = false) {
|
|
13043
|
+
if (typeof value !== "string" || !allowEmpty && value.trim() === "") {
|
|
13044
|
+
throw new Error(`${field} must be ${allowEmpty ? "a string" : "a non-empty string"}`);
|
|
13045
|
+
}
|
|
13046
|
+
return allowEmpty ? value : value.trim();
|
|
13047
|
+
}
|
|
13048
|
+
function requiredHeaderValue(value, field) {
|
|
13049
|
+
const parsed = requiredString5(value, field);
|
|
13050
|
+
if (/\r|\n/.test(parsed) || parsed.length > 4096) throw new Error(`${field} is not a safe header value`);
|
|
13051
|
+
return parsed;
|
|
13052
|
+
}
|
|
13053
|
+
function boundedInteger(value, field, minimum, maximum) {
|
|
13054
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
13055
|
+
throw new Error(`${field} must be an integer from ${minimum} to ${maximum}`);
|
|
13056
|
+
}
|
|
13057
|
+
return value;
|
|
13058
|
+
}
|
|
13059
|
+
function enumValue(value, field, choices) {
|
|
13060
|
+
if (typeof value !== "string" || !choices.includes(value)) {
|
|
13061
|
+
throw new Error(`${field} must be one of ${choices.join(", ")}`);
|
|
13062
|
+
}
|
|
13063
|
+
return value;
|
|
13064
|
+
}
|
|
13065
|
+
function decodeUtf82(value) {
|
|
13066
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
13067
|
+
}
|
|
13068
|
+
function retryAfterMs4(value) {
|
|
13069
|
+
if (!value) return 6e4;
|
|
13070
|
+
const seconds = Number(value);
|
|
13071
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
13072
|
+
const date = Date.parse(value);
|
|
13073
|
+
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
|
|
13074
|
+
}
|
|
13075
|
+
function redactProviderText(value) {
|
|
13076
|
+
return value.replace(/SharedAccessSignature\s+[^\s<]+/gi, "SharedAccessSignature [redacted]").replace(/SharedAccessKey=[^;\s<]+/gi, "SharedAccessKey=[redacted]");
|
|
13077
|
+
}
|
|
13078
|
+
function isRecord2(value) {
|
|
13079
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13080
|
+
}
|
|
13081
|
+
|
|
12208
13082
|
// src/connectors/adapters/basecamp.ts
|
|
12209
13083
|
var basecampConnector = declarativeRestConnector({
|
|
12210
13084
|
kind: "basecamp",
|
|
@@ -18735,7 +19609,7 @@ var checkoutConnector = declarativeRestConnector({
|
|
|
18735
19609
|
});
|
|
18736
19610
|
|
|
18737
19611
|
// src/connectors/adapters/docuseal.ts
|
|
18738
|
-
import { createHmac as
|
|
19612
|
+
import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
18739
19613
|
var DEFAULT_BASE = "https://api.docuseal.com";
|
|
18740
19614
|
function readDocuSealCredentials(creds) {
|
|
18741
19615
|
if (creds.kind === "api-key" && typeof creds.apiKey === "string" && creds.apiKey.length > 0) {
|
|
@@ -18860,11 +19734,11 @@ function docuseal(opts = {}) {
|
|
|
18860
19734
|
if (!creds?.webhookSecret) return { valid: false, reason: "missing_webhook_secret" };
|
|
18861
19735
|
const sig = firstHeader(headers, "x-docuseal-signature");
|
|
18862
19736
|
if (!sig) return { valid: false, reason: "missing_signature_header" };
|
|
18863
|
-
const expected =
|
|
19737
|
+
const expected = createHmac4("sha256", creds.webhookSecret).update(rawBody).digest("hex");
|
|
18864
19738
|
const a = Buffer.from(sig.toLowerCase(), "utf-8");
|
|
18865
19739
|
const b = Buffer.from(expected, "utf-8");
|
|
18866
19740
|
if (a.length !== b.length) return { valid: false, reason: "invalid_signature" };
|
|
18867
|
-
return
|
|
19741
|
+
return timingSafeEqual2(a, b) ? { valid: true } : { valid: false, reason: "invalid_signature" };
|
|
18868
19742
|
},
|
|
18869
19743
|
async handleInboundEvent({ rawBody }) {
|
|
18870
19744
|
let parsed;
|
|
@@ -22482,7 +23356,7 @@ var frontConnector = declarativeRestConnector({
|
|
|
22482
23356
|
});
|
|
22483
23357
|
|
|
22484
23358
|
// src/connectors/oauth.ts
|
|
22485
|
-
import { createHash as
|
|
23359
|
+
import { createHash as createHash4, randomBytes } from "crypto";
|
|
22486
23360
|
var PENDING_TTL_MS = 10 * 60 * 1e3;
|
|
22487
23361
|
var InMemoryOAuthFlowStore = class {
|
|
22488
23362
|
pendingFlows = /* @__PURE__ */ new Map();
|
|
@@ -22510,7 +23384,7 @@ function startOAuthFlow(input) {
|
|
|
22510
23384
|
const now = input.now ?? Date.now();
|
|
22511
23385
|
store.sweep?.(now);
|
|
22512
23386
|
const codeVerifier = base64Url(randomBytes(48));
|
|
22513
|
-
const codeChallenge = base64Url(
|
|
23387
|
+
const codeChallenge = base64Url(createHash4("sha256").update(codeVerifier).digest());
|
|
22514
23388
|
const state = base64Url(randomBytes(24));
|
|
22515
23389
|
store.put(state, {
|
|
22516
23390
|
codeVerifier,
|
|
@@ -24429,11 +25303,11 @@ var googleCloudStorageConnector = declarativeRestConnector({
|
|
|
24429
25303
|
});
|
|
24430
25304
|
|
|
24431
25305
|
// src/connectors/adapters/google-pubsub.ts
|
|
24432
|
-
import { createHash as
|
|
25306
|
+
import { createHash as createHash5, createSign } from "crypto";
|
|
24433
25307
|
var TOKEN_URL3 = "https://oauth2.googleapis.com/token";
|
|
24434
25308
|
var API_ROOT = "https://pubsub.googleapis.com/v1";
|
|
24435
25309
|
var PUBSUB_SCOPE = "https://www.googleapis.com/auth/pubsub";
|
|
24436
|
-
var
|
|
25310
|
+
var MAX_RESPONSE_BYTES3 = 8 * 1024 * 1024;
|
|
24437
25311
|
var MAX_REQUEST_BYTES = 1e7;
|
|
24438
25312
|
var MAX_TOKEN_CACHE_ENTRIES = 256;
|
|
24439
25313
|
var tokenCache = /* @__PURE__ */ new Map();
|
|
@@ -24454,14 +25328,14 @@ var googlePubSubConnector = {
|
|
|
24454
25328
|
defaultConsistencyModel: "advisory",
|
|
24455
25329
|
rateLimit: { requests: 600, windowMs: 6e4, scope: "data-source" },
|
|
24456
25330
|
capabilities: [
|
|
24457
|
-
|
|
25331
|
+
readCapability3("topics.list", "List topics in the service account project.", {
|
|
24458
25332
|
pageSize: { type: "integer", minimum: 1, maximum: 1e3 },
|
|
24459
25333
|
pageToken: { type: "string" }
|
|
24460
25334
|
}),
|
|
24461
|
-
|
|
25335
|
+
readCapability3("topics.get", "Get one topic and its server-side configuration.", {
|
|
24462
25336
|
topic: { type: "string", description: "Topic ID in the service account project." }
|
|
24463
25337
|
}, ["topic"]),
|
|
24464
|
-
|
|
25338
|
+
mutationCapability4("topics.create", "Create a topic in the service account project.", {
|
|
24465
25339
|
topic: { type: "string" },
|
|
24466
25340
|
labels: { type: "object", additionalProperties: { type: "string" } },
|
|
24467
25341
|
allowedPersistenceRegions: { type: "array", items: { type: "string" } },
|
|
@@ -24469,10 +25343,10 @@ var googlePubSubConnector = {
|
|
|
24469
25343
|
schema: { type: "string", description: "Full Pub/Sub schema resource name." },
|
|
24470
25344
|
schemaEncoding: { type: "string", enum: ["JSON", "BINARY"] }
|
|
24471
25345
|
}, ["topic"]),
|
|
24472
|
-
|
|
25346
|
+
mutationCapability4("topics.delete", "Delete a topic. Existing subscriptions remain but stop receiving messages.", {
|
|
24473
25347
|
topic: { type: "string" }
|
|
24474
25348
|
}, ["topic"]),
|
|
24475
|
-
|
|
25349
|
+
mutationCapability4("messages.publish", "Publish up to 1,000 messages to a topic.", {
|
|
24476
25350
|
topic: { type: "string" },
|
|
24477
25351
|
messages: {
|
|
24478
25352
|
type: "array",
|
|
@@ -24481,14 +25355,14 @@ var googlePubSubConnector = {
|
|
|
24481
25355
|
description: "Messages with either text (UTF-8) or data (base64), plus optional string attributes and orderingKey."
|
|
24482
25356
|
}
|
|
24483
25357
|
}, ["topic", "messages"]),
|
|
24484
|
-
|
|
25358
|
+
readCapability3("subscriptions.list", "List subscriptions in the service account project.", {
|
|
24485
25359
|
pageSize: { type: "integer", minimum: 1, maximum: 1e3 },
|
|
24486
25360
|
pageToken: { type: "string" }
|
|
24487
25361
|
}),
|
|
24488
|
-
|
|
25362
|
+
readCapability3("subscriptions.get", "Get one subscription and its delivery configuration.", {
|
|
24489
25363
|
subscription: { type: "string" }
|
|
24490
25364
|
}, ["subscription"]),
|
|
24491
|
-
|
|
25365
|
+
mutationCapability4("subscriptions.create", "Create a pull subscription for a topic.", {
|
|
24492
25366
|
subscription: { type: "string" },
|
|
24493
25367
|
topic: { type: "string" },
|
|
24494
25368
|
ackDeadlineSeconds: { type: "integer", minimum: 10, maximum: 600 },
|
|
@@ -24504,18 +25378,18 @@ var googlePubSubConnector = {
|
|
|
24504
25378
|
enableExactlyOnceDelivery: { type: "boolean" },
|
|
24505
25379
|
labels: { type: "object", additionalProperties: { type: "string" } }
|
|
24506
25380
|
}, ["subscription", "topic"]),
|
|
24507
|
-
|
|
25381
|
+
mutationCapability4("subscriptions.delete", "Delete a subscription and discard its retained messages.", {
|
|
24508
25382
|
subscription: { type: "string" }
|
|
24509
25383
|
}, ["subscription"]),
|
|
24510
|
-
|
|
25384
|
+
mutationCapability4("messages.pull", "Pull messages and make them temporarily unavailable to other subscribers.", {
|
|
24511
25385
|
subscription: { type: "string" },
|
|
24512
25386
|
maxMessages: { type: "integer", minimum: 1, maximum: 1e3 }
|
|
24513
25387
|
}, ["subscription", "maxMessages"]),
|
|
24514
|
-
|
|
25388
|
+
mutationCapability4("messages.acknowledge", "Acknowledge delivered messages by ack ID.", {
|
|
24515
25389
|
subscription: { type: "string" },
|
|
24516
25390
|
ackIds: { type: "array", minItems: 1, maxItems: 1e3, items: { type: "string" } }
|
|
24517
25391
|
}, ["subscription", "ackIds"]),
|
|
24518
|
-
|
|
25392
|
+
mutationCapability4("messages.modifyAckDeadline", "Change the acknowledgement deadline for delivered messages.", {
|
|
24519
25393
|
subscription: { type: "string" },
|
|
24520
25394
|
ackIds: { type: "array", minItems: 1, maxItems: 1e3, items: { type: "string" } },
|
|
24521
25395
|
ackDeadlineSeconds: { type: "integer", minimum: 0, maximum: 600 }
|
|
@@ -24553,11 +25427,11 @@ var googlePubSubConnector = {
|
|
|
24553
25427
|
if (labels) body.labels = labels;
|
|
24554
25428
|
const regions2 = optionalStringArray(inv.args.allowedPersistenceRegions, "allowedPersistenceRegions");
|
|
24555
25429
|
if (regions2) body.messageStoragePolicy = { allowedPersistenceRegions: regions2 };
|
|
24556
|
-
if (inv.args.kmsKeyName !== void 0) body.kmsKeyName =
|
|
25430
|
+
if (inv.args.kmsKeyName !== void 0) body.kmsKeyName = requiredString6(inv.args.kmsKeyName, "kmsKeyName");
|
|
24557
25431
|
if (inv.args.schema !== void 0) {
|
|
24558
25432
|
body.schemaSettings = {
|
|
24559
|
-
schema:
|
|
24560
|
-
...inv.args.schemaEncoding === void 0 ? {} : { encoding:
|
|
25433
|
+
schema: requiredString6(inv.args.schema, "schema"),
|
|
25434
|
+
...inv.args.schemaEncoding === void 0 ? {} : { encoding: enumValue2(inv.args.schemaEncoding, "schemaEncoding", ["JSON", "BINARY"]) }
|
|
24561
25435
|
};
|
|
24562
25436
|
}
|
|
24563
25437
|
data4 = await pubSubRequest(credentials, inv, "PUT", topicPath(credentials, inv.args.topic), void 0, body);
|
|
@@ -24596,7 +25470,7 @@ var googlePubSubConnector = {
|
|
|
24596
25470
|
"POST",
|
|
24597
25471
|
`${subscriptionPath(credentials, inv.args.subscription)}:pull`,
|
|
24598
25472
|
void 0,
|
|
24599
|
-
{ maxMessages:
|
|
25473
|
+
{ maxMessages: boundedInteger2(inv.args.maxMessages, "maxMessages", 1, 1e3) }
|
|
24600
25474
|
);
|
|
24601
25475
|
break;
|
|
24602
25476
|
case "messages.acknowledge":
|
|
@@ -24618,7 +25492,7 @@ var googlePubSubConnector = {
|
|
|
24618
25492
|
void 0,
|
|
24619
25493
|
{
|
|
24620
25494
|
ackIds: requiredStringArray(inv.args.ackIds, "ackIds", 1e3),
|
|
24621
|
-
ackDeadlineSeconds:
|
|
25495
|
+
ackDeadlineSeconds: boundedInteger2(inv.args.ackDeadlineSeconds, "ackDeadlineSeconds", 0, 600)
|
|
24622
25496
|
}
|
|
24623
25497
|
);
|
|
24624
25498
|
break;
|
|
@@ -24647,7 +25521,7 @@ var googlePubSubConnector = {
|
|
|
24647
25521
|
}
|
|
24648
25522
|
}
|
|
24649
25523
|
};
|
|
24650
|
-
function
|
|
25524
|
+
function readCapability3(name, description, properties, required = []) {
|
|
24651
25525
|
return {
|
|
24652
25526
|
name,
|
|
24653
25527
|
class: "read",
|
|
@@ -24655,7 +25529,7 @@ function readCapability2(name, description, properties, required = []) {
|
|
|
24655
25529
|
parameters: { type: "object", properties, ...required.length ? { required } : {} }
|
|
24656
25530
|
};
|
|
24657
25531
|
}
|
|
24658
|
-
function
|
|
25532
|
+
function mutationCapability4(name, description, properties, required) {
|
|
24659
25533
|
return {
|
|
24660
25534
|
name,
|
|
24661
25535
|
class: "mutation",
|
|
@@ -24675,7 +25549,7 @@ function parseServiceAccountCredentials(credentials, dataSourceId) {
|
|
|
24675
25549
|
} catch {
|
|
24676
25550
|
throw new CredentialsExpired("Google Pub/Sub service-account key must be valid JSON", dataSourceId);
|
|
24677
25551
|
}
|
|
24678
|
-
if (!
|
|
25552
|
+
if (!isRecord3(parsed) || parsed.type !== "service_account") {
|
|
24679
25553
|
throw new CredentialsExpired("Google Pub/Sub requires a Google service_account key", dataSourceId);
|
|
24680
25554
|
}
|
|
24681
25555
|
const projectId = requiredCredentialString(parsed.project_id, "project_id", dataSourceId);
|
|
@@ -24693,7 +25567,7 @@ function parseServiceAccountCredentials(credentials, dataSourceId) {
|
|
|
24693
25567
|
return { projectId, clientEmail, privateKey };
|
|
24694
25568
|
}
|
|
24695
25569
|
async function accessToken(credentials, dataSourceId) {
|
|
24696
|
-
const cacheKey =
|
|
25570
|
+
const cacheKey = createHash5("sha256").update(credentials.clientEmail).update("\0").update(credentials.privateKey).digest("hex");
|
|
24697
25571
|
const cached = tokenCache.get(cacheKey);
|
|
24698
25572
|
if (cached && cached.expiresAt > Date.now() + 6e4) {
|
|
24699
25573
|
tokenCache.delete(cacheKey);
|
|
@@ -24735,8 +25609,8 @@ async function exchangeAccessToken(credentials, dataSourceId, cacheKey) {
|
|
|
24735
25609
|
body: form2
|
|
24736
25610
|
});
|
|
24737
25611
|
const body = await readJson(response, 64 * 1024);
|
|
24738
|
-
if (!response.ok || !
|
|
24739
|
-
const reason =
|
|
25612
|
+
if (!response.ok || !isRecord3(body) || typeof body.access_token !== "string" || body.access_token.trim() === "") {
|
|
25613
|
+
const reason = isRecord3(body) && typeof body.error === "string" ? body.error : void 0;
|
|
24740
25614
|
throw new CredentialsExpired("Google rejected the Pub/Sub service-account grant", dataSourceId, {
|
|
24741
25615
|
status: response.status,
|
|
24742
25616
|
reason,
|
|
@@ -24772,9 +25646,9 @@ async function pubSubRequest(credentials, inv, method, path, query2, body) {
|
|
|
24772
25646
|
},
|
|
24773
25647
|
body: serialized
|
|
24774
25648
|
});
|
|
24775
|
-
const responseBody = await readJson(response,
|
|
25649
|
+
const responseBody = await readJson(response, MAX_RESPONSE_BYTES3);
|
|
24776
25650
|
if (response.ok) return responseBody;
|
|
24777
|
-
const providerError =
|
|
25651
|
+
const providerError = isRecord3(responseBody) && isRecord3(responseBody.error) ? responseBody.error : void 0;
|
|
24778
25652
|
const reason = providerError && typeof providerError.status === "string" ? providerError.status : void 0;
|
|
24779
25653
|
if (response.status === 401) {
|
|
24780
25654
|
throw new CredentialsExpired("Google Pub/Sub credentials were rejected", inv.source.id, {
|
|
@@ -24795,7 +25669,7 @@ async function pubSubRequest(credentials, inv, method, path, query2, body) {
|
|
|
24795
25669
|
status: response.status,
|
|
24796
25670
|
reason,
|
|
24797
25671
|
body: responseBody,
|
|
24798
|
-
retryAfterMs:
|
|
25672
|
+
retryAfterMs: retryAfterMs5(response.headers.get("retry-after"))
|
|
24799
25673
|
});
|
|
24800
25674
|
}
|
|
24801
25675
|
const message = providerError && typeof providerError.message === "string" ? providerError.message : `HTTP ${response.status}`;
|
|
@@ -24811,7 +25685,7 @@ function subscriptionPath(credentials, value) {
|
|
|
24811
25685
|
return `${projectPath(credentials, "subscriptions")}/${encodeURIComponent(resourceId(value, "subscription"))}`;
|
|
24812
25686
|
}
|
|
24813
25687
|
function resourceId(value, field) {
|
|
24814
|
-
const id2 =
|
|
25688
|
+
const id2 = requiredString6(value, field);
|
|
24815
25689
|
if (!/^[A-Za-z][A-Za-z0-9._~+%-]{2,254}$/.test(id2) || id2.toLowerCase().startsWith("goog")) {
|
|
24816
25690
|
throw new Error(`${field} must be a valid Pub/Sub resource ID`);
|
|
24817
25691
|
}
|
|
@@ -24819,8 +25693,8 @@ function resourceId(value, field) {
|
|
|
24819
25693
|
}
|
|
24820
25694
|
function pagination(args) {
|
|
24821
25695
|
const query2 = new URLSearchParams();
|
|
24822
|
-
if (args.pageSize !== void 0) query2.set("pageSize", String(
|
|
24823
|
-
if (args.pageToken !== void 0) query2.set("pageToken",
|
|
25696
|
+
if (args.pageSize !== void 0) query2.set("pageSize", String(boundedInteger2(args.pageSize, "pageSize", 1, 1e3)));
|
|
25697
|
+
if (args.pageToken !== void 0) query2.set("pageToken", requiredString6(args.pageToken, "pageToken"));
|
|
24824
25698
|
return query2;
|
|
24825
25699
|
}
|
|
24826
25700
|
function subscriptionBody(credentials, args) {
|
|
@@ -24829,11 +25703,11 @@ function subscriptionBody(credentials, args) {
|
|
|
24829
25703
|
setOptionalBoolean(body, "retainAckedMessages", args.retainAckedMessages);
|
|
24830
25704
|
setOptionalDuration(body, "messageRetentionDuration", args.messageRetentionDuration);
|
|
24831
25705
|
if (args.expirationTtl !== void 0) body.expirationPolicy = { ttl: duration(args.expirationTtl, "expirationTtl") };
|
|
24832
|
-
if (args.filter !== void 0) body.filter =
|
|
25706
|
+
if (args.filter !== void 0) body.filter = requiredString6(args.filter, "filter");
|
|
24833
25707
|
if (args.deadLetterTopic !== void 0) {
|
|
24834
25708
|
body.deadLetterPolicy = {
|
|
24835
25709
|
deadLetterTopic: topicPath(credentials, args.deadLetterTopic),
|
|
24836
|
-
maxDeliveryAttempts:
|
|
25710
|
+
maxDeliveryAttempts: boundedInteger2(args.maxDeliveryAttempts, "maxDeliveryAttempts", 5, 100)
|
|
24837
25711
|
};
|
|
24838
25712
|
} else if (args.maxDeliveryAttempts !== void 0) {
|
|
24839
25713
|
throw new Error("maxDeliveryAttempts requires deadLetterTopic");
|
|
@@ -24855,15 +25729,15 @@ function publishMessages(value) {
|
|
|
24855
25729
|
throw new Error("messages must contain 1 to 1000 entries");
|
|
24856
25730
|
}
|
|
24857
25731
|
return value.map((entry, index) => {
|
|
24858
|
-
if (!
|
|
25732
|
+
if (!isRecord3(entry)) throw new Error(`messages[${index}] must be an object`);
|
|
24859
25733
|
const hasText = typeof entry.text === "string";
|
|
24860
25734
|
const hasData = typeof entry.data === "string";
|
|
24861
25735
|
if (hasText === hasData) throw new Error(`messages[${index}] requires exactly one of text or data`);
|
|
24862
|
-
const data4 = hasText ? Buffer.from(entry.text, "utf8").toString("base64") :
|
|
25736
|
+
const data4 = hasText ? Buffer.from(entry.text, "utf8").toString("base64") : strictBase642(entry.data, `messages[${index}].data`);
|
|
24863
25737
|
const message = { data: data4 };
|
|
24864
25738
|
const attributes = optionalStringMap(entry.attributes, `messages[${index}].attributes`);
|
|
24865
25739
|
if (attributes) message.attributes = attributes;
|
|
24866
|
-
if (entry.orderingKey !== void 0) message.orderingKey =
|
|
25740
|
+
if (entry.orderingKey !== void 0) message.orderingKey = requiredString6(entry.orderingKey, `messages[${index}].orderingKey`);
|
|
24867
25741
|
return message;
|
|
24868
25742
|
});
|
|
24869
25743
|
}
|
|
@@ -24904,11 +25778,11 @@ function requiredCredentialString(value, field, dataSourceId) {
|
|
|
24904
25778
|
}
|
|
24905
25779
|
return value.trim();
|
|
24906
25780
|
}
|
|
24907
|
-
function
|
|
25781
|
+
function requiredString6(value, field) {
|
|
24908
25782
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${field} must be a non-empty string`);
|
|
24909
25783
|
return value.trim();
|
|
24910
25784
|
}
|
|
24911
|
-
function
|
|
25785
|
+
function boundedInteger2(value, field, minimum, maximum) {
|
|
24912
25786
|
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
24913
25787
|
throw new Error(`${field} must be an integer from ${minimum} to ${maximum}`);
|
|
24914
25788
|
}
|
|
@@ -24918,7 +25792,7 @@ function requiredStringArray(value, field, maximum) {
|
|
|
24918
25792
|
if (!Array.isArray(value) || value.length < 1 || value.length > maximum) {
|
|
24919
25793
|
throw new Error(`${field} must contain 1 to ${maximum} strings`);
|
|
24920
25794
|
}
|
|
24921
|
-
return value.map((entry, index) =>
|
|
25795
|
+
return value.map((entry, index) => requiredString6(entry, `${field}[${index}]`));
|
|
24922
25796
|
}
|
|
24923
25797
|
function optionalStringArray(value, field) {
|
|
24924
25798
|
if (value === void 0) return void 0;
|
|
@@ -24926,16 +25800,16 @@ function optionalStringArray(value, field) {
|
|
|
24926
25800
|
}
|
|
24927
25801
|
function optionalStringMap(value, field) {
|
|
24928
25802
|
if (value === void 0) return void 0;
|
|
24929
|
-
if (!
|
|
25803
|
+
if (!isRecord3(value)) throw new Error(`${field} must be an object of strings`);
|
|
24930
25804
|
const entries = Object.entries(value);
|
|
24931
25805
|
if (entries.length > 64) throw new Error(`${field} cannot contain more than 64 entries`);
|
|
24932
25806
|
return Object.fromEntries(entries.map(([key, entry]) => [
|
|
24933
|
-
|
|
24934
|
-
|
|
25807
|
+
requiredString6(key, `${field} key`),
|
|
25808
|
+
requiredString6(entry, `${field}.${key}`)
|
|
24935
25809
|
]));
|
|
24936
25810
|
}
|
|
24937
25811
|
function setOptionalInteger(body, key, value, minimum, maximum) {
|
|
24938
|
-
if (value !== void 0) body[key] =
|
|
25812
|
+
if (value !== void 0) body[key] = boundedInteger2(value, key, minimum, maximum);
|
|
24939
25813
|
}
|
|
24940
25814
|
function setOptionalBoolean(body, key, value) {
|
|
24941
25815
|
if (value === void 0) return;
|
|
@@ -24946,17 +25820,17 @@ function setOptionalDuration(body, key, value) {
|
|
|
24946
25820
|
if (value !== void 0) body[key] = duration(value, key);
|
|
24947
25821
|
}
|
|
24948
25822
|
function duration(value, field) {
|
|
24949
|
-
const parsed =
|
|
25823
|
+
const parsed = requiredString6(value, field);
|
|
24950
25824
|
if (!/^\d+(?:\.\d{1,9})?s$/.test(parsed)) throw new Error(`${field} must be a protobuf duration ending in s`);
|
|
24951
25825
|
return parsed;
|
|
24952
25826
|
}
|
|
24953
|
-
function
|
|
25827
|
+
function enumValue2(value, field, choices) {
|
|
24954
25828
|
if (typeof value !== "string" || !choices.includes(value)) {
|
|
24955
25829
|
throw new Error(`${field} must be one of ${choices.join(", ")}`);
|
|
24956
25830
|
}
|
|
24957
25831
|
return value;
|
|
24958
25832
|
}
|
|
24959
|
-
function
|
|
25833
|
+
function strictBase642(value, field) {
|
|
24960
25834
|
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
24961
25835
|
throw new Error(`${field} must be canonical base64`);
|
|
24962
25836
|
}
|
|
@@ -24965,14 +25839,14 @@ function strictBase64(value, field) {
|
|
|
24965
25839
|
function base64UrlJson(value) {
|
|
24966
25840
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
24967
25841
|
}
|
|
24968
|
-
function
|
|
25842
|
+
function retryAfterMs5(value) {
|
|
24969
25843
|
if (!value) return 6e4;
|
|
24970
25844
|
const seconds = Number(value);
|
|
24971
25845
|
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
24972
25846
|
const date = Date.parse(value);
|
|
24973
25847
|
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
|
|
24974
25848
|
}
|
|
24975
|
-
function
|
|
25849
|
+
function isRecord3(value) {
|
|
24976
25850
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24977
25851
|
}
|
|
24978
25852
|
|
|
@@ -26748,7 +27622,7 @@ async function ensureFreshAccessToken5(creds, clientId, clientSecret) {
|
|
|
26748
27622
|
}
|
|
26749
27623
|
|
|
26750
27624
|
// src/connectors/adapters/google-sheets.ts
|
|
26751
|
-
import { createHash as
|
|
27625
|
+
import { createHash as createHash6 } from "crypto";
|
|
26752
27626
|
var SCOPES5 = ["https://www.googleapis.com/auth/spreadsheets"];
|
|
26753
27627
|
var AUTH_URL6 = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
26754
27628
|
var TOKEN_URL7 = "https://oauth2.googleapis.com/token";
|
|
@@ -27021,7 +27895,7 @@ async function fetchAllRows(accessToken4, meta) {
|
|
|
27021
27895
|
function rowFingerprint(values) {
|
|
27022
27896
|
const keys = Object.keys(values).sort();
|
|
27023
27897
|
const blob = keys.map((k) => `${k}=${values[k]}`).join("");
|
|
27024
|
-
return
|
|
27898
|
+
return createHash6("sha256").update(blob).digest("hex").slice(0, 16);
|
|
27025
27899
|
}
|
|
27026
27900
|
function matchesPredicate(row, predicate) {
|
|
27027
27901
|
for (const [k, v] of Object.entries(predicate)) {
|
|
@@ -27875,7 +28749,7 @@ var granolaConnector = declarativeRestConnector({
|
|
|
27875
28749
|
});
|
|
27876
28750
|
|
|
27877
28751
|
// src/connectors/adapters/hellosign.ts
|
|
27878
|
-
import { createHmac as
|
|
28752
|
+
import { createHmac as createHmac5, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
27879
28753
|
var SCOPES6 = [
|
|
27880
28754
|
"basic_account_info",
|
|
27881
28755
|
"request_signature",
|
|
@@ -28098,11 +28972,11 @@ function hellosign(opts) {
|
|
|
28098
28972
|
if (!event || typeof event.event_time !== "string" || typeof event.event_type !== "string" || typeof event.event_hash !== "string") {
|
|
28099
28973
|
return { valid: false, reason: "missing_event_fields" };
|
|
28100
28974
|
}
|
|
28101
|
-
const expected =
|
|
28975
|
+
const expected = createHmac5("sha256", source.credentials.accessToken).update(`${event.event_time}${event.event_type}`).digest("hex");
|
|
28102
28976
|
const a = Buffer.from(event.event_hash.toLowerCase(), "utf-8");
|
|
28103
28977
|
const b = Buffer.from(expected.toLowerCase(), "utf-8");
|
|
28104
28978
|
if (a.length !== b.length) return { valid: false, reason: "invalid_signature" };
|
|
28105
|
-
return
|
|
28979
|
+
return timingSafeEqual3(a, b) ? { valid: true } : { valid: false, reason: "invalid_signature" };
|
|
28106
28980
|
},
|
|
28107
28981
|
async handleInboundEvent({ rawBody }) {
|
|
28108
28982
|
const parsed = parseInboundBody(rawBody);
|
|
@@ -40041,7 +40915,7 @@ function outlookMail(opts) {
|
|
|
40041
40915
|
async executeMutation(inv) {
|
|
40042
40916
|
const accessToken4 = await ensureFreshAccessToken13(inv.source.credentials, clientId, clientSecret, inv.onCredentialsRotated);
|
|
40043
40917
|
if (inv.capabilityName === "send_reply") return sendReply2(inv, accessToken4, timeoutMs);
|
|
40044
|
-
if (inv.capabilityName === "send_message") return
|
|
40918
|
+
if (inv.capabilityName === "send_message") return sendMessage2(inv, accessToken4, timeoutMs);
|
|
40045
40919
|
if (inv.capabilityName === "create_draft") return createDraft(inv, accessToken4, timeoutMs);
|
|
40046
40920
|
if (inv.capabilityName === "subscribe_folder") return subscribeFolder(inv, accessToken4, timeoutMs);
|
|
40047
40921
|
if (inv.capabilityName === "forward_message") return forwardMessage(inv, accessToken4, timeoutMs);
|
|
@@ -40299,7 +41173,7 @@ function buildMessagePayload(args, idempotencyKey, cap) {
|
|
|
40299
41173
|
}
|
|
40300
41174
|
return payload;
|
|
40301
41175
|
}
|
|
40302
|
-
async function
|
|
41176
|
+
async function sendMessage2(inv, accessToken4, timeoutMs) {
|
|
40303
41177
|
const args = inv.args ?? {};
|
|
40304
41178
|
const message = buildMessagePayload(args, inv.idempotencyKey, "send_message");
|
|
40305
41179
|
const res = await fetch(`${API7}/me/sendMail`, {
|
|
@@ -42581,7 +43455,7 @@ var rssConnector = {
|
|
|
42581
43455
|
if (!res.ok) {
|
|
42582
43456
|
throw new Error(`rss fetch ${res.status} ${res.statusText} for ${url.toString()}`);
|
|
42583
43457
|
}
|
|
42584
|
-
const body = await
|
|
43458
|
+
const body = await readBoundedText2(res, MAX_BODY_BYTES);
|
|
42585
43459
|
const parsed = parseFeed(body, url.toString());
|
|
42586
43460
|
const filtered = filterAndLimit(parsed.entries, since, limit);
|
|
42587
43461
|
const data4 = {
|
|
@@ -42661,7 +43535,7 @@ function readSinceMs(value) {
|
|
|
42661
43535
|
}
|
|
42662
43536
|
return ms;
|
|
42663
43537
|
}
|
|
42664
|
-
async function
|
|
43538
|
+
async function readBoundedText2(res, maxBytes) {
|
|
42665
43539
|
const reader = res.body?.getReader();
|
|
42666
43540
|
if (!reader) return await res.text();
|
|
42667
43541
|
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
@@ -42715,7 +43589,7 @@ function parseRss(text) {
|
|
|
42715
43589
|
return { feedTitle: null, feedUpdated: null, entries: [], format: "rss" };
|
|
42716
43590
|
}
|
|
42717
43591
|
const channelInner = stripAllElements(channelOuter, "item");
|
|
42718
|
-
const feedTitle =
|
|
43592
|
+
const feedTitle = decodeXml3(firstTagText(channelInner, "title"));
|
|
42719
43593
|
const items = collectElements(channelOuter, "item");
|
|
42720
43594
|
const entries = items.map((item) => {
|
|
42721
43595
|
const guid = firstTagText(item, "guid");
|
|
@@ -42725,17 +43599,17 @@ function parseRss(text) {
|
|
|
42725
43599
|
const contentEncoded = firstTagText(item, "content:encoded");
|
|
42726
43600
|
const pubDate = firstTagText(item, "pubDate");
|
|
42727
43601
|
const author = firstTagText(item, "author") ?? firstTagText(item, "dc:creator");
|
|
42728
|
-
const categories = collectElements(item, "category").map((cat) =>
|
|
42729
|
-
const id2 =
|
|
43602
|
+
const categories = collectElements(item, "category").map((cat) => decodeXml3(stripTags(cat)) ?? "").filter(Boolean);
|
|
43603
|
+
const id2 = decodeXml3(guid) ?? decodeXml3(link) ?? hash(item);
|
|
42730
43604
|
return {
|
|
42731
43605
|
id: id2,
|
|
42732
|
-
title:
|
|
42733
|
-
link:
|
|
42734
|
-
summary:
|
|
42735
|
-
content:
|
|
42736
|
-
published: normalizeDate(
|
|
43606
|
+
title: decodeXml3(title),
|
|
43607
|
+
link: decodeXml3(link),
|
|
43608
|
+
summary: decodeXml3(description),
|
|
43609
|
+
content: decodeXml3(contentEncoded),
|
|
43610
|
+
published: normalizeDate(decodeXml3(pubDate)),
|
|
42737
43611
|
updated: null,
|
|
42738
|
-
author:
|
|
43612
|
+
author: decodeXml3(author),
|
|
42739
43613
|
categories
|
|
42740
43614
|
};
|
|
42741
43615
|
});
|
|
@@ -42744,17 +43618,17 @@ function parseRss(text) {
|
|
|
42744
43618
|
function parseAtom(text, feedUrl) {
|
|
42745
43619
|
const feedOuter = extractFirstElement(text, "feed") ?? text;
|
|
42746
43620
|
const feedInner = stripAllElements(feedOuter, "entry");
|
|
42747
|
-
const feedTitle =
|
|
42748
|
-
const feedUpdated = normalizeDate(
|
|
43621
|
+
const feedTitle = decodeXml3(firstTagText(feedInner, "title"));
|
|
43622
|
+
const feedUpdated = normalizeDate(decodeXml3(firstTagText(feedInner, "updated")));
|
|
42749
43623
|
const items = collectElements(feedOuter, "entry");
|
|
42750
43624
|
const entries = items.map((item) => {
|
|
42751
|
-
const id2 =
|
|
42752
|
-
const title =
|
|
42753
|
-
const summary =
|
|
43625
|
+
const id2 = decodeXml3(firstTagText(item, "id"));
|
|
43626
|
+
const title = decodeXml3(firstTagText(item, "title"));
|
|
43627
|
+
const summary = decodeXml3(firstTagText(item, "summary"));
|
|
42754
43628
|
const contentNode = firstTagText(item, "content");
|
|
42755
|
-
const published = normalizeDate(
|
|
42756
|
-
const updated = normalizeDate(
|
|
42757
|
-
const author =
|
|
43629
|
+
const published = normalizeDate(decodeXml3(firstTagText(item, "published")));
|
|
43630
|
+
const updated = normalizeDate(decodeXml3(firstTagText(item, "updated")));
|
|
43631
|
+
const author = decodeXml3(firstTagText(extractFirstElement(item, "author") ?? "", "name")) ?? decodeXml3(firstTagText(item, "author"));
|
|
42758
43632
|
const link = pickAtomLink(item);
|
|
42759
43633
|
const categories = collectAtomCategories(item);
|
|
42760
43634
|
return {
|
|
@@ -42762,7 +43636,7 @@ function parseAtom(text, feedUrl) {
|
|
|
42762
43636
|
title,
|
|
42763
43637
|
link,
|
|
42764
43638
|
summary,
|
|
42765
|
-
content:
|
|
43639
|
+
content: decodeXml3(contentNode),
|
|
42766
43640
|
published,
|
|
42767
43641
|
updated,
|
|
42768
43642
|
author,
|
|
@@ -42848,9 +43722,9 @@ function collectAtomCategories(entryOuter) {
|
|
|
42848
43722
|
let m;
|
|
42849
43723
|
while ((m = re.exec(entryOuter)) !== null) {
|
|
42850
43724
|
const term = readAttr(m[1] ?? "", "term");
|
|
42851
|
-
if (term) out.push(
|
|
43725
|
+
if (term) out.push(decodeXml3(term) ?? "");
|
|
42852
43726
|
else if (m[2]) {
|
|
42853
|
-
const inner =
|
|
43727
|
+
const inner = decodeXml3(stripTags(m[2]));
|
|
42854
43728
|
if (inner) out.push(inner);
|
|
42855
43729
|
}
|
|
42856
43730
|
}
|
|
@@ -42878,7 +43752,7 @@ function unwrapCdata(value) {
|
|
|
42878
43752
|
out += value.slice(lastIdx);
|
|
42879
43753
|
return out;
|
|
42880
43754
|
}
|
|
42881
|
-
function
|
|
43755
|
+
function decodeXml3(value) {
|
|
42882
43756
|
if (value === null) return null;
|
|
42883
43757
|
const trimmed = value.trim();
|
|
42884
43758
|
if (trimmed.length === 0) return null;
|
|
@@ -52665,17 +53539,17 @@ var zohoBookingsConnector = {
|
|
|
52665
53539
|
category: "calendar",
|
|
52666
53540
|
defaultConsistencyModel: "authoritative",
|
|
52667
53541
|
capabilities: [
|
|
52668
|
-
|
|
52669
|
-
|
|
53542
|
+
readCapability4("workspaces.list", "List Zoho Bookings workspaces.", {}),
|
|
53543
|
+
readCapability4("services.list", "List services, optionally within one workspace.", {
|
|
52670
53544
|
workspace_id: { type: "string" }
|
|
52671
53545
|
}),
|
|
52672
|
-
|
|
53546
|
+
readCapability4("resources.list", "List bookable resources, optionally for one service.", {
|
|
52673
53547
|
service_id: { type: "string" }
|
|
52674
53548
|
}),
|
|
52675
|
-
|
|
53549
|
+
readCapability4("staff.list", "List staff, optionally for one service.", {
|
|
52676
53550
|
service_id: { type: "string" }
|
|
52677
53551
|
}),
|
|
52678
|
-
|
|
53552
|
+
readCapability4("appointments.list", "List appointments from a required start time.", {
|
|
52679
53553
|
from_time: {
|
|
52680
53554
|
type: "string",
|
|
52681
53555
|
description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format."
|
|
@@ -52685,17 +53559,17 @@ var zohoBookingsConnector = {
|
|
|
52685
53559
|
staff_id: { type: "string" },
|
|
52686
53560
|
status: { type: "string" }
|
|
52687
53561
|
}, ["from_time"]),
|
|
52688
|
-
|
|
53562
|
+
readCapability4("appointments.get", "Read one appointment by booking id.", {
|
|
52689
53563
|
booking_id: { type: "string" }
|
|
52690
53564
|
}, ["booking_id"]),
|
|
52691
|
-
|
|
53565
|
+
readCapability4("availability.fetch", "Fetch open time slots for a service and date.", {
|
|
52692
53566
|
service_id: { type: "string" },
|
|
52693
53567
|
selected_date: { type: "string", description: "Date in YYYY-MM-DD format." },
|
|
52694
53568
|
staff_id: { type: "string" },
|
|
52695
53569
|
group_id: { type: "string" },
|
|
52696
53570
|
resource_id: { type: "string" }
|
|
52697
53571
|
}, ["service_id", "selected_date"]),
|
|
52698
|
-
|
|
53572
|
+
mutationCapability5("appointments.book", "Book an appointment for a customer.", {
|
|
52699
53573
|
service_id: { type: "string" },
|
|
52700
53574
|
from_time: { type: "string", description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format." },
|
|
52701
53575
|
customer_details: {
|
|
@@ -52711,13 +53585,13 @@ var zohoBookingsConnector = {
|
|
|
52711
53585
|
additional_fields: { type: "object" },
|
|
52712
53586
|
payment_info: { type: "object" }
|
|
52713
53587
|
}, ["service_id", "from_time", "customer_details"]),
|
|
52714
|
-
|
|
53588
|
+
mutationCapability5("appointments.reschedule", "Move an appointment to a new time, staff member, or group.", {
|
|
52715
53589
|
booking_id: { type: "string" },
|
|
52716
53590
|
start_time: { type: "string", description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format." },
|
|
52717
53591
|
staff_id: { type: "string" },
|
|
52718
53592
|
group_id: { type: "string" }
|
|
52719
53593
|
}, ["booking_id"]),
|
|
52720
|
-
|
|
53594
|
+
mutationCapability5("appointments.cancel", "Cancel an appointment by booking id.", {
|
|
52721
53595
|
booking_id: { type: "string" }
|
|
52722
53596
|
}, ["booking_id"])
|
|
52723
53597
|
]
|
|
@@ -52834,7 +53708,7 @@ var zohoBookingsConnector = {
|
|
|
52834
53708
|
}
|
|
52835
53709
|
}
|
|
52836
53710
|
};
|
|
52837
|
-
function
|
|
53711
|
+
function readCapability4(name, description, properties, required = []) {
|
|
52838
53712
|
return {
|
|
52839
53713
|
name,
|
|
52840
53714
|
class: "read",
|
|
@@ -52843,7 +53717,7 @@ function readCapability3(name, description, properties, required = []) {
|
|
|
52843
53717
|
requiredScopes: ["zohobookings.data.READ"]
|
|
52844
53718
|
};
|
|
52845
53719
|
}
|
|
52846
|
-
function
|
|
53720
|
+
function mutationCapability5(name, description, properties, required) {
|
|
52847
53721
|
return {
|
|
52848
53722
|
name,
|
|
52849
53723
|
class: "mutation",
|
|
@@ -52898,7 +53772,7 @@ async function request2(source, path, options) {
|
|
|
52898
53772
|
throw new ProviderRateLimited("Zoho Bookings rate limit (429)", source.id, {
|
|
52899
53773
|
status: 429,
|
|
52900
53774
|
body: responseBody,
|
|
52901
|
-
retryAfterMs:
|
|
53775
|
+
retryAfterMs: retryAfterMs6(response.headers.get("retry-after"))
|
|
52902
53776
|
});
|
|
52903
53777
|
}
|
|
52904
53778
|
if (!response.ok) throw new Error(`zoho-bookings ${options.method} ${path} HTTP ${response.status}`);
|
|
@@ -52943,7 +53817,7 @@ function exactlyOne(args, keys, label) {
|
|
|
52943
53817
|
const present = keys.filter((key) => args[key] !== void 0 && args[key] !== null && args[key] !== "");
|
|
52944
53818
|
if (present.length !== 1) throw new Error(`zoho-bookings: exactly one ${label} is required`);
|
|
52945
53819
|
}
|
|
52946
|
-
function
|
|
53820
|
+
function retryAfterMs6(value) {
|
|
52947
53821
|
if (!value) return 6e4;
|
|
52948
53822
|
const seconds = Number(value);
|
|
52949
53823
|
return Number.isFinite(seconds) && seconds >= 0 ? Math.max(1e3, seconds * 1e3) : 6e4;
|
|
@@ -54082,11 +54956,11 @@ async function request3(source, path, options) {
|
|
|
54082
54956
|
});
|
|
54083
54957
|
}
|
|
54084
54958
|
if (response.status === 429) {
|
|
54085
|
-
const
|
|
54959
|
+
const retryAfterMs7 = parseRetryAfter(response.headers.get("retry-after"));
|
|
54086
54960
|
throw new ProviderRateLimited("Zoho Campaigns rate limit (429)", source.id, {
|
|
54087
54961
|
status: 429,
|
|
54088
54962
|
body: responseBody,
|
|
54089
|
-
retryAfterMs:
|
|
54963
|
+
retryAfterMs: retryAfterMs7
|
|
54090
54964
|
});
|
|
54091
54965
|
}
|
|
54092
54966
|
if (!response.ok) {
|
|
@@ -61746,6 +62620,8 @@ var CONNECTOR_ADAPTER_FACTORIES = [
|
|
|
61746
62620
|
defineFactoryAdapter(() => googleCloudStorageConnector, googleOAuthEnvMap),
|
|
61747
62621
|
defineFactoryAdapter(() => googlePubSubConnector, {}),
|
|
61748
62622
|
defineFactoryAdapter(() => azureBlobStorageConnector, {}),
|
|
62623
|
+
defineFactoryAdapter(() => azureEventGridConnector, {}),
|
|
62624
|
+
defineFactoryAdapter(() => azureServiceBusConnector, {}),
|
|
61749
62625
|
defineFactoryAdapter(() => backblazeConnector, {}),
|
|
61750
62626
|
defineFactoryAdapter(() => cloudinaryConnector, {}),
|
|
61751
62627
|
defineFactoryAdapter(() => codaConnector, {}),
|
|
@@ -62519,11 +63395,11 @@ function validateOutboundStartArgs(args) {
|
|
|
62519
63395
|
assertNonEmptyString(args.agentId, "agentId", 128);
|
|
62520
63396
|
assertE164(args.toNumber, "toNumber");
|
|
62521
63397
|
assertE164(args.fromNumber, "fromNumber");
|
|
62522
|
-
if (!
|
|
63398
|
+
if (!isRecord4(args.mission)) throw new Error("phony start_outbound_call requires mission");
|
|
62523
63399
|
const mission = args.mission;
|
|
62524
63400
|
assertNonEmptyString(mission.goal, "mission.goal", 2e3);
|
|
62525
63401
|
if (mission.goal.trim().length < 8) throw new Error("phony start_outbound_call mission.goal must be at least 8 characters");
|
|
62526
|
-
if (mission.successSchema !== void 0 && !
|
|
63402
|
+
if (mission.successSchema !== void 0 && !isRecord4(mission.successSchema)) {
|
|
62527
63403
|
throw new Error("phony start_outbound_call mission.successSchema must be an object when supplied");
|
|
62528
63404
|
}
|
|
62529
63405
|
if (mission.ivrHints !== void 0) {
|
|
@@ -62537,7 +63413,7 @@ function validateOutboundStartArgs(args) {
|
|
|
62537
63413
|
if (args.missionId !== void 0) assertNonEmptyString(args.missionId, "missionId", 128);
|
|
62538
63414
|
if (args.voiceCloneId !== void 0) assertNonEmptyString(args.voiceCloneId, "voiceCloneId", 128);
|
|
62539
63415
|
if (args.callerProfile !== void 0) {
|
|
62540
|
-
if (!
|
|
63416
|
+
if (!isRecord4(args.callerProfile)) throw new Error("phony start_outbound_call callerProfile must be an object");
|
|
62541
63417
|
if (args.callerProfile.userName !== void 0) assertNonEmptyString(args.callerProfile.userName, "callerProfile.userName", 120);
|
|
62542
63418
|
if (args.callerProfile.companyName !== void 0) {
|
|
62543
63419
|
assertNonEmptyString(args.callerProfile.companyName, "callerProfile.companyName", 120);
|
|
@@ -62564,7 +63440,7 @@ function assertOptionalInteger(value, field, min, max) {
|
|
|
62564
63440
|
throw new Error(`phony start_outbound_call ${field} must be an integer between ${min} and ${max}`);
|
|
62565
63441
|
}
|
|
62566
63442
|
}
|
|
62567
|
-
function
|
|
63443
|
+
function isRecord4(value) {
|
|
62568
63444
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
62569
63445
|
}
|
|
62570
63446
|
async function getJson(inv, token, url, label) {
|
|
@@ -62636,7 +63512,7 @@ var INGEST_FIELDS = [
|
|
|
62636
63512
|
];
|
|
62637
63513
|
|
|
62638
63514
|
// src/connectors/adapters/webhook.ts
|
|
62639
|
-
import { createHmac as
|
|
63515
|
+
import { createHmac as createHmac6 } from "crypto";
|
|
62640
63516
|
var webhookConnector = {
|
|
62641
63517
|
manifest: {
|
|
62642
63518
|
kind: "webhook",
|
|
@@ -62750,7 +63626,7 @@ function signHeaders(creds, body, idempotencyKey) {
|
|
|
62750
63626
|
"x-phony-idempotency-key": idempotencyKey
|
|
62751
63627
|
};
|
|
62752
63628
|
if (creds.kind === "hmac" && typeof creds.secret === "string" && creds.secret.length > 0) {
|
|
62753
|
-
const sig =
|
|
63629
|
+
const sig = createHmac6("sha256", creds.secret).update(`${ts}.${body}`).digest("hex");
|
|
62754
63630
|
headers["x-phony-signature"] = `sha256=${sig}`;
|
|
62755
63631
|
}
|
|
62756
63632
|
return headers;
|
|
@@ -141686,6 +142562,8 @@ export {
|
|
|
141686
142562
|
avalaraConnector,
|
|
141687
142563
|
azureAdConnector,
|
|
141688
142564
|
azureBlobStorageConnector,
|
|
142565
|
+
azureEventGridConnector,
|
|
142566
|
+
azureServiceBusConnector,
|
|
141689
142567
|
basecampConnector,
|
|
141690
142568
|
backblazeConnector,
|
|
141691
142569
|
biginByZohoConnector,
|
|
@@ -142254,4 +143132,4 @@ export {
|
|
|
142254
143132
|
demandbaseConnector,
|
|
142255
143133
|
adapters_exports
|
|
142256
143134
|
};
|
|
142257
|
-
//# sourceMappingURL=chunk-
|
|
143135
|
+
//# sourceMappingURL=chunk-XZL47RBS.js.map
|