@tangle-network/agent-integrations 0.53.47 → 0.53.48

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.
Files changed (54) hide show
  1. package/dist/catalog.d.ts +2 -2
  2. package/dist/catalog.js +9 -9
  3. package/dist/{chunk-U36WHHML.js → chunk-CBWD2IOL.js} +251 -10
  4. package/dist/chunk-CBWD2IOL.js.map +1 -0
  5. package/dist/{chunk-TP4MD4PD.js → chunk-EZR72HCQ.js} +2 -2
  6. package/dist/{chunk-C7SE5X44.js → chunk-GY4PFAWA.js} +380 -63
  7. package/dist/chunk-GY4PFAWA.js.map +1 -0
  8. package/dist/{chunk-AGXTCR34.js → chunk-HNEEIMQC.js} +2427 -205
  9. package/dist/{chunk-AGXTCR34.js.map → chunk-HNEEIMQC.js.map} +1 -1
  10. package/dist/{chunk-JR2RWYQO.js → chunk-I5EF5KIT.js} +2 -2
  11. package/dist/{chunk-DHF5EXLO.js → chunk-PXOM5AVK.js} +7 -2
  12. package/dist/{chunk-DHF5EXLO.js.map → chunk-PXOM5AVK.js.map} +1 -1
  13. package/dist/{chunk-EKSAOR2I.js → chunk-Q7TDHVRZ.js} +2 -2
  14. package/dist/{chunk-WE7SQ7PB.js → chunk-RRSNINEV.js} +15 -3
  15. package/dist/chunk-RRSNINEV.js.map +1 -0
  16. package/dist/{chunk-AG4ORH2A.js → chunk-TKEVCGAI.js} +6 -6
  17. package/dist/chunk-TKEVCGAI.js.map +1 -0
  18. package/dist/connect/index.d.ts +2 -2
  19. package/dist/connect/index.js +2 -2
  20. package/dist/connectors/adapters/index.d.ts +45 -3
  21. package/dist/connectors/adapters/index.js +16 -2
  22. package/dist/connectors/index.d.ts +37 -12
  23. package/dist/connectors/index.js +17 -3
  24. package/dist/{consumer-UnsjK9iM.d.ts → consumer-BcFIDgMD.d.ts} +1 -1
  25. package/dist/consumer.d.ts +3 -3
  26. package/dist/consumer.js +2 -2
  27. package/dist/{core-types-Cx53j2Xp.d.ts → core-types-CE1oMiuI.d.ts} +7 -1
  28. package/dist/coverage-catalog.d.ts +2 -2
  29. package/dist/coverage-catalog.js +1 -1
  30. package/dist/{importers-YLXwPCz_.d.ts → importers-CHOC-2Y8.d.ts} +1 -1
  31. package/dist/index.d.ts +13 -12
  32. package/dist/index.js +23 -9
  33. package/dist/mcp.d.ts +3 -3
  34. package/dist/mcp.js +9 -9
  35. package/dist/middleware/index.d.ts +2 -2
  36. package/dist/middleware/index.js +2 -2
  37. package/dist/registry.d.ts +2 -2
  38. package/dist/registry.js +9 -9
  39. package/dist/runtime.d.ts +2 -2
  40. package/dist/runtime.js +9 -9
  41. package/dist/specs.d.ts +11 -3
  42. package/dist/specs.js +5 -5
  43. package/dist/{tangle-id--7mgjNkq.d.ts → tangle-id-BL_JQwKA.d.ts} +1 -1
  44. package/dist/{types-qFsboS2G.d.ts → types-EXGqQYoU.d.ts} +25 -10
  45. package/docs/integration-execution-audit.md +17 -11
  46. package/docs/integration-execution-matrix.json +837 -304
  47. package/package.json +1 -1
  48. package/dist/chunk-AG4ORH2A.js.map +0 -1
  49. package/dist/chunk-C7SE5X44.js.map +0 -1
  50. package/dist/chunk-U36WHHML.js.map +0 -1
  51. package/dist/chunk-WE7SQ7PB.js.map +0 -1
  52. /package/dist/{chunk-TP4MD4PD.js.map → chunk-EZR72HCQ.js.map} +0 -0
  53. /package/dist/{chunk-JR2RWYQO.js.map → chunk-I5EF5KIT.js.map} +0 -0
  54. /package/dist/{chunk-EKSAOR2I.js.map → chunk-Q7TDHVRZ.js.map} +0 -0
@@ -14,7 +14,7 @@ import {
14
14
  TangleIdentityUnreachableError,
15
15
  createTangleIdentityClient,
16
16
  tangleIdentity
17
- } from "./chunk-WE7SQ7PB.js";
17
+ } from "./chunk-RRSNINEV.js";
18
18
  import {
19
19
  __export
20
20
  } from "./chunk-PZ5AY32C.js";
@@ -50,7 +50,9 @@ __export(adapters_exports, {
50
50
  altTextAiConnector: () => altTextAiConnector,
51
51
  alttextifyConnector: () => alttextifyConnector,
52
52
  amazonBedrockConnector: () => amazonBedrockConnector,
53
+ amazonCloudWatchConnector: () => amazonCloudWatchConnector,
53
54
  amazonEventBridgeConnector: () => amazonEventBridgeConnector,
55
+ amazonLambdaConnector: () => amazonLambdaConnector,
54
56
  amazonS3Connector: () => amazonS3Connector,
55
57
  amazonSecretsManagerConnector: () => amazonSecretsManagerConnector,
56
58
  amazonSesConnector: () => amazonSesConnector,
@@ -60,6 +62,7 @@ __export(adapters_exports, {
60
62
  aminosConnector: () => aminosConnector,
61
63
  ampecoConnector: () => ampecoConnector,
62
64
  amplemarketConnector: () => amplemarketConnector,
65
+ amplitudeConnector: () => amplitudeConnector,
63
66
  anthropicConnector: () => anthropicConnector,
64
67
  anyhookWebsocketConnector: () => anyhookWebsocketConnector,
65
68
  apifyConnector: () => apifyConnector,
@@ -118,6 +121,7 @@ __export(adapters_exports, {
118
121
  browseAiConnector: () => browseAiConnector,
119
122
  builtwithConnector: () => builtwithConnector,
120
123
  buttondownConnector: () => buttondownConnector,
124
+ calCom: () => calCom,
121
125
  calComConnector: () => calComConnector,
122
126
  calendlyConnector: () => calendlyConnector,
123
127
  cambAiConnector: () => cambAiConnector,
@@ -161,6 +165,7 @@ __export(adapters_exports, {
161
165
  clockodoConnector: () => clockodoConnector,
162
166
  closeConnector: () => closeConnector,
163
167
  cloudconvertConnector: () => cloudconvertConnector,
168
+ cloudflareConnector: () => cloudflareConnector,
164
169
  cloudinaryConnector: () => cloudinaryConnector,
165
170
  cloutlyConnector: () => cloutlyConnector,
166
171
  codaConnector: () => codaConnector,
@@ -604,6 +609,8 @@ __export(adapters_exports, {
604
609
  textcortexAiConnector: () => textcortexAiConnector,
605
610
  theirstackConnector: () => theirstackConnector,
606
611
  ticktickConnector: () => ticktickConnector,
612
+ tiktok: () => tiktok,
613
+ tiktokConnector: () => tiktokConnector,
607
614
  timeOpsConnector: () => timeOpsConnector,
608
615
  timelinesAiConnector: () => timelinesAiConnector,
609
616
  tlDvConnector: () => tlDvConnector,
@@ -747,8 +754,8 @@ function signSigV4(input) {
747
754
  const authorization = `${ALGORITHM} Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
748
755
  return { amzDate, signedHeaders, canonicalRequest, stringToSign, signature, authorization };
749
756
  }
750
- function amzDateNow(date = /* @__PURE__ */ new Date()) {
751
- return date.toISOString().replace(/[:-]|\.\d{3}/g, "");
757
+ function amzDateNow(date2 = /* @__PURE__ */ new Date()) {
758
+ return date2.toISOString().replace(/[:-]|\.\d{3}/g, "");
752
759
  }
753
760
  function hashSha256Hex(data4) {
754
761
  return createHash("sha256").update(data4, "utf8").digest("hex");
@@ -957,7 +964,7 @@ async function executeRestRequest(spec, request4, inv, requiredArgs) {
957
964
  const headers = {
958
965
  accept: "application/json",
959
966
  ...renderHeaders(spec.defaultHeaders ?? {}, scope, true),
960
- ...renderHeaders(renderableHeaders, scope)
967
+ ...renderHeaders(renderableHeaders, scope, false, requiredArgs)
961
968
  };
962
969
  const structuredCredentials = placement.kind === "structured-headers" || placement.kind === "structured-json-body" ? readStructuredCredentials(inv.source.credentials, placement.fields) : placement.kind === "basic-structured" ? readStructuredCredentials(inv.source.credentials, {
963
970
  [placement.usernameField]: placement.usernameField,
@@ -1011,7 +1018,8 @@ async function executeRestRequest(spec, request4, inv, requiredArgs) {
1011
1018
  body: bodyString,
1012
1019
  signal: AbortSignal.timeout(2e4)
1013
1020
  });
1014
- if (res.status === 401 || res.status === 403) {
1021
+ const credentialsExpiredStatuses = spec.credentialsExpiredStatuses ?? [401, 403];
1022
+ if (credentialsExpiredStatuses.includes(res.status)) {
1015
1023
  throw new CredentialsExpired(`${spec.displayName} rejected credentials (${res.status})`, inv.source.id);
1016
1024
  }
1017
1025
  if (res.status === 409 || res.status === 412) {
@@ -1188,7 +1196,12 @@ function credentialToken(credentials) {
1188
1196
  }
1189
1197
  function redactCredentialText(text, credentials, additionalSecrets = []) {
1190
1198
  const candidates = credentials.kind === "oauth2" ? [credentials.accessToken, credentials.refreshToken] : credentials.kind === "api-key" ? [credentials.apiKey, ...jsonStringValues(credentials.apiKey)] : credentials.kind === "custom" ? Object.values(credentials.values) : [];
1191
- const secrets = [...candidates, ...additionalSecrets].filter(
1199
+ const authorizationSecrets = additionalSecrets.flatMap((secret) => {
1200
+ if (typeof secret !== "string") return [];
1201
+ const credential2 = secret.match(/^(?:Basic|Bearer)\s+(.+)$/i)?.[1];
1202
+ return credential2 ? [secret, credential2] : [secret];
1203
+ });
1204
+ const secrets = [...candidates, ...authorizationSecrets].filter(
1192
1205
  (secret) => typeof secret === "string" && secret.length > 0
1193
1206
  );
1194
1207
  return secrets.reduce(
@@ -1270,12 +1283,24 @@ function retryAfterMsFromHeader(raw) {
1270
1283
  function renderScope(inv, credentialDefaults) {
1271
1284
  return { ...credentialDefaults, ...inv.args, connection: inv.source.metadata };
1272
1285
  }
1273
- function renderHeaders(headers, args, rawExact = false) {
1274
- return Object.fromEntries(Object.entries(headers).map(([key, value]) => {
1286
+ function renderHeaders(headers, args, rawExact = false, requiredArgs) {
1287
+ const out = {};
1288
+ for (const [key, value] of Object.entries(headers)) {
1275
1289
  const exact = value.match(/^\{([a-zA-Z0-9_.-]+)\}$/);
1276
- if (rawExact && exact) return [key, String(readRequiredPath(args, exact[1]))];
1277
- return [key, interpolate(value, args)];
1278
- }));
1290
+ if (exact) {
1291
+ const resolved = readPath(args, exact[1]);
1292
+ if (resolved === void 0 || resolved === null) {
1293
+ if (rawExact || requiredArgs?.includes(exact[1])) {
1294
+ throw new Error(`missing required argument: ${exact[1]}`);
1295
+ }
1296
+ continue;
1297
+ }
1298
+ out[key] = rawExact ? String(resolved) : encodeURIComponent(String(resolved));
1299
+ continue;
1300
+ }
1301
+ out[key] = interpolate(value, args);
1302
+ }
1303
+ return out;
1279
1304
  }
1280
1305
  function renderObject(input, args, requiredArgs) {
1281
1306
  const out = {};
@@ -20103,6 +20128,332 @@ function arbitraryBodyParameters() {
20103
20128
  };
20104
20129
  }
20105
20130
 
20131
+ // src/connectors/adapters/amplitude.ts
20132
+ var date = {
20133
+ type: "string",
20134
+ pattern: "^[0-9]{8}$",
20135
+ description: "Inclusive date in YYYYMMDD format."
20136
+ };
20137
+ var isoTimestamp = {
20138
+ type: "string",
20139
+ description: "ISO 8601 timestamp with a time-zone offset."
20140
+ };
20141
+ var annotationId = {
20142
+ annotationId: { type: "integer", minimum: 1, description: "Amplitude annotation ID." }
20143
+ };
20144
+ var categoryId = {
20145
+ categoryId: { type: "integer", minimum: 1, description: "Amplitude annotation category ID." }
20146
+ };
20147
+ var annotation = {
20148
+ type: "object",
20149
+ properties: {
20150
+ label: { type: "string", minLength: 1 },
20151
+ start: isoTimestamp,
20152
+ category: { type: "string" },
20153
+ chart_id: { type: ["string", "null"] },
20154
+ details: { type: "string" },
20155
+ end: { ...isoTimestamp, type: ["string", "null"] }
20156
+ },
20157
+ required: ["label", "start"],
20158
+ additionalProperties: false
20159
+ };
20160
+ var amplitudeConnector = declarativeRestConnector({
20161
+ kind: "amplitude",
20162
+ displayName: "Amplitude",
20163
+ description: "Query project analytics and manage chart annotations with Amplitude project API credentials.",
20164
+ auth: {
20165
+ kind: "api-key",
20166
+ hint: 'JSON credential bundle: {"apiKey":"...","secretKey":"..."} from Project Settings \u2192 General. Set metadata.apiBaseUrl to https://analytics.eu.amplitude.com only for an EU-resident project; the default is https://amplitude.com.'
20167
+ },
20168
+ category: "other",
20169
+ defaultConsistencyModel: "authoritative",
20170
+ baseUrl: { metadataKey: "apiBaseUrl", fallback: "https://amplitude.com" },
20171
+ allowedBaseUrls: ["https://amplitude.com", "https://analytics.eu.amplitude.com"],
20172
+ credentialPlacement: {
20173
+ kind: "basic-structured",
20174
+ usernameField: "apiKey",
20175
+ passwordField: "secretKey"
20176
+ },
20177
+ test: { method: "GET", path: "/api/2/events/list" },
20178
+ capabilities: [
20179
+ {
20180
+ name: "events.list",
20181
+ class: "read",
20182
+ description: "List visible project events with current-week totals, uniques, and daily-active-user share.",
20183
+ parameters: { type: "object", properties: {} },
20184
+ request: { method: "GET", path: "/api/2/events/list" }
20185
+ },
20186
+ {
20187
+ name: "events.segment",
20188
+ class: "read",
20189
+ description: "Query event totals, uniques, percentages, averages, or formulas over a date range.",
20190
+ parameters: {
20191
+ type: "object",
20192
+ properties: {
20193
+ event: {
20194
+ type: "string",
20195
+ description: 'JSON event definition, for example {"event_type":"_active"}.'
20196
+ },
20197
+ secondEvent: { type: "string", description: "Optional second JSON event definition." },
20198
+ metric: {
20199
+ type: "string",
20200
+ enum: ["uniques", "totals", "pct_dau", "average", "histogram", "sums", "value_avg", "formula"]
20201
+ },
20202
+ activeUserType: { type: "string", enum: ["any", "active"] },
20203
+ start: date,
20204
+ end: date,
20205
+ interval: { type: "integer", enum: [-3e5, -36e5, 1, 7, 30] },
20206
+ segment: { type: "string", description: "JSON array of Amplitude segment definitions." },
20207
+ groupBy: { type: "string" },
20208
+ secondGroupBy: { type: "string" },
20209
+ limit: { type: "integer", minimum: 1, maximum: 1e3 },
20210
+ formula: { type: "string" },
20211
+ rollingWindow: { type: "integer", minimum: 1 },
20212
+ rollingAverage: { type: "integer", minimum: 1 }
20213
+ },
20214
+ required: ["event", "start", "end"]
20215
+ },
20216
+ request: {
20217
+ method: "GET",
20218
+ path: "/api/2/events/segmentation",
20219
+ query: {
20220
+ e: "{event}",
20221
+ e2: "{secondEvent}",
20222
+ m: "{metric}",
20223
+ n: "{activeUserType}",
20224
+ start: "{start}",
20225
+ end: "{end}",
20226
+ i: "{interval}",
20227
+ s: "{segment}",
20228
+ g: "{groupBy}",
20229
+ g2: "{secondGroupBy}",
20230
+ limit: "{limit}",
20231
+ formula: "{formula}",
20232
+ rollingWindow: "{rollingWindow}",
20233
+ rollingAverage: "{rollingAverage}"
20234
+ }
20235
+ }
20236
+ },
20237
+ {
20238
+ name: "users.counts",
20239
+ class: "read",
20240
+ description: "Get active or new user counts over a date range.",
20241
+ parameters: {
20242
+ type: "object",
20243
+ properties: {
20244
+ start: date,
20245
+ end: date,
20246
+ mode: { type: "string", enum: ["active", "new"] },
20247
+ interval: { type: "integer", enum: [1, 7, 30] },
20248
+ segment: { type: "string", description: "JSON array of Amplitude segment definitions." },
20249
+ groupBy: { type: "string" }
20250
+ },
20251
+ required: ["start", "end"]
20252
+ },
20253
+ request: {
20254
+ method: "GET",
20255
+ path: "/api/2/users",
20256
+ query: {
20257
+ start: "{start}",
20258
+ end: "{end}",
20259
+ m: "{mode}",
20260
+ i: "{interval}",
20261
+ s: "{segment}",
20262
+ g: "{groupBy}"
20263
+ }
20264
+ }
20265
+ },
20266
+ {
20267
+ name: "sessions.average-length",
20268
+ class: "read",
20269
+ description: "Get average session length in seconds for each day in a date range.",
20270
+ parameters: {
20271
+ type: "object",
20272
+ properties: { start: date, end: date },
20273
+ required: ["start", "end"]
20274
+ },
20275
+ request: {
20276
+ method: "GET",
20277
+ path: "/api/2/sessions/average",
20278
+ query: { start: "{start}", end: "{end}" }
20279
+ }
20280
+ },
20281
+ {
20282
+ name: "users.search",
20283
+ class: "read",
20284
+ description: "Search for a user by Amplitude ID, device ID, user ID, or user ID prefix.",
20285
+ parameters: {
20286
+ type: "object",
20287
+ properties: { user: { type: "string", minLength: 1 } },
20288
+ required: ["user"]
20289
+ },
20290
+ request: { method: "GET", path: "/api/2/usersearch", query: { user: "{user}" } }
20291
+ },
20292
+ {
20293
+ name: "users.activity",
20294
+ class: "read",
20295
+ description: "Read one user summary and a bounded window of recent or earliest events.",
20296
+ parameters: {
20297
+ type: "object",
20298
+ properties: {
20299
+ user: { type: "string", minLength: 1, description: "Amplitude user ID." },
20300
+ offset: { type: "integer", minimum: 0 },
20301
+ limit: { type: "integer", minimum: 0, maximum: 1e3 },
20302
+ direction: { type: "string", enum: ["earliest", "latest"] }
20303
+ },
20304
+ required: ["user"]
20305
+ },
20306
+ request: {
20307
+ method: "GET",
20308
+ path: "/api/2/useractivity",
20309
+ query: { user: "{user}", offset: "{offset}", limit: "{limit}", direction: "{direction}" }
20310
+ }
20311
+ },
20312
+ {
20313
+ name: "charts.results",
20314
+ class: "read",
20315
+ description: "Export results from one saved Amplitude chart by chart ID.",
20316
+ parameters: {
20317
+ type: "object",
20318
+ properties: { chartId: { type: "string", minLength: 1 } },
20319
+ required: ["chartId"]
20320
+ },
20321
+ request: { method: "GET", path: "/api/3/chart/{chartId}/csv" }
20322
+ },
20323
+ {
20324
+ name: "annotations.list",
20325
+ class: "read",
20326
+ description: "List project chart annotations with optional category, chart, and date filters.",
20327
+ parameters: {
20328
+ type: "object",
20329
+ properties: {
20330
+ category: { type: "string" },
20331
+ chartId: { type: "string" },
20332
+ start: isoTimestamp,
20333
+ end: isoTimestamp
20334
+ }
20335
+ },
20336
+ request: {
20337
+ method: "GET",
20338
+ path: "/api/3/annotations",
20339
+ query: { category: "{category}", chart_id: "{chartId}", start: "{start}", end: "{end}" }
20340
+ }
20341
+ },
20342
+ {
20343
+ name: "annotations.get",
20344
+ class: "read",
20345
+ description: "Read one chart annotation by ID.",
20346
+ parameters: { type: "object", properties: annotationId, required: ["annotationId"] },
20347
+ request: { method: "GET", path: "/api/3/annotations/{annotationId}" }
20348
+ },
20349
+ {
20350
+ name: "annotations.create",
20351
+ class: "mutation",
20352
+ description: "Create a project-wide or chart-specific annotation.",
20353
+ parameters: {
20354
+ type: "object",
20355
+ properties: { annotation },
20356
+ required: ["annotation"]
20357
+ },
20358
+ request: { method: "POST", path: "/api/3/annotations", body: "{annotation}" },
20359
+ cas: "none",
20360
+ externalEffect: true
20361
+ },
20362
+ {
20363
+ name: "annotations.update",
20364
+ class: "mutation",
20365
+ description: "Partially update one annotation.",
20366
+ parameters: {
20367
+ type: "object",
20368
+ properties: {
20369
+ ...annotationId,
20370
+ changes: {
20371
+ ...annotation,
20372
+ required: []
20373
+ }
20374
+ },
20375
+ required: ["annotationId", "changes"]
20376
+ },
20377
+ request: { method: "PUT", path: "/api/3/annotations/{annotationId}", body: "{changes}" },
20378
+ cas: "optimistic-read-verify",
20379
+ externalEffect: true
20380
+ },
20381
+ {
20382
+ name: "annotations.delete",
20383
+ class: "mutation",
20384
+ description: "Permanently delete one annotation.",
20385
+ parameters: { type: "object", properties: annotationId, required: ["annotationId"] },
20386
+ request: { method: "DELETE", path: "/api/3/annotations/{annotationId}" },
20387
+ cas: "optimistic-read-verify",
20388
+ externalEffect: true
20389
+ },
20390
+ {
20391
+ name: "annotation-categories.list",
20392
+ class: "read",
20393
+ description: "List annotation categories or filter by exact category name.",
20394
+ parameters: {
20395
+ type: "object",
20396
+ properties: { category: { type: "string" } }
20397
+ },
20398
+ request: {
20399
+ method: "GET",
20400
+ path: "/api/3/annotation-categories",
20401
+ query: { category: "{category}" }
20402
+ }
20403
+ },
20404
+ {
20405
+ name: "annotation-categories.get",
20406
+ class: "read",
20407
+ description: "Read one annotation category by ID.",
20408
+ parameters: { type: "object", properties: categoryId, required: ["categoryId"] },
20409
+ request: { method: "GET", path: "/api/3/annotation-categories/{categoryId}" }
20410
+ },
20411
+ {
20412
+ name: "annotation-categories.create",
20413
+ class: "mutation",
20414
+ description: "Create an annotation category.",
20415
+ parameters: {
20416
+ type: "object",
20417
+ properties: { category: { type: "string", minLength: 1 } },
20418
+ required: ["category"]
20419
+ },
20420
+ request: {
20421
+ method: "POST",
20422
+ path: "/api/3/annotation-categories",
20423
+ body: { category: "{category}" }
20424
+ },
20425
+ cas: "none",
20426
+ externalEffect: true
20427
+ },
20428
+ {
20429
+ name: "annotation-categories.update",
20430
+ class: "mutation",
20431
+ description: "Rename one annotation category.",
20432
+ parameters: {
20433
+ type: "object",
20434
+ properties: { ...categoryId, category: { type: "string", minLength: 1 } },
20435
+ required: ["categoryId", "category"]
20436
+ },
20437
+ request: {
20438
+ method: "PUT",
20439
+ path: "/api/3/annotation-categories/{categoryId}",
20440
+ body: { category: "{category}" }
20441
+ },
20442
+ cas: "optimistic-read-verify",
20443
+ externalEffect: true
20444
+ },
20445
+ {
20446
+ name: "annotation-categories.delete",
20447
+ class: "mutation",
20448
+ description: "Permanently delete one annotation category.",
20449
+ parameters: { type: "object", properties: categoryId, required: ["categoryId"] },
20450
+ request: { method: "DELETE", path: "/api/3/annotation-categories/{categoryId}" },
20451
+ cas: "optimistic-read-verify",
20452
+ externalEffect: true
20453
+ }
20454
+ ]
20455
+ });
20456
+
20106
20457
  // src/connectors/adapters/amazon-eventbridge.ts
20107
20458
  var amazonEventBridgeConnector = declarativeRestConnector({
20108
20459
  kind: "amazon-eventbridge",
@@ -20442,6 +20793,717 @@ var amazonEventBridgeConnector = declarativeRestConnector({
20442
20793
  ]
20443
20794
  });
20444
20795
 
20796
+ // src/connectors/adapters/amazon-cloudwatch.ts
20797
+ var target = (operation) => `GraniteServiceVersion20100801.${operation}`;
20798
+ var amazonCloudWatchConnector = declarativeRestConnector({
20799
+ kind: "aws-cloudwatch",
20800
+ displayName: "AWS CloudWatch",
20801
+ description: "Read and publish CloudWatch metrics, manage metric alarms, and manage dashboards.",
20802
+ auth: {
20803
+ kind: "api-key",
20804
+ hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA\u2026","secretAccessKey":"\u2026","region":"us-east-1"}. Optional "sessionToken" and "endpoint" support temporary credentials and local AWS-compatible endpoints.'
20805
+ },
20806
+ category: "other",
20807
+ // Metric publication is eventually consistent and cannot be deduplicated by
20808
+ // a caller-provided key. Alarm and dashboard writes use stronger CAS labels.
20809
+ defaultConsistencyModel: "advisory",
20810
+ credentialPlacement: { kind: "aws-sigv4", service: "monitoring" },
20811
+ baseUrl: {
20812
+ metadataKey: "endpoint",
20813
+ fallback: "https://monitoring.{region}.amazonaws.com"
20814
+ },
20815
+ defaultHeaders: {
20816
+ "Content-Type": "application/x-amz-json-1.0"
20817
+ },
20818
+ test: {
20819
+ method: "POST",
20820
+ path: "/",
20821
+ headers: { "X-Amz-Target": target("ListMetrics") },
20822
+ body: {}
20823
+ },
20824
+ capabilities: [
20825
+ {
20826
+ name: "metrics.list",
20827
+ class: "read",
20828
+ description: "List available CloudWatch metrics and their dimensions.",
20829
+ parameters: {
20830
+ type: "object",
20831
+ properties: {
20832
+ namespace: { type: "string" },
20833
+ metricName: { type: "string" },
20834
+ dimensions: { type: "array", description: "AWS DimensionFilter objects." },
20835
+ nextToken: { type: "string" },
20836
+ recentlyActive: { type: "string", enum: ["PT3H"] },
20837
+ includeLinkedAccounts: { type: "boolean" },
20838
+ owningAccount: { type: "string" }
20839
+ }
20840
+ },
20841
+ request: {
20842
+ method: "POST",
20843
+ path: "/",
20844
+ headers: { "X-Amz-Target": target("ListMetrics") },
20845
+ body: {
20846
+ Namespace: "{namespace}",
20847
+ MetricName: "{metricName}",
20848
+ Dimensions: "{dimensions}",
20849
+ NextToken: "{nextToken}",
20850
+ RecentlyActive: "{recentlyActive}",
20851
+ IncludeLinkedAccounts: "{includeLinkedAccounts}",
20852
+ OwningAccount: "{owningAccount}"
20853
+ }
20854
+ }
20855
+ },
20856
+ {
20857
+ name: "metrics.statistics.get",
20858
+ class: "read",
20859
+ description: "Get statistics for one metric over a time range.",
20860
+ parameters: {
20861
+ type: "object",
20862
+ properties: {
20863
+ namespace: { type: "string" },
20864
+ metricName: { type: "string" },
20865
+ dimensions: { type: "array", description: "AWS Dimension objects." },
20866
+ startTime: { type: "number", description: "Unix epoch seconds." },
20867
+ endTime: { type: "number", description: "Unix epoch seconds." },
20868
+ period: { type: "integer", description: "Aggregation period in seconds." },
20869
+ statistics: { type: "array", items: { type: "string" } },
20870
+ extendedStatistics: { type: "array", items: { type: "string" } },
20871
+ unit: { type: "string" }
20872
+ },
20873
+ required: ["namespace", "metricName", "startTime", "endTime", "period"]
20874
+ },
20875
+ request: {
20876
+ method: "POST",
20877
+ path: "/",
20878
+ headers: { "X-Amz-Target": target("GetMetricStatistics") },
20879
+ body: {
20880
+ Namespace: "{namespace}",
20881
+ MetricName: "{metricName}",
20882
+ Dimensions: "{dimensions}",
20883
+ StartTime: "{startTime}",
20884
+ EndTime: "{endTime}",
20885
+ Period: "{period}",
20886
+ Statistics: "{statistics}",
20887
+ ExtendedStatistics: "{extendedStatistics}",
20888
+ Unit: "{unit}"
20889
+ }
20890
+ }
20891
+ },
20892
+ {
20893
+ name: "metrics.data.get",
20894
+ class: "read",
20895
+ description: "Run up to 500 metric-data or metric-math queries in one request.",
20896
+ parameters: {
20897
+ type: "object",
20898
+ properties: {
20899
+ metricDataQueries: { type: "array", description: "AWS MetricDataQuery objects." },
20900
+ startTime: { type: "number", description: "Unix epoch seconds." },
20901
+ endTime: { type: "number", description: "Unix epoch seconds." },
20902
+ nextToken: { type: "string" },
20903
+ scanBy: { type: "string", enum: ["TimestampDescending", "TimestampAscending"] },
20904
+ maxDatapoints: { type: "integer" },
20905
+ labelOptions: { type: "object" }
20906
+ },
20907
+ required: ["metricDataQueries", "startTime", "endTime"]
20908
+ },
20909
+ request: {
20910
+ method: "POST",
20911
+ path: "/",
20912
+ headers: { "X-Amz-Target": target("GetMetricData") },
20913
+ body: {
20914
+ MetricDataQueries: "{metricDataQueries}",
20915
+ StartTime: "{startTime}",
20916
+ EndTime: "{endTime}",
20917
+ NextToken: "{nextToken}",
20918
+ ScanBy: "{scanBy}",
20919
+ MaxDatapoints: "{maxDatapoints}",
20920
+ LabelOptions: "{labelOptions}"
20921
+ }
20922
+ }
20923
+ },
20924
+ {
20925
+ name: "alarms.list",
20926
+ class: "read",
20927
+ description: "List metric and composite alarms with optional filters.",
20928
+ parameters: {
20929
+ type: "object",
20930
+ properties: {
20931
+ alarmNames: { type: "array", items: { type: "string" } },
20932
+ alarmNamePrefix: { type: "string" },
20933
+ alarmTypes: { type: "array", items: { type: "string" } },
20934
+ childrenOfAlarmName: { type: "string" },
20935
+ parentsOfAlarmName: { type: "string" },
20936
+ stateValue: { type: "string", enum: ["OK", "ALARM", "INSUFFICIENT_DATA"] },
20937
+ actionPrefix: { type: "string" },
20938
+ maxRecords: { type: "integer" },
20939
+ nextToken: { type: "string" }
20940
+ }
20941
+ },
20942
+ request: {
20943
+ method: "POST",
20944
+ path: "/",
20945
+ headers: { "X-Amz-Target": target("DescribeAlarms") },
20946
+ body: {
20947
+ AlarmNames: "{alarmNames}",
20948
+ AlarmNamePrefix: "{alarmNamePrefix}",
20949
+ AlarmTypes: "{alarmTypes}",
20950
+ ChildrenOfAlarmName: "{childrenOfAlarmName}",
20951
+ ParentsOfAlarmName: "{parentsOfAlarmName}",
20952
+ StateValue: "{stateValue}",
20953
+ ActionPrefix: "{actionPrefix}",
20954
+ MaxRecords: "{maxRecords}",
20955
+ NextToken: "{nextToken}"
20956
+ }
20957
+ }
20958
+ },
20959
+ {
20960
+ name: "dashboards.list",
20961
+ class: "read",
20962
+ description: "List CloudWatch dashboards in the account.",
20963
+ parameters: {
20964
+ type: "object",
20965
+ properties: {
20966
+ dashboardNamePrefix: { type: "string" },
20967
+ nextToken: { type: "string" }
20968
+ }
20969
+ },
20970
+ request: {
20971
+ method: "POST",
20972
+ path: "/",
20973
+ headers: { "X-Amz-Target": target("ListDashboards") },
20974
+ body: {
20975
+ DashboardNamePrefix: "{dashboardNamePrefix}",
20976
+ NextToken: "{nextToken}"
20977
+ }
20978
+ }
20979
+ },
20980
+ {
20981
+ name: "dashboards.get",
20982
+ class: "read",
20983
+ description: "Get one CloudWatch dashboard definition.",
20984
+ parameters: {
20985
+ type: "object",
20986
+ properties: { dashboardName: { type: "string" } },
20987
+ required: ["dashboardName"]
20988
+ },
20989
+ request: {
20990
+ method: "POST",
20991
+ path: "/",
20992
+ headers: { "X-Amz-Target": target("GetDashboard") },
20993
+ body: { DashboardName: "{dashboardName}" }
20994
+ }
20995
+ },
20996
+ {
20997
+ name: "metrics.publish",
20998
+ class: "mutation",
20999
+ description: "Publish custom metric data or entity metric data to CloudWatch.",
21000
+ parameters: {
21001
+ type: "object",
21002
+ properties: {
21003
+ namespace: { type: "string" },
21004
+ metricData: { type: "array", description: "AWS MetricDatum objects." },
21005
+ entityMetricData: { type: "array", description: "AWS EntityMetricData objects." },
21006
+ strictEntityValidation: { type: "boolean" }
21007
+ },
21008
+ required: ["namespace"]
21009
+ },
21010
+ request: {
21011
+ method: "POST",
21012
+ path: "/",
21013
+ headers: { "X-Amz-Target": target("PutMetricData") },
21014
+ body: {
21015
+ Namespace: "{namespace}",
21016
+ MetricData: "{metricData}",
21017
+ EntityMetricData: "{entityMetricData}",
21018
+ StrictEntityValidation: "{strictEntityValidation}"
21019
+ }
21020
+ },
21021
+ cas: "none",
21022
+ externalEffect: true
21023
+ },
21024
+ {
21025
+ name: "alarms.put",
21026
+ class: "mutation",
21027
+ description: "Create or fully replace a CloudWatch metric alarm.",
21028
+ parameters: {
21029
+ type: "object",
21030
+ properties: {
21031
+ alarm: {
21032
+ type: "object",
21033
+ description: "AWS PutMetricAlarm input without undeclared transport fields."
21034
+ }
21035
+ },
21036
+ required: ["alarm"]
21037
+ },
21038
+ request: {
21039
+ method: "POST",
21040
+ path: "/",
21041
+ headers: { "X-Amz-Target": target("PutMetricAlarm") },
21042
+ body: "{alarm}"
21043
+ },
21044
+ cas: "optimistic-read-verify",
21045
+ externalEffect: true
21046
+ },
21047
+ {
21048
+ name: "alarms.delete",
21049
+ class: "mutation",
21050
+ description: "Delete up to 100 CloudWatch alarms by name.",
21051
+ parameters: {
21052
+ type: "object",
21053
+ properties: {
21054
+ alarmNames: { type: "array", items: { type: "string" } }
21055
+ },
21056
+ required: ["alarmNames"]
21057
+ },
21058
+ request: {
21059
+ method: "POST",
21060
+ path: "/",
21061
+ headers: { "X-Amz-Target": target("DeleteAlarms") },
21062
+ body: { AlarmNames: "{alarmNames}" }
21063
+ },
21064
+ cas: "native-idempotency",
21065
+ externalEffect: true
21066
+ },
21067
+ {
21068
+ name: "dashboards.put",
21069
+ class: "mutation",
21070
+ description: "Create or fully replace a CloudWatch dashboard.",
21071
+ parameters: {
21072
+ type: "object",
21073
+ properties: {
21074
+ dashboardName: { type: "string" },
21075
+ dashboardBody: { type: "string", description: "CloudWatch dashboard JSON string." }
21076
+ },
21077
+ required: ["dashboardName", "dashboardBody"]
21078
+ },
21079
+ request: {
21080
+ method: "POST",
21081
+ path: "/",
21082
+ headers: { "X-Amz-Target": target("PutDashboard") },
21083
+ body: {
21084
+ DashboardName: "{dashboardName}",
21085
+ DashboardBody: "{dashboardBody}"
21086
+ }
21087
+ },
21088
+ cas: "optimistic-read-verify",
21089
+ externalEffect: true
21090
+ },
21091
+ {
21092
+ name: "dashboards.delete",
21093
+ class: "mutation",
21094
+ description: "Delete up to 100 CloudWatch dashboards by name.",
21095
+ parameters: {
21096
+ type: "object",
21097
+ properties: {
21098
+ dashboardNames: { type: "array", items: { type: "string" } }
21099
+ },
21100
+ required: ["dashboardNames"]
21101
+ },
21102
+ request: {
21103
+ method: "POST",
21104
+ path: "/",
21105
+ headers: { "X-Amz-Target": target("DeleteDashboards") },
21106
+ body: { DashboardNames: "{dashboardNames}" }
21107
+ },
21108
+ cas: "native-idempotency",
21109
+ externalEffect: true
21110
+ }
21111
+ ]
21112
+ });
21113
+
21114
+ // src/connectors/adapters/amazon-lambda.ts
21115
+ var awsCredentialHint = 'AWS credentials as JSON: {"accessKeyId":"AKIA\u2026","secretAccessKey":"\u2026","region":"us-east-1"}. Optional "sessionToken" and "endpoint" support temporary credentials and local AWS-compatible endpoints.';
21116
+ var amazonLambdaConnector = declarativeRestConnector({
21117
+ kind: "aws-lambda",
21118
+ displayName: "AWS Lambda",
21119
+ description: "Inspect, invoke, create, update, version, alias, and delete AWS Lambda functions.",
21120
+ auth: { kind: "api-key", hint: awsCredentialHint },
21121
+ category: "other",
21122
+ // Lambda invocation is at-least-once and can cause arbitrary downstream
21123
+ // effects. The connection cannot promise authoritative mutation replay.
21124
+ defaultConsistencyModel: "advisory",
21125
+ credentialPlacement: { kind: "aws-sigv4", service: "lambda" },
21126
+ baseUrl: {
21127
+ metadataKey: "endpoint",
21128
+ fallback: "https://lambda.{region}.amazonaws.com"
21129
+ },
21130
+ test: {
21131
+ method: "GET",
21132
+ path: "/2015-03-31/functions",
21133
+ query: { MaxItems: "1" }
21134
+ },
21135
+ capabilities: [
21136
+ {
21137
+ name: "functions.list",
21138
+ class: "read",
21139
+ description: "List Lambda functions in the configured AWS region.",
21140
+ parameters: {
21141
+ type: "object",
21142
+ properties: {
21143
+ marker: { type: "string", description: "Pagination marker." },
21144
+ maxItems: { type: "integer", description: "Maximum functions to return (1-50)." },
21145
+ functionVersion: {
21146
+ type: "string",
21147
+ enum: ["ALL"],
21148
+ description: "Include published versions when set to ALL."
21149
+ },
21150
+ masterRegion: { type: "string", description: "Filter Lambda@Edge replicas by region." }
21151
+ }
21152
+ },
21153
+ request: {
21154
+ method: "GET",
21155
+ path: "/2015-03-31/functions",
21156
+ query: {
21157
+ Marker: "{marker}",
21158
+ MaxItems: "{maxItems}",
21159
+ FunctionVersion: "{functionVersion}",
21160
+ MasterRegion: "{masterRegion}"
21161
+ }
21162
+ }
21163
+ },
21164
+ {
21165
+ name: "functions.get",
21166
+ class: "read",
21167
+ description: "Get one function configuration and its temporary deployment-package URL.",
21168
+ parameters: {
21169
+ type: "object",
21170
+ properties: {
21171
+ functionName: { type: "string", description: "Function name or ARN." },
21172
+ qualifier: { type: "string", description: "Version number or alias." }
21173
+ },
21174
+ required: ["functionName"]
21175
+ },
21176
+ request: {
21177
+ method: "GET",
21178
+ path: "/2015-03-31/functions/{functionName}",
21179
+ query: { Qualifier: "{qualifier}" }
21180
+ }
21181
+ },
21182
+ {
21183
+ name: "aliases.list",
21184
+ class: "read",
21185
+ description: "List aliases for a Lambda function.",
21186
+ parameters: {
21187
+ type: "object",
21188
+ properties: {
21189
+ functionName: { type: "string" },
21190
+ functionVersion: { type: "string" },
21191
+ marker: { type: "string" },
21192
+ maxItems: { type: "integer" }
21193
+ },
21194
+ required: ["functionName"]
21195
+ },
21196
+ request: {
21197
+ method: "GET",
21198
+ path: "/2015-03-31/functions/{functionName}/aliases",
21199
+ query: {
21200
+ FunctionVersion: "{functionVersion}",
21201
+ Marker: "{marker}",
21202
+ MaxItems: "{maxItems}"
21203
+ }
21204
+ }
21205
+ },
21206
+ {
21207
+ name: "functions.invoke",
21208
+ class: "mutation",
21209
+ description: "Invoke a Lambda function synchronously, asynchronously, or as a dry-run permission check.",
21210
+ parameters: {
21211
+ type: "object",
21212
+ properties: {
21213
+ functionName: { type: "string", description: "Function name or ARN." },
21214
+ qualifier: { type: "string", description: "Version number or alias." },
21215
+ invocationType: {
21216
+ type: "string",
21217
+ enum: ["RequestResponse", "Event", "DryRun"]
21218
+ },
21219
+ logType: { type: "string", enum: ["None", "Tail"] },
21220
+ clientContext: {
21221
+ type: "string",
21222
+ description: "Base64-encoded client context for synchronous invocation."
21223
+ },
21224
+ payload: {
21225
+ description: "JSON payload passed directly to the function."
21226
+ }
21227
+ },
21228
+ required: ["functionName", "payload"]
21229
+ },
21230
+ request: {
21231
+ method: "POST",
21232
+ path: "/2015-03-31/functions/{functionName}/invocations",
21233
+ query: { Qualifier: "{qualifier}" },
21234
+ headers: {
21235
+ "X-Amz-Invocation-Type": "{invocationType}",
21236
+ "X-Amz-Log-Type": "{logType}",
21237
+ "X-Amz-Client-Context": "{clientContext}"
21238
+ },
21239
+ body: "{payload}"
21240
+ },
21241
+ cas: "none",
21242
+ externalEffect: true
21243
+ },
21244
+ {
21245
+ name: "functions.create",
21246
+ class: "mutation",
21247
+ description: "Create a Lambda function from an S3 object, inline zip, or ECR image.",
21248
+ parameters: {
21249
+ type: "object",
21250
+ properties: {
21251
+ functionName: { type: "string" },
21252
+ role: { type: "string", description: "Execution-role ARN." },
21253
+ code: {
21254
+ type: "object",
21255
+ description: "AWS FunctionCode shape: S3Bucket/S3Key/S3ObjectVersion, ZipFile, or ImageUri."
21256
+ },
21257
+ runtime: { type: "string" },
21258
+ handler: { type: "string" },
21259
+ description: { type: "string" },
21260
+ timeout: { type: "integer" },
21261
+ memorySize: { type: "integer" },
21262
+ publish: { type: "boolean" },
21263
+ packageType: { type: "string", enum: ["Zip", "Image"] },
21264
+ architectures: { type: "array", items: { type: "string" } },
21265
+ environment: { type: "object", description: "AWS Environment shape." },
21266
+ vpcConfig: { type: "object", description: "AWS VpcConfig shape." },
21267
+ layers: { type: "array", items: { type: "string" } },
21268
+ tags: { type: "object" },
21269
+ ephemeralStorage: { type: "object" },
21270
+ loggingConfig: { type: "object" }
21271
+ },
21272
+ required: ["functionName", "role", "code"]
21273
+ },
21274
+ request: {
21275
+ method: "POST",
21276
+ path: "/2015-03-31/functions",
21277
+ body: {
21278
+ FunctionName: "{functionName}",
21279
+ Role: "{role}",
21280
+ Code: "{code}",
21281
+ Runtime: "{runtime}",
21282
+ Handler: "{handler}",
21283
+ Description: "{description}",
21284
+ Timeout: "{timeout}",
21285
+ MemorySize: "{memorySize}",
21286
+ Publish: "{publish}",
21287
+ PackageType: "{packageType}",
21288
+ Architectures: "{architectures}",
21289
+ Environment: "{environment}",
21290
+ VpcConfig: "{vpcConfig}",
21291
+ Layers: "{layers}",
21292
+ Tags: "{tags}",
21293
+ EphemeralStorage: "{ephemeralStorage}",
21294
+ LoggingConfig: "{loggingConfig}"
21295
+ }
21296
+ },
21297
+ cas: "native-idempotency",
21298
+ externalEffect: true
21299
+ },
21300
+ {
21301
+ name: "functions.code.update",
21302
+ class: "mutation",
21303
+ description: "Replace the unpublished code for a Lambda function.",
21304
+ parameters: {
21305
+ type: "object",
21306
+ properties: {
21307
+ functionName: { type: "string" },
21308
+ s3Bucket: { type: "string" },
21309
+ s3Key: { type: "string" },
21310
+ s3ObjectVersion: { type: "string" },
21311
+ imageUri: { type: "string" },
21312
+ zipFile: { type: "string", description: "Base64-encoded zip bytes." },
21313
+ publish: { type: "boolean" },
21314
+ dryRun: { type: "boolean" },
21315
+ revisionId: { type: "string" },
21316
+ architectures: { type: "array", items: { type: "string" } }
21317
+ },
21318
+ required: ["functionName"]
21319
+ },
21320
+ request: {
21321
+ method: "PUT",
21322
+ path: "/2015-03-31/functions/{functionName}/code",
21323
+ body: {
21324
+ S3Bucket: "{s3Bucket}",
21325
+ S3Key: "{s3Key}",
21326
+ S3ObjectVersion: "{s3ObjectVersion}",
21327
+ ImageUri: "{imageUri}",
21328
+ ZipFile: "{zipFile}",
21329
+ Publish: "{publish}",
21330
+ DryRun: "{dryRun}",
21331
+ RevisionId: "{revisionId}",
21332
+ Architectures: "{architectures}"
21333
+ }
21334
+ },
21335
+ cas: "optimistic-read-verify",
21336
+ externalEffect: true
21337
+ },
21338
+ {
21339
+ name: "functions.configuration.update",
21340
+ class: "mutation",
21341
+ description: "Update the unpublished configuration for a Lambda function.",
21342
+ parameters: {
21343
+ type: "object",
21344
+ properties: {
21345
+ functionName: { type: "string" },
21346
+ role: { type: "string" },
21347
+ handler: { type: "string" },
21348
+ description: { type: "string" },
21349
+ timeout: { type: "integer" },
21350
+ memorySize: { type: "integer" },
21351
+ runtime: { type: "string" },
21352
+ environment: { type: "object" },
21353
+ layers: { type: "array", items: { type: "string" } },
21354
+ vpcConfig: { type: "object" },
21355
+ revisionId: { type: "string" },
21356
+ ephemeralStorage: { type: "object" },
21357
+ loggingConfig: { type: "object" }
21358
+ },
21359
+ required: ["functionName"]
21360
+ },
21361
+ request: {
21362
+ method: "PUT",
21363
+ path: "/2015-03-31/functions/{functionName}/configuration",
21364
+ body: {
21365
+ Role: "{role}",
21366
+ Handler: "{handler}",
21367
+ Description: "{description}",
21368
+ Timeout: "{timeout}",
21369
+ MemorySize: "{memorySize}",
21370
+ Runtime: "{runtime}",
21371
+ Environment: "{environment}",
21372
+ Layers: "{layers}",
21373
+ VpcConfig: "{vpcConfig}",
21374
+ RevisionId: "{revisionId}",
21375
+ EphemeralStorage: "{ephemeralStorage}",
21376
+ LoggingConfig: "{loggingConfig}"
21377
+ }
21378
+ },
21379
+ cas: "optimistic-read-verify",
21380
+ externalEffect: true
21381
+ },
21382
+ {
21383
+ name: "versions.publish",
21384
+ class: "mutation",
21385
+ description: "Publish an immutable version from the current function code and configuration.",
21386
+ parameters: {
21387
+ type: "object",
21388
+ properties: {
21389
+ functionName: { type: "string" },
21390
+ codeSha256: { type: "string" },
21391
+ description: { type: "string" },
21392
+ revisionId: { type: "string" }
21393
+ },
21394
+ required: ["functionName"]
21395
+ },
21396
+ request: {
21397
+ method: "POST",
21398
+ path: "/2015-03-31/functions/{functionName}/versions",
21399
+ body: {
21400
+ CodeSha256: "{codeSha256}",
21401
+ Description: "{description}",
21402
+ RevisionId: "{revisionId}"
21403
+ }
21404
+ },
21405
+ cas: "optimistic-read-verify",
21406
+ externalEffect: true
21407
+ },
21408
+ {
21409
+ name: "aliases.create",
21410
+ class: "mutation",
21411
+ description: "Create an alias that points to a published function version.",
21412
+ parameters: {
21413
+ type: "object",
21414
+ properties: {
21415
+ functionName: { type: "string" },
21416
+ name: { type: "string" },
21417
+ functionVersion: { type: "string" },
21418
+ description: { type: "string" },
21419
+ routingConfig: { type: "object" }
21420
+ },
21421
+ required: ["functionName", "name", "functionVersion"]
21422
+ },
21423
+ request: {
21424
+ method: "POST",
21425
+ path: "/2015-03-31/functions/{functionName}/aliases",
21426
+ body: {
21427
+ Name: "{name}",
21428
+ FunctionVersion: "{functionVersion}",
21429
+ Description: "{description}",
21430
+ RoutingConfig: "{routingConfig}"
21431
+ }
21432
+ },
21433
+ cas: "native-idempotency",
21434
+ externalEffect: true
21435
+ },
21436
+ {
21437
+ name: "aliases.update",
21438
+ class: "mutation",
21439
+ description: "Move or reconfigure an existing function alias.",
21440
+ parameters: {
21441
+ type: "object",
21442
+ properties: {
21443
+ functionName: { type: "string" },
21444
+ name: { type: "string" },
21445
+ functionVersion: { type: "string" },
21446
+ description: { type: "string" },
21447
+ routingConfig: { type: "object" },
21448
+ revisionId: { type: "string" }
21449
+ },
21450
+ required: ["functionName", "name"]
21451
+ },
21452
+ request: {
21453
+ method: "PUT",
21454
+ path: "/2015-03-31/functions/{functionName}/aliases/{name}",
21455
+ body: {
21456
+ FunctionVersion: "{functionVersion}",
21457
+ Description: "{description}",
21458
+ RoutingConfig: "{routingConfig}",
21459
+ RevisionId: "{revisionId}"
21460
+ }
21461
+ },
21462
+ cas: "optimistic-read-verify",
21463
+ externalEffect: true
21464
+ },
21465
+ {
21466
+ name: "aliases.delete",
21467
+ class: "mutation",
21468
+ description: "Delete a function alias without deleting the function version.",
21469
+ parameters: {
21470
+ type: "object",
21471
+ properties: {
21472
+ functionName: { type: "string" },
21473
+ name: { type: "string" }
21474
+ },
21475
+ required: ["functionName", "name"]
21476
+ },
21477
+ request: {
21478
+ method: "DELETE",
21479
+ path: "/2015-03-31/functions/{functionName}/aliases/{name}"
21480
+ },
21481
+ cas: "native-idempotency",
21482
+ externalEffect: true
21483
+ },
21484
+ {
21485
+ name: "functions.delete",
21486
+ class: "mutation",
21487
+ description: "Permanently delete a Lambda function or one published version.",
21488
+ parameters: {
21489
+ type: "object",
21490
+ properties: {
21491
+ functionName: { type: "string" },
21492
+ qualifier: { type: "string", description: "Version to delete. Omit to delete all versions." }
21493
+ },
21494
+ required: ["functionName"]
21495
+ },
21496
+ request: {
21497
+ method: "DELETE",
21498
+ path: "/2015-03-31/functions/{functionName}",
21499
+ query: { Qualifier: "{qualifier}" }
21500
+ },
21501
+ cas: "native-idempotency",
21502
+ externalEffect: true
21503
+ }
21504
+ ]
21505
+ });
21506
+
20445
21507
  // src/connectors/adapters/amazon-s3.ts
20446
21508
  var amazonS3Connector = declarativeRestConnector({
20447
21509
  kind: "amazon-s3",
@@ -23995,9 +25057,9 @@ function requiredString4(value, field) {
23995
25057
  }
23996
25058
  function isoDate(value, field) {
23997
25059
  const parsed = requiredString4(value, field);
23998
- const date = new Date(parsed);
23999
- if (!Number.isFinite(date.getTime())) throw new Error(`${field} must be an ISO 8601 timestamp`);
24000
- return date.toISOString();
25060
+ const date2 = new Date(parsed);
25061
+ if (!Number.isFinite(date2.getTime())) throw new Error(`${field} must be an ISO 8601 timestamp`);
25062
+ return date2.toISOString();
24001
25063
  }
24002
25064
  function requiredJsonValue(value, field) {
24003
25065
  if (value === void 0) throw new Error(`${field} is required`);
@@ -24015,8 +25077,8 @@ function retryAfterMs3(value) {
24015
25077
  if (!value) return 6e4;
24016
25078
  const seconds = Number(value);
24017
25079
  if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
24018
- const date = Date.parse(value);
24019
- return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
25080
+ const date2 = Date.parse(value);
25081
+ return Number.isFinite(date2) ? Math.max(0, date2 - Date.now()) : 6e4;
24020
25082
  }
24021
25083
  function isRecord(value) {
24022
25084
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -24573,8 +25635,8 @@ function retryAfterMs4(value) {
24573
25635
  if (!value) return 6e4;
24574
25636
  const seconds = Number(value);
24575
25637
  if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
24576
- const date = Date.parse(value);
24577
- return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
25638
+ const date2 = Date.parse(value);
25639
+ return Number.isFinite(date2) ? Math.max(0, date2 - Date.now()) : 6e4;
24578
25640
  }
24579
25641
  function redactProviderText(value) {
24580
25642
  return value.replace(/SharedAccessSignature\s+[^\s<]+/gi, "SharedAccessSignature [redacted]").replace(/SharedAccessKey=[^;\s<]+/gi, "SharedAccessKey=[redacted]");
@@ -26300,10 +27362,190 @@ var billplzConnector = declarativeRestConnector({
26300
27362
  ]
26301
27363
  });
26302
27364
 
27365
+ // src/connectors/oauth.ts
27366
+ import { createHash as createHash4, randomBytes } from "crypto";
27367
+ var PENDING_TTL_MS = 10 * 60 * 1e3;
27368
+ var InMemoryOAuthFlowStore = class {
27369
+ pendingFlows = /* @__PURE__ */ new Map();
27370
+ put(state, flow) {
27371
+ this.pendingFlows.set(state, flow);
27372
+ }
27373
+ consume(state) {
27374
+ const flow = this.pendingFlows.get(state);
27375
+ this.pendingFlows.delete(state);
27376
+ if (!flow || flow.expiresAt <= Date.now()) return void 0;
27377
+ return flow;
27378
+ }
27379
+ sweep(now) {
27380
+ for (const [k, v] of this.pendingFlows) {
27381
+ if (v.expiresAt <= now) this.pendingFlows.delete(k);
27382
+ }
27383
+ }
27384
+ clear() {
27385
+ this.pendingFlows.clear();
27386
+ }
27387
+ };
27388
+ var defaultFlowStore = new InMemoryOAuthFlowStore();
27389
+ function startOAuthFlow(input) {
27390
+ const store = input.store ?? defaultFlowStore;
27391
+ const now = input.now ?? Date.now();
27392
+ store.sweep?.(now);
27393
+ const usePkce = (input.pkce ?? "required") !== "unsupported";
27394
+ const codeVerifier = usePkce ? base64Url(randomBytes(48)) : void 0;
27395
+ const codeChallenge = codeVerifier ? base64Url(createHash4("sha256").update(codeVerifier).digest()) : void 0;
27396
+ const state = base64Url(randomBytes(24));
27397
+ store.put(state, {
27398
+ codeVerifier,
27399
+ state,
27400
+ projectId: input.projectId,
27401
+ kind: input.kind,
27402
+ label: input.label,
27403
+ redirectUri: input.redirectUri,
27404
+ expiresAt: now + PENDING_TTL_MS
27405
+ });
27406
+ const url = new URL(input.authorizationUrl);
27407
+ url.searchParams.set("response_type", "code");
27408
+ url.searchParams.set(
27409
+ oauthParameterName(input.authorizationClientIdParam, "client_id"),
27410
+ input.clientId
27411
+ );
27412
+ url.searchParams.set("redirect_uri", input.redirectUri);
27413
+ url.searchParams.set("scope", input.scopes.join(input.scopeSeparator ?? " "));
27414
+ url.searchParams.set("state", state);
27415
+ if (input.extraAuthParams) {
27416
+ for (const [k, v] of Object.entries(input.extraAuthParams)) {
27417
+ url.searchParams.set(k, v);
27418
+ }
27419
+ }
27420
+ if (codeChallenge) {
27421
+ url.searchParams.set("code_challenge", codeChallenge);
27422
+ url.searchParams.set("code_challenge_method", "S256");
27423
+ } else {
27424
+ url.searchParams.delete("code_challenge");
27425
+ url.searchParams.delete("code_challenge_method");
27426
+ }
27427
+ return { authorizationUrl: url.toString(), state };
27428
+ }
27429
+ async function consumePendingFlow(state, store = defaultFlowStore) {
27430
+ await store.sweep?.(Date.now());
27431
+ const flow = await store.consume(state);
27432
+ if (!flow) {
27433
+ throw new Error("Unknown or expired OAuth state: possible CSRF, replay, or stale flow");
27434
+ }
27435
+ return flow;
27436
+ }
27437
+ async function exchangeAuthorizationCode(input) {
27438
+ const usePkce = (input.pkce ?? "required") !== "unsupported";
27439
+ if (usePkce && !input.codeVerifier) {
27440
+ throw new Error("OAuth token exchange requires a PKCE code_verifier");
27441
+ }
27442
+ const body = new URLSearchParams({
27443
+ grant_type: "authorization_code",
27444
+ code: input.code,
27445
+ redirect_uri: input.redirectUri
27446
+ });
27447
+ if (usePkce) body.set("code_verifier", input.codeVerifier);
27448
+ const headers = {
27449
+ "content-type": "application/x-www-form-urlencoded",
27450
+ accept: "application/json"
27451
+ };
27452
+ applyTokenClientAuthentication(input, body, headers);
27453
+ const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
27454
+ method: "POST",
27455
+ headers,
27456
+ body,
27457
+ signal: input.signal
27458
+ });
27459
+ if (!res.ok) {
27460
+ const text = await res.text().catch(() => "");
27461
+ throw new Error(`OAuth token exchange failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
27462
+ }
27463
+ const json = await res.json();
27464
+ return {
27465
+ accessToken: json.access_token,
27466
+ refreshToken: json.refresh_token,
27467
+ expiresIn: json.expires_in,
27468
+ scope: json.scope,
27469
+ tokenType: json.token_type,
27470
+ idToken: json.id_token
27471
+ };
27472
+ }
27473
+ async function refreshAccessToken(input) {
27474
+ const body = new URLSearchParams({
27475
+ grant_type: "refresh_token",
27476
+ refresh_token: input.refreshToken
27477
+ });
27478
+ const headers = {
27479
+ "content-type": "application/x-www-form-urlencoded",
27480
+ accept: "application/json"
27481
+ };
27482
+ applyTokenClientAuthentication(input, body, headers);
27483
+ const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
27484
+ method: "POST",
27485
+ headers,
27486
+ body,
27487
+ signal: input.signal
27488
+ });
27489
+ if (!res.ok) {
27490
+ const text = await res.text().catch(() => "");
27491
+ throw new Error(`OAuth refresh failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
27492
+ }
27493
+ const json = await res.json();
27494
+ return {
27495
+ accessToken: json.access_token,
27496
+ // Some providers omit refresh_token on refresh — keep the previous one
27497
+ // in that case (caller passes through if undefined).
27498
+ refreshToken: json.refresh_token,
27499
+ expiresIn: json.expires_in,
27500
+ scope: json.scope,
27501
+ tokenType: json.token_type,
27502
+ idToken: json.id_token
27503
+ };
27504
+ }
27505
+ function applyTokenClientAuthentication(input, body, headers) {
27506
+ const method = input.tokenClientAuthMethod ?? "client_secret_post";
27507
+ if (method === "none") {
27508
+ body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
27509
+ return;
27510
+ }
27511
+ if (!input.clientSecret) {
27512
+ throw new Error(`OAuth ${method} client authentication requires a client secret`);
27513
+ }
27514
+ if (method === "client_secret_post") {
27515
+ body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
27516
+ body.set(
27517
+ oauthParameterName(input.tokenClientSecretParam, "client_secret"),
27518
+ input.clientSecret
27519
+ );
27520
+ return;
27521
+ }
27522
+ if (method === "client_secret_basic") {
27523
+ headers.authorization = `Basic ${Buffer.from(
27524
+ `${input.clientId}:${input.clientSecret}`,
27525
+ "utf8"
27526
+ ).toString("base64")}`;
27527
+ return;
27528
+ }
27529
+ throw new Error("Unsupported OAuth token client authentication method");
27530
+ }
27531
+ function base64Url(buf) {
27532
+ return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
27533
+ }
27534
+ function oauthParameterName(value, fallback) {
27535
+ const name = value ?? fallback;
27536
+ if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(name)) {
27537
+ throw new Error("Invalid OAuth parameter name");
27538
+ }
27539
+ return name;
27540
+ }
27541
+ function _resetPendingFlowsForTests() {
27542
+ defaultFlowStore.clear?.();
27543
+ }
27544
+
26303
27545
  // src/connectors/adapters/cal-com.ts
26304
27546
  var authorizeUrl = "https://app.cal.com/auth/oauth2/authorize";
26305
27547
  var tokenUrl = "https://api.cal.com/v2/auth/oauth2/token";
26306
- var calComConnector = declarativeRestConnector({
27548
+ var calComSpec = {
26307
27549
  kind: "cal-com",
26308
27550
  displayName: "Cal.com",
26309
27551
  description: "Schedule, query, and cancel Cal.com bookings and read event types through the Platform v2 API.",
@@ -26320,8 +27562,9 @@ var calComConnector = declarativeRestConnector({
26320
27562
  "SCHEDULE_READ",
26321
27563
  "SCHEDULE_WRITE"
26322
27564
  ],
26323
- clientIdEnv: "CALCOM_OAUTH_CLIENT_ID",
26324
- clientSecretEnv: "CALCOM_OAUTH_CLIENT_SECRET"
27565
+ pkce: "required",
27566
+ tokenClientAuthMethod: "none",
27567
+ clientIdEnv: "CALCOM_OAUTH_CLIENT_ID"
26325
27568
  },
26326
27569
  category: "calendar",
26327
27570
  defaultConsistencyModel: "authoritative",
@@ -26642,7 +27885,100 @@ var calComConnector = declarativeRestConnector({
26642
27885
  requiredScopes: ["EVENT_TYPE_READ"]
26643
27886
  }
26644
27887
  ]
26645
- });
27888
+ };
27889
+ var calComConnector = declarativeRestConnector(calComSpec);
27890
+ function calCom(options) {
27891
+ const adapter = declarativeRestConnector(calComSpec);
27892
+ const now = options.now ?? Date.now;
27893
+ const refreshes = /* @__PURE__ */ new Map();
27894
+ adapter.exchangeOAuth = async (input) => {
27895
+ const tokens = await exchangeAuthorizationCode({
27896
+ tokenUrl,
27897
+ clientId: options.clientId,
27898
+ tokenClientAuthMethod: "none",
27899
+ code: input.code,
27900
+ codeVerifier: input.codeVerifier,
27901
+ redirectUri: input.redirectUri,
27902
+ fetchImpl: options.fetchImpl
27903
+ });
27904
+ return {
27905
+ credentials: {
27906
+ kind: "oauth2",
27907
+ accessToken: tokens.accessToken,
27908
+ refreshToken: tokens.refreshToken,
27909
+ expiresAt: tokens.expiresIn ? now() + tokens.expiresIn * 1e3 : void 0
27910
+ },
27911
+ scopes: tokens.scope?.split(/[\s,]+/).filter(Boolean) ?? calComSpec.auth.scopes,
27912
+ metadata: {}
27913
+ };
27914
+ };
27915
+ adapter.refreshToken = async (credentials) => {
27916
+ if (credentials.kind !== "oauth2" || !credentials.refreshToken) {
27917
+ throw new Error("cal-com.refreshToken: missing refresh token");
27918
+ }
27919
+ const refreshed = await refreshAccessToken({
27920
+ tokenUrl,
27921
+ clientId: options.clientId,
27922
+ tokenClientAuthMethod: "none",
27923
+ refreshToken: credentials.refreshToken,
27924
+ fetchImpl: options.fetchImpl
27925
+ });
27926
+ return {
27927
+ kind: "oauth2",
27928
+ accessToken: refreshed.accessToken,
27929
+ refreshToken: refreshed.refreshToken ?? credentials.refreshToken,
27930
+ expiresAt: refreshed.expiresIn ? now() + refreshed.expiresIn * 1e3 : void 0
27931
+ };
27932
+ };
27933
+ const executeRead2 = adapter.executeRead?.bind(adapter);
27934
+ const executeMutation = adapter.executeMutation?.bind(adapter);
27935
+ if (executeRead2) {
27936
+ adapter.executeRead = async (invocation) => executeRead2(
27937
+ await withFreshCalComCredentials(invocation, adapter, refreshes, now)
27938
+ );
27939
+ }
27940
+ if (executeMutation) {
27941
+ adapter.executeMutation = async (invocation) => executeMutation(
27942
+ await withFreshCalComCredentials(invocation, adapter, refreshes, now)
27943
+ );
27944
+ }
27945
+ return adapter;
27946
+ }
27947
+ async function withFreshCalComCredentials(invocation, adapter, refreshes, now) {
27948
+ const credentials = invocation.source.credentials;
27949
+ if (credentials.kind !== "oauth2") {
27950
+ throw new CredentialsExpired("Cal.com requires OAuth2 credentials.", invocation.source.id);
27951
+ }
27952
+ if (!credentials.expiresAt || credentials.expiresAt > now() + 6e4) {
27953
+ return invocation;
27954
+ }
27955
+ if (!credentials.refreshToken || !adapter.refreshToken) {
27956
+ throw new CredentialsExpired(
27957
+ "Cal.com access token expired and no refresh token is available.",
27958
+ invocation.source.id
27959
+ );
27960
+ }
27961
+ let refresh = refreshes.get(invocation.source.id);
27962
+ if (!refresh) {
27963
+ refresh = adapter.refreshToken(credentials);
27964
+ refreshes.set(invocation.source.id, refresh);
27965
+ const clear = () => {
27966
+ if (refreshes.get(invocation.source.id) === refresh) {
27967
+ refreshes.delete(invocation.source.id);
27968
+ }
27969
+ };
27970
+ void refresh.then(clear, clear);
27971
+ }
27972
+ const rotated = await refresh;
27973
+ await invocation.onCredentialsRotated?.(rotated);
27974
+ return {
27975
+ ...invocation,
27976
+ source: {
27977
+ ...invocation.source,
27978
+ credentials: rotated
27979
+ }
27980
+ };
27981
+ }
26646
27982
 
26647
27983
  // src/connectors/adapters/calendly.ts
26648
27984
  var calendlyConnector = declarativeRestConnector({
@@ -27840,6 +29176,273 @@ var clickupConnector = declarativeRestConnector({
27840
29176
  ]
27841
29177
  });
27842
29178
 
29179
+ // src/connectors/adapters/cloudflare.ts
29180
+ var pagination = {
29181
+ page: { type: "integer", minimum: 1 },
29182
+ perPage: { type: "integer", minimum: 5, maximum: 50 }
29183
+ };
29184
+ var paginationQuery = { page: "{page}", per_page: "{perPage}" };
29185
+ var zoneId = {
29186
+ zoneId: { type: "string", minLength: 1, description: "Cloudflare zone identifier." }
29187
+ };
29188
+ var recordId = {
29189
+ recordId: { type: "string", minLength: 1, description: "Cloudflare DNS record identifier." }
29190
+ };
29191
+ var recordFields = {
29192
+ type: {
29193
+ type: "string",
29194
+ enum: [
29195
+ "A",
29196
+ "AAAA",
29197
+ "CAA",
29198
+ "CERT",
29199
+ "CNAME",
29200
+ "DNSKEY",
29201
+ "DS",
29202
+ "HTTPS",
29203
+ "LOC",
29204
+ "MX",
29205
+ "NAPTR",
29206
+ "NS",
29207
+ "OPENPGPKEY",
29208
+ "PTR",
29209
+ "SMIMEA",
29210
+ "SRV",
29211
+ "SSHFP",
29212
+ "SVCB",
29213
+ "TLSA",
29214
+ "TXT",
29215
+ "URI"
29216
+ ]
29217
+ },
29218
+ name: { type: "string", minLength: 1, description: "Complete DNS record name." },
29219
+ content: { type: "string", description: "Provider-native record content." },
29220
+ ttl: {
29221
+ type: "integer",
29222
+ minimum: 1,
29223
+ maximum: 86400,
29224
+ description: "TTL in seconds. Use 1 for automatic."
29225
+ },
29226
+ proxied: { type: "boolean" },
29227
+ priority: { type: "integer" },
29228
+ comment: { type: ["string", "null"] },
29229
+ tags: { type: "array", items: { type: "string" } },
29230
+ data: { type: "object", description: "Provider-native structured data for records such as SRV or CAA." },
29231
+ settings: { type: "object", description: "Provider-native DNS record settings." }
29232
+ };
29233
+ var cloudflareConnector = declarativeRestConnector({
29234
+ kind: "cloudflare",
29235
+ displayName: "Cloudflare",
29236
+ description: "Inspect Cloudflare accounts and zones, then manage DNS records with a dedicated scoped API token.",
29237
+ auth: {
29238
+ kind: "api-key",
29239
+ hint: "Create a dedicated Cloudflare API token for Tangle Integration Hub. Grant Account Settings Read, Zone Read, Zone Settings Read, and DNS Read or DNS Edit only on selected resources. Never reuse a Tangle deployment, Workers, Terraform, or infrastructure token."
29240
+ },
29241
+ category: "other",
29242
+ defaultConsistencyModel: "authoritative",
29243
+ baseUrl: "https://api.cloudflare.com/client/v4",
29244
+ credentialPlacement: { kind: "bearer" },
29245
+ test: {
29246
+ method: "GET",
29247
+ path: "/user/tokens/verify",
29248
+ expectResponse: [
29249
+ { path: "success", equals: true },
29250
+ { path: "result.status", equals: "active" }
29251
+ ]
29252
+ },
29253
+ capabilities: [
29254
+ {
29255
+ name: "auth.verify",
29256
+ class: "read",
29257
+ description: "Verify that the current API token is valid and active.",
29258
+ parameters: { type: "object", properties: {} },
29259
+ request: { method: "GET", path: "/user/tokens/verify" }
29260
+ },
29261
+ {
29262
+ name: "accounts.get",
29263
+ class: "read",
29264
+ description: "Read one Cloudflare account and its settings.",
29265
+ parameters: {
29266
+ type: "object",
29267
+ properties: { accountId: { type: "string", minLength: 1 } },
29268
+ required: ["accountId"]
29269
+ },
29270
+ request: { method: "GET", path: "/accounts/{accountId}" }
29271
+ },
29272
+ {
29273
+ name: "zones.list",
29274
+ class: "read",
29275
+ description: "List or filter zones by account, domain, status, and type.",
29276
+ parameters: {
29277
+ type: "object",
29278
+ properties: {
29279
+ ...pagination,
29280
+ accountId: { type: "string" },
29281
+ name: { type: "string" },
29282
+ status: { type: "string", enum: ["initializing", "pending", "active", "moved"] },
29283
+ type: { type: "string", description: "Comma-separated zone types." },
29284
+ match: { type: "string", enum: ["any", "all"] },
29285
+ order: { type: "string", enum: ["name", "status", "account.id", "account.name", "plan.id"] },
29286
+ direction: { type: "string", enum: ["asc", "desc"] }
29287
+ }
29288
+ },
29289
+ request: {
29290
+ method: "GET",
29291
+ path: "/zones",
29292
+ query: {
29293
+ ...paginationQuery,
29294
+ "account.id": "{accountId}",
29295
+ name: "{name}",
29296
+ status: "{status}",
29297
+ type: "{type}",
29298
+ match: "{match}",
29299
+ order: "{order}",
29300
+ direction: "{direction}"
29301
+ }
29302
+ }
29303
+ },
29304
+ {
29305
+ name: "zones.get",
29306
+ class: "read",
29307
+ description: "Read one zone with status, nameservers, plan, and ownership metadata.",
29308
+ parameters: { type: "object", properties: zoneId, required: ["zoneId"] },
29309
+ request: { method: "GET", path: "/zones/{zoneId}" }
29310
+ },
29311
+ {
29312
+ name: "zones.settings.list",
29313
+ class: "read",
29314
+ description: "List all settings for one zone.",
29315
+ parameters: { type: "object", properties: zoneId, required: ["zoneId"] },
29316
+ request: { method: "GET", path: "/zones/{zoneId}/settings" }
29317
+ },
29318
+ {
29319
+ name: "zones.settings.get",
29320
+ class: "read",
29321
+ description: "Read one setting for a zone.",
29322
+ parameters: {
29323
+ type: "object",
29324
+ properties: {
29325
+ ...zoneId,
29326
+ settingId: { type: "string", minLength: 1 }
29327
+ },
29328
+ required: ["zoneId", "settingId"]
29329
+ },
29330
+ request: { method: "GET", path: "/zones/{zoneId}/settings/{settingId}" }
29331
+ },
29332
+ {
29333
+ name: "dns.records.list",
29334
+ class: "read",
29335
+ description: "List and filter DNS records in one zone.",
29336
+ parameters: {
29337
+ type: "object",
29338
+ properties: {
29339
+ ...zoneId,
29340
+ ...pagination,
29341
+ type: { type: "string" },
29342
+ name: { type: "string", description: "Exact record name." },
29343
+ content: { type: "string", description: "Exact record content." },
29344
+ proxied: { type: "boolean" },
29345
+ match: { type: "string", enum: ["any", "all"] },
29346
+ order: { type: "string", enum: ["type", "name", "content", "ttl", "proxied"] },
29347
+ direction: { type: "string", enum: ["asc", "desc"] }
29348
+ },
29349
+ required: ["zoneId"]
29350
+ },
29351
+ request: {
29352
+ method: "GET",
29353
+ path: "/zones/{zoneId}/dns_records",
29354
+ query: {
29355
+ ...paginationQuery,
29356
+ type: "{type}",
29357
+ "name.exact": "{name}",
29358
+ "content.exact": "{content}",
29359
+ proxied: "{proxied}",
29360
+ match: "{match}",
29361
+ order: "{order}",
29362
+ direction: "{direction}"
29363
+ }
29364
+ }
29365
+ },
29366
+ {
29367
+ name: "dns.records.get",
29368
+ class: "read",
29369
+ description: "Read one DNS record by zone and record ID.",
29370
+ parameters: {
29371
+ type: "object",
29372
+ properties: { ...zoneId, ...recordId },
29373
+ required: ["zoneId", "recordId"]
29374
+ },
29375
+ request: { method: "GET", path: "/zones/{zoneId}/dns_records/{recordId}" }
29376
+ },
29377
+ {
29378
+ name: "dns.records.export",
29379
+ class: "read",
29380
+ description: "Export the current zone records as a BIND zone file before a change.",
29381
+ parameters: { type: "object", properties: zoneId, required: ["zoneId"] },
29382
+ request: { method: "GET", path: "/zones/{zoneId}/dns_records/export" }
29383
+ },
29384
+ {
29385
+ name: "dns.records.create",
29386
+ class: "mutation",
29387
+ description: "Create one DNS record in a selected zone.",
29388
+ parameters: {
29389
+ type: "object",
29390
+ properties: {
29391
+ ...zoneId,
29392
+ record: {
29393
+ type: "object",
29394
+ properties: recordFields,
29395
+ required: ["type", "name"],
29396
+ additionalProperties: false
29397
+ }
29398
+ },
29399
+ required: ["zoneId", "record"]
29400
+ },
29401
+ request: { method: "POST", path: "/zones/{zoneId}/dns_records", body: "{record}" },
29402
+ cas: "none",
29403
+ externalEffect: true
29404
+ },
29405
+ {
29406
+ name: "dns.records.update",
29407
+ class: "mutation",
29408
+ description: "Partially update one DNS record.",
29409
+ parameters: {
29410
+ type: "object",
29411
+ properties: {
29412
+ ...zoneId,
29413
+ ...recordId,
29414
+ changes: {
29415
+ type: "object",
29416
+ properties: recordFields,
29417
+ additionalProperties: false
29418
+ }
29419
+ },
29420
+ required: ["zoneId", "recordId", "changes"]
29421
+ },
29422
+ request: {
29423
+ method: "PATCH",
29424
+ path: "/zones/{zoneId}/dns_records/{recordId}",
29425
+ body: "{changes}"
29426
+ },
29427
+ cas: "optimistic-read-verify",
29428
+ externalEffect: true
29429
+ },
29430
+ {
29431
+ name: "dns.records.delete",
29432
+ class: "mutation",
29433
+ description: "Permanently delete one DNS record.",
29434
+ parameters: {
29435
+ type: "object",
29436
+ properties: { ...zoneId, ...recordId },
29437
+ required: ["zoneId", "recordId"]
29438
+ },
29439
+ request: { method: "DELETE", path: "/zones/{zoneId}/dns_records/{recordId}" },
29440
+ cas: "optimistic-read-verify",
29441
+ externalEffect: true
29442
+ }
29443
+ ]
29444
+ });
29445
+
27843
29446
  // src/connectors/adapters/cloudinary.ts
27844
29447
  var cloudinaryConnector = declarativeRestConnector({
27845
29448
  kind: "cloudinary",
@@ -36164,134 +37767,6 @@ var frontConnector = declarativeRestConnector({
36164
37767
  ]
36165
37768
  });
36166
37769
 
36167
- // src/connectors/oauth.ts
36168
- import { createHash as createHash4, randomBytes } from "crypto";
36169
- var PENDING_TTL_MS = 10 * 60 * 1e3;
36170
- var InMemoryOAuthFlowStore = class {
36171
- pendingFlows = /* @__PURE__ */ new Map();
36172
- put(state, flow) {
36173
- this.pendingFlows.set(state, flow);
36174
- }
36175
- consume(state) {
36176
- const flow = this.pendingFlows.get(state);
36177
- this.pendingFlows.delete(state);
36178
- if (!flow || flow.expiresAt <= Date.now()) return void 0;
36179
- return flow;
36180
- }
36181
- sweep(now) {
36182
- for (const [k, v] of this.pendingFlows) {
36183
- if (v.expiresAt <= now) this.pendingFlows.delete(k);
36184
- }
36185
- }
36186
- clear() {
36187
- this.pendingFlows.clear();
36188
- }
36189
- };
36190
- var defaultFlowStore = new InMemoryOAuthFlowStore();
36191
- function startOAuthFlow(input) {
36192
- const store = input.store ?? defaultFlowStore;
36193
- const now = input.now ?? Date.now();
36194
- store.sweep?.(now);
36195
- const codeVerifier = base64Url(randomBytes(48));
36196
- const codeChallenge = base64Url(createHash4("sha256").update(codeVerifier).digest());
36197
- const state = base64Url(randomBytes(24));
36198
- store.put(state, {
36199
- codeVerifier,
36200
- state,
36201
- projectId: input.projectId,
36202
- kind: input.kind,
36203
- label: input.label,
36204
- redirectUri: input.redirectUri,
36205
- expiresAt: now + PENDING_TTL_MS
36206
- });
36207
- const url = new URL(input.authorizationUrl);
36208
- url.searchParams.set("response_type", "code");
36209
- url.searchParams.set("client_id", input.clientId);
36210
- url.searchParams.set("redirect_uri", input.redirectUri);
36211
- url.searchParams.set("scope", input.scopes.join(input.scopeSeparator ?? " "));
36212
- url.searchParams.set("state", state);
36213
- url.searchParams.set("code_challenge", codeChallenge);
36214
- url.searchParams.set("code_challenge_method", "S256");
36215
- if (input.extraAuthParams) {
36216
- for (const [k, v] of Object.entries(input.extraAuthParams)) {
36217
- url.searchParams.set(k, v);
36218
- }
36219
- }
36220
- return { authorizationUrl: url.toString(), state };
36221
- }
36222
- async function consumePendingFlow(state, store = defaultFlowStore) {
36223
- await store.sweep?.(Date.now());
36224
- const flow = await store.consume(state);
36225
- if (!flow) {
36226
- throw new Error("Unknown or expired OAuth state: possible CSRF, replay, or stale flow");
36227
- }
36228
- return flow;
36229
- }
36230
- async function exchangeAuthorizationCode(input) {
36231
- const body = new URLSearchParams({
36232
- grant_type: "authorization_code",
36233
- client_id: input.clientId,
36234
- client_secret: input.clientSecret,
36235
- code: input.code,
36236
- redirect_uri: input.redirectUri,
36237
- code_verifier: input.codeVerifier
36238
- });
36239
- const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
36240
- method: "POST",
36241
- headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
36242
- body,
36243
- signal: input.signal
36244
- });
36245
- if (!res.ok) {
36246
- const text = await res.text().catch(() => "");
36247
- throw new Error(`OAuth token exchange failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
36248
- }
36249
- const json = await res.json();
36250
- return {
36251
- accessToken: json.access_token,
36252
- refreshToken: json.refresh_token,
36253
- expiresIn: json.expires_in,
36254
- scope: json.scope,
36255
- tokenType: json.token_type,
36256
- idToken: json.id_token
36257
- };
36258
- }
36259
- async function refreshAccessToken(input) {
36260
- const body = new URLSearchParams({
36261
- grant_type: "refresh_token",
36262
- client_id: input.clientId,
36263
- client_secret: input.clientSecret,
36264
- refresh_token: input.refreshToken
36265
- });
36266
- const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
36267
- method: "POST",
36268
- headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
36269
- body,
36270
- signal: input.signal
36271
- });
36272
- if (!res.ok) {
36273
- const text = await res.text().catch(() => "");
36274
- throw new Error(`OAuth refresh failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
36275
- }
36276
- const json = await res.json();
36277
- return {
36278
- accessToken: json.access_token,
36279
- // Some providers omit refresh_token on refresh — keep the previous one
36280
- // in that case (caller passes through if undefined).
36281
- refreshToken: json.refresh_token,
36282
- expiresIn: json.expires_in,
36283
- scope: json.scope,
36284
- tokenType: json.token_type,
36285
- idToken: json.id_token
36286
- };
36287
- }
36288
- function base64Url(buf) {
36289
- return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
36290
- }
36291
- function _resetPendingFlowsForTests() {
36292
- defaultFlowStore.clear?.();
36293
- }
36294
-
36295
37770
  // src/connectors/adapters/google-errors.ts
36296
37771
  var AUTH_REASONS = /* @__PURE__ */ new Set([
36297
37772
  "autherror",
@@ -38527,13 +40002,13 @@ var googlePubSubConnector = {
38527
40002
  let data4;
38528
40003
  switch (inv.capabilityName) {
38529
40004
  case "topics.list":
38530
- data4 = await pubSubRequest(credentials, inv, "GET", projectPath(credentials, "topics"), pagination(inv.args));
40005
+ data4 = await pubSubRequest(credentials, inv, "GET", projectPath(credentials, "topics"), pagination2(inv.args));
38531
40006
  break;
38532
40007
  case "topics.get":
38533
40008
  data4 = await pubSubRequest(credentials, inv, "GET", topicPath(credentials, inv.args.topic));
38534
40009
  break;
38535
40010
  case "subscriptions.list":
38536
- data4 = await pubSubRequest(credentials, inv, "GET", projectPath(credentials, "subscriptions"), pagination(inv.args));
40011
+ data4 = await pubSubRequest(credentials, inv, "GET", projectPath(credentials, "subscriptions"), pagination2(inv.args));
38537
40012
  break;
38538
40013
  case "subscriptions.get":
38539
40014
  data4 = await pubSubRequest(credentials, inv, "GET", subscriptionPath(credentials, inv.args.subscription));
@@ -38817,7 +40292,7 @@ function resourceId(value, field) {
38817
40292
  }
38818
40293
  return id2;
38819
40294
  }
38820
- function pagination(args) {
40295
+ function pagination2(args) {
38821
40296
  const query2 = new URLSearchParams();
38822
40297
  if (args.pageSize !== void 0) query2.set("pageSize", String(boundedInteger2(args.pageSize, "pageSize", 1, 1e3)));
38823
40298
  if (args.pageToken !== void 0) query2.set("pageToken", requiredString6(args.pageToken, "pageToken"));
@@ -38969,8 +40444,8 @@ function retryAfterMs5(value) {
38969
40444
  if (!value) return 6e4;
38970
40445
  const seconds = Number(value);
38971
40446
  if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
38972
- const date = Date.parse(value);
38973
- return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 6e4;
40447
+ const date2 = Date.parse(value);
40448
+ return Number.isFinite(date2) ? Math.max(0, date2 - Date.now()) : 6e4;
38974
40449
  }
38975
40450
  function isRecord3(value) {
38976
40451
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -41903,25 +43378,25 @@ async function updateRow(inv, accessToken4, timeoutMs) {
41903
43378
  const meta = readSheetMeta(inv.source.metadata);
41904
43379
  const { rowKey, patch, expectedFingerprint } = inv.args;
41905
43380
  const rows = await fetchAllRows(accessToken4, meta);
41906
- const target = rows.find((r) => normalizeKey(r.values[meta.keyColumn]) === normalizeKey(rowKey));
41907
- if (!target) {
43381
+ const target2 = rows.find((r) => normalizeKey(r.values[meta.keyColumn]) === normalizeKey(rowKey));
43382
+ if (!target2) {
41908
43383
  throw new ResourceContention(
41909
43384
  `row with key "${rowKey}" not found`,
41910
43385
  [],
41911
43386
  { availableRows: rows.length }
41912
43387
  );
41913
43388
  }
41914
- if (expectedFingerprint && expectedFingerprint !== target.fingerprint) {
43389
+ if (expectedFingerprint && expectedFingerprint !== target2.fingerprint) {
41915
43390
  throw new ResourceContention(
41916
43391
  `row "${rowKey}" was modified since the agent last read it; re-read and try again`,
41917
43392
  [],
41918
- { current: target.values, currentFingerprint: target.fingerprint }
43393
+ { current: target2.values, currentFingerprint: target2.fingerprint }
41919
43394
  );
41920
43395
  }
41921
43396
  const updatedValues = meta.headers.map(
41922
- (h) => h in patch ? String(patch[h]) : target.values[h] ?? ""
43397
+ (h) => h in patch ? String(patch[h]) : target2.values[h] ?? ""
41923
43398
  );
41924
- const range = `${meta.sheetName}!A${target.rowIndex + 1}:${columnIndexToLetter(meta.headers.length - 1)}${target.rowIndex + 1}`;
43399
+ const range = `${meta.sheetName}!A${target2.rowIndex + 1}:${columnIndexToLetter(meta.headers.length - 1)}${target2.rowIndex + 1}`;
41925
43400
  const url = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(meta.spreadsheetId)}/values/${encodeURIComponent(range)}?valueInputOption=USER_ENTERED`;
41926
43401
  const res = await fetch(url, {
41927
43402
  method: "PUT",
@@ -44534,9 +46009,9 @@ function parseRetryAfterMs(header2) {
44534
46009
  if (!header2) return 1e3;
44535
46010
  const seconds = Number(header2);
44536
46011
  if (Number.isFinite(seconds) && seconds >= 0) return Math.floor(seconds * 1e3);
44537
- const date = Date.parse(header2);
44538
- if (!Number.isFinite(date)) return 1e3;
44539
- return Math.max(0, date - Date.now());
46012
+ const date2 = Date.parse(header2);
46013
+ if (!Number.isFinite(date2)) return 1e3;
46014
+ return Math.max(0, date2 - Date.now());
44540
46015
  }
44541
46016
  function stringify2(value) {
44542
46017
  if (typeof value === "string") return value;
@@ -49683,7 +51158,7 @@ function microsoftCalendar(opts) {
49683
51158
  return adapter;
49684
51159
  }
49685
51160
  async function getScheduleBusy(input) {
49686
- const target = input.userPrincipal === "me" ? "me" : input.userPrincipal;
51161
+ const target2 = input.userPrincipal === "me" ? "me" : input.userPrincipal;
49687
51162
  const url = "https://graph.microsoft.com/v1.0/me/calendar/getSchedule";
49688
51163
  const res = await fetch(url, {
49689
51164
  method: "POST",
@@ -49692,7 +51167,7 @@ async function getScheduleBusy(input) {
49692
51167
  "content-type": "application/json"
49693
51168
  },
49694
51169
  body: JSON.stringify({
49695
- schedules: [target],
51170
+ schedules: [target2],
49696
51171
  startTime: { dateTime: input.timeMin, timeZone: "UTC" },
49697
51172
  endTime: { dateTime: input.timeMax, timeZone: "UTC" },
49698
51173
  availabilityViewInterval: 30
@@ -54684,6 +56159,9 @@ function notion(opts) {
54684
56159
  if (!clientId || !clientSecret) {
54685
56160
  throw new Error("Notion OAuth client not configured (NOTION_OAUTH_CLIENT_ID / _SECRET)");
54686
56161
  }
56162
+ if (!input.codeVerifier) {
56163
+ throw new Error("notion.exchangeOAuth: missing PKCE code verifier");
56164
+ }
54687
56165
  const body = new URLSearchParams({
54688
56166
  grant_type: "authorization_code",
54689
56167
  code: input.code,
@@ -61455,9 +62933,9 @@ function mutablePath(rootPath, value) {
61455
62933
  }
61456
62934
  async function canonicalizeExistingPath(client, configuredRoot, path) {
61457
62935
  const root = posix.normalize(await client.realPath(configuredRoot));
61458
- const target = posix.normalize(await client.realPath(path));
61459
- assertWithinCanonicalRoot(root, target);
61460
- return target;
62936
+ const target2 = posix.normalize(await client.realPath(path));
62937
+ assertWithinCanonicalRoot(root, target2);
62938
+ return target2;
61461
62939
  }
61462
62940
  async function canonicalizeDestinationPath(client, configuredRoot, path) {
61463
62941
  const root = posix.normalize(await client.realPath(configuredRoot));
@@ -61479,8 +62957,8 @@ async function canonicalizeDestinationPath(client, configuredRoot, path) {
61479
62957
  assertWithinCanonicalRoot(root, destination);
61480
62958
  return destination;
61481
62959
  }
61482
- function assertWithinCanonicalRoot(root, target) {
61483
- if (root !== "/" && target !== root && !target.startsWith(`${root}/`)) {
62960
+ function assertWithinCanonicalRoot(root, target2) {
62961
+ if (root !== "/" && target2 !== root && !target2.startsWith(`${root}/`)) {
61484
62962
  throw new Error("SFTP path resolves outside the configured root");
61485
62963
  }
61486
62964
  }
@@ -67939,6 +69417,9 @@ function twitter(opts) {
67939
69417
  if (!clientId || !clientSecret) {
67940
69418
  throw new Error("Twitter OAuth client not configured (TWITTER_OAUTH_CLIENT_ID / _SECRET)");
67941
69419
  }
69420
+ if (!input.codeVerifier) {
69421
+ throw new Error("twitter.exchangeOAuth: missing PKCE code verifier");
69422
+ }
67942
69423
  const tokens = await twitterTokenRequest(clientId, clientSecret, {
67943
69424
  grant_type: "authorization_code",
67944
69425
  code: input.code,
@@ -67999,6 +69480,733 @@ async function twitterTokenRequest(clientId, clientSecret, params) {
67999
69480
  };
68000
69481
  }
68001
69482
 
69483
+ // src/connectors/adapters/tiktok.ts
69484
+ var AUTHORIZATION_URL = "https://www.tiktok.com/v2/auth/authorize/";
69485
+ var TOKEN_URL20 = "https://open.tiktokapis.com/v2/oauth/token/";
69486
+ var API_BASE_URL = "https://open.tiktokapis.com";
69487
+ var SCOPES14 = ["user.info.basic", "video.list", "video.publish"];
69488
+ var VIDEO_FIELDS = [
69489
+ "id",
69490
+ "create_time",
69491
+ "cover_image_url",
69492
+ "share_url",
69493
+ "video_description",
69494
+ "duration",
69495
+ "height",
69496
+ "width",
69497
+ "title",
69498
+ "embed_link",
69499
+ "like_count",
69500
+ "comment_count",
69501
+ "share_count",
69502
+ "view_count"
69503
+ ].join(",");
69504
+ var PRIVACY_LEVELS = [
69505
+ "PUBLIC_TO_EVERYONE",
69506
+ "MUTUAL_FOLLOW_FRIENDS",
69507
+ "FOLLOWER_OF_CREATOR",
69508
+ "SELF_ONLY"
69509
+ ];
69510
+ var jsonPostHeaders = {
69511
+ "content-type": "application/json; charset=UTF-8"
69512
+ };
69513
+ var TIKTOK_SPEC = {
69514
+ kind: "tiktok",
69515
+ displayName: "TikTok",
69516
+ description: "Read the connected TikTok profile and videos, then publish approved videos or photo posts from verified HTTPS URLs.",
69517
+ auth: {
69518
+ kind: "oauth2",
69519
+ authorizationUrl: AUTHORIZATION_URL,
69520
+ tokenUrl: TOKEN_URL20,
69521
+ scopes: [...SCOPES14],
69522
+ scopeSeparator: ",",
69523
+ pkce: "unsupported",
69524
+ authorizationClientIdParam: "client_key",
69525
+ tokenClientIdParam: "client_key",
69526
+ tokenClientSecretParam: "client_secret",
69527
+ clientIdEnv: "TIKTOK_OAUTH_CLIENT_KEY",
69528
+ clientSecretEnv: "TIKTOK_OAUTH_CLIENT_SECRET",
69529
+ tokenMetadata: { openId: "open_id" }
69530
+ },
69531
+ category: "comms",
69532
+ defaultConsistencyModel: "advisory",
69533
+ baseUrl: API_BASE_URL,
69534
+ credentialsExpiredStatuses: [401],
69535
+ test: {
69536
+ method: "GET",
69537
+ path: "/v2/user/info/",
69538
+ query: { fields: "open_id,union_id,avatar_url,display_name" }
69539
+ },
69540
+ capabilities: [
69541
+ {
69542
+ name: "user.info",
69543
+ class: "read",
69544
+ description: "Read the connected TikTok account identity, display name, and avatar.",
69545
+ parameters: { type: "object", properties: {} },
69546
+ requiredScopes: ["user.info.basic"],
69547
+ request: {
69548
+ method: "GET",
69549
+ path: "/v2/user/info/",
69550
+ query: { fields: "open_id,union_id,avatar_url,display_name" }
69551
+ }
69552
+ },
69553
+ {
69554
+ name: "videos.list",
69555
+ class: "read",
69556
+ description: "List videos for the connected creator, including public URLs, dimensions, duration, and engagement counts.",
69557
+ parameters: {
69558
+ type: "object",
69559
+ properties: {
69560
+ cursor: {
69561
+ type: "integer",
69562
+ minimum: 0,
69563
+ description: "UTC millisecond cursor returned by the previous page."
69564
+ },
69565
+ max_count: {
69566
+ type: "integer",
69567
+ minimum: 1,
69568
+ maximum: 20,
69569
+ default: 10
69570
+ }
69571
+ }
69572
+ },
69573
+ requiredScopes: ["video.list"],
69574
+ request: {
69575
+ method: "POST",
69576
+ path: "/v2/video/list/",
69577
+ query: { fields: VIDEO_FIELDS },
69578
+ headers: jsonPostHeaders,
69579
+ body: { cursor: "{cursor}", max_count: "{max_count}" }
69580
+ }
69581
+ },
69582
+ {
69583
+ name: "videos.query",
69584
+ class: "read",
69585
+ description: "Read up to 20 TikTok videos by their exact video ids.",
69586
+ parameters: {
69587
+ type: "object",
69588
+ properties: {
69589
+ video_ids: {
69590
+ type: "array",
69591
+ minItems: 1,
69592
+ maxItems: 20,
69593
+ uniqueItems: true,
69594
+ items: { type: "string", minLength: 1 }
69595
+ }
69596
+ },
69597
+ required: ["video_ids"]
69598
+ },
69599
+ requiredScopes: ["video.list"],
69600
+ request: {
69601
+ method: "POST",
69602
+ path: "/v2/video/query/",
69603
+ query: { fields: VIDEO_FIELDS },
69604
+ headers: jsonPostHeaders,
69605
+ body: { filters: { video_ids: "{video_ids}" } }
69606
+ }
69607
+ },
69608
+ {
69609
+ name: "publishing.creatorInfo",
69610
+ class: "read",
69611
+ description: "Read the latest creator posting limits, privacy choices, and interaction settings before presenting a publish confirmation.",
69612
+ parameters: { type: "object", properties: {} },
69613
+ requiredScopes: ["video.publish"],
69614
+ request: {
69615
+ method: "POST",
69616
+ path: "/v2/post/publish/creator_info/query/",
69617
+ headers: jsonPostHeaders,
69618
+ body: {}
69619
+ }
69620
+ },
69621
+ {
69622
+ name: "publishing.status",
69623
+ class: "read",
69624
+ description: "Read processing, moderation, and publication status for one publish request.",
69625
+ parameters: {
69626
+ type: "object",
69627
+ properties: {
69628
+ publish_id: { type: "string", minLength: 1, maxLength: 64 }
69629
+ },
69630
+ required: ["publish_id"]
69631
+ },
69632
+ requiredScopes: ["video.publish"],
69633
+ request: {
69634
+ method: "POST",
69635
+ path: "/v2/post/publish/status/fetch/",
69636
+ headers: jsonPostHeaders,
69637
+ body: { publish_id: "{publish_id}" }
69638
+ }
69639
+ },
69640
+ {
69641
+ name: "publishing.videoFromUrl",
69642
+ class: "mutation",
69643
+ description: "Directly publish one approved video from an app-verified HTTPS URL. The adapter refreshes creator limits before it sends the post.",
69644
+ parameters: {
69645
+ type: "object",
69646
+ properties: {
69647
+ video_url: {
69648
+ type: "string",
69649
+ format: "uri",
69650
+ pattern: "^https://",
69651
+ description: "Public HTTPS URL covered by the domain or URL prefix verified in the TikTok app."
69652
+ },
69653
+ video_duration_sec: {
69654
+ type: "number",
69655
+ exclusiveMinimum: 0,
69656
+ description: "Measured video duration used to enforce the creator-specific limit."
69657
+ },
69658
+ privacy_level: { type: "string", enum: [...PRIVACY_LEVELS] },
69659
+ title: { type: "string", maxLength: 2200 },
69660
+ disable_duet: { type: "boolean" },
69661
+ disable_comment: { type: "boolean" },
69662
+ disable_stitch: { type: "boolean" },
69663
+ video_cover_timestamp_ms: { type: "integer", minimum: 0 },
69664
+ brand_content_toggle: {
69665
+ type: "boolean",
69666
+ description: "True for a paid partnership that promotes a third-party business."
69667
+ },
69668
+ brand_organic_toggle: {
69669
+ type: "boolean",
69670
+ description: "True when the post promotes the creator's own business."
69671
+ },
69672
+ is_aigc: {
69673
+ type: "boolean",
69674
+ description: "True when TikTok must label the video as AI-generated content."
69675
+ }
69676
+ },
69677
+ required: [
69678
+ "video_url",
69679
+ "video_duration_sec",
69680
+ "privacy_level",
69681
+ "disable_duet",
69682
+ "disable_comment",
69683
+ "disable_stitch",
69684
+ "brand_content_toggle",
69685
+ "brand_organic_toggle"
69686
+ ]
69687
+ },
69688
+ requiredScopes: ["video.publish"],
69689
+ request: {
69690
+ method: "POST",
69691
+ path: "/v2/post/publish/video/init/",
69692
+ headers: jsonPostHeaders,
69693
+ body: {
69694
+ post_info: {
69695
+ title: "{title}",
69696
+ privacy_level: "{privacy_level}",
69697
+ disable_duet: "{disable_duet}",
69698
+ disable_comment: "{disable_comment}",
69699
+ disable_stitch: "{disable_stitch}",
69700
+ video_cover_timestamp_ms: "{video_cover_timestamp_ms}",
69701
+ brand_content_toggle: "{brand_content_toggle}",
69702
+ brand_organic_toggle: "{brand_organic_toggle}",
69703
+ is_aigc: "{is_aigc}"
69704
+ },
69705
+ source_info: {
69706
+ source: "PULL_FROM_URL",
69707
+ video_url: "{video_url}"
69708
+ }
69709
+ }
69710
+ },
69711
+ cas: "none",
69712
+ externalEffect: true
69713
+ },
69714
+ {
69715
+ name: "publishing.photosFromUrls",
69716
+ class: "mutation",
69717
+ description: "Directly publish 1\u201335 approved photos from app-verified HTTPS URLs. The adapter refreshes creator options before it sends the post.",
69718
+ parameters: {
69719
+ type: "object",
69720
+ properties: {
69721
+ photo_images: {
69722
+ type: "array",
69723
+ minItems: 1,
69724
+ maxItems: 35,
69725
+ items: { type: "string", format: "uri", pattern: "^https://" }
69726
+ },
69727
+ photo_cover_index: { type: "integer", minimum: 0 },
69728
+ privacy_level: { type: "string", enum: [...PRIVACY_LEVELS] },
69729
+ title: { type: "string", maxLength: 90 },
69730
+ description: { type: "string", maxLength: 4e3 },
69731
+ disable_comment: { type: "boolean" },
69732
+ auto_add_music: { type: "boolean" },
69733
+ brand_content_toggle: {
69734
+ type: "boolean",
69735
+ description: "True for a paid partnership that promotes a third-party business."
69736
+ },
69737
+ brand_organic_toggle: {
69738
+ type: "boolean",
69739
+ description: "True when the post promotes the creator's own business."
69740
+ }
69741
+ },
69742
+ required: [
69743
+ "photo_images",
69744
+ "photo_cover_index",
69745
+ "privacy_level",
69746
+ "disable_comment",
69747
+ "auto_add_music",
69748
+ "brand_content_toggle",
69749
+ "brand_organic_toggle"
69750
+ ]
69751
+ },
69752
+ requiredScopes: ["video.publish"],
69753
+ request: {
69754
+ method: "POST",
69755
+ path: "/v2/post/publish/content/init/",
69756
+ headers: jsonPostHeaders,
69757
+ body: {
69758
+ media_type: "PHOTO",
69759
+ post_mode: "DIRECT_POST",
69760
+ post_info: {
69761
+ title: "{title}",
69762
+ description: "{description}",
69763
+ privacy_level: "{privacy_level}",
69764
+ disable_comment: "{disable_comment}",
69765
+ auto_add_music: "{auto_add_music}",
69766
+ brand_content_toggle: "{brand_content_toggle}",
69767
+ brand_organic_toggle: "{brand_organic_toggle}"
69768
+ },
69769
+ source_info: {
69770
+ source: "PULL_FROM_URL",
69771
+ photo_images: "{photo_images}",
69772
+ photo_cover_index: "{photo_cover_index}"
69773
+ }
69774
+ }
69775
+ },
69776
+ cas: "none",
69777
+ externalEffect: true
69778
+ }
69779
+ ]
69780
+ };
69781
+ var tiktokConnector = createTikTokConnector();
69782
+ function tiktok(options) {
69783
+ const adapter = createTikTokConnector();
69784
+ const inFlightRefreshes = /* @__PURE__ */ new Map();
69785
+ const refresh = async (credentials) => {
69786
+ assertOAuthClient(options);
69787
+ if (credentials.kind !== "oauth2" || !credentials.refreshToken) {
69788
+ throw new Error("tiktok.refreshToken: missing refresh token");
69789
+ }
69790
+ const token = await tiktokTokenRequest(
69791
+ options,
69792
+ {
69793
+ grant_type: "refresh_token",
69794
+ refresh_token: credentials.refreshToken
69795
+ },
69796
+ [credentials.refreshToken]
69797
+ );
69798
+ if (!token.expiresIn) {
69799
+ throw new Error("tiktok token request returned an incomplete refresh grant");
69800
+ }
69801
+ return {
69802
+ ...tokenCredentials(token),
69803
+ refreshToken: token.refreshToken ?? credentials.refreshToken
69804
+ };
69805
+ };
69806
+ const withFreshCredentials = async (invocation) => {
69807
+ const credentials = invocation.source.credentials;
69808
+ if (credentials.kind !== "oauth2") return invocation;
69809
+ if (credentials.expiresAt !== void 0 && credentials.expiresAt > Date.now() + 6e4) {
69810
+ return invocation;
69811
+ }
69812
+ if (!credentials.refreshToken) {
69813
+ throw new CredentialsExpired(
69814
+ "TikTok access token expired and no refresh token is available",
69815
+ invocation.source.id
69816
+ );
69817
+ }
69818
+ let pending = inFlightRefreshes.get(invocation.source.id);
69819
+ if (!pending) {
69820
+ let next;
69821
+ const promise = Promise.resolve().then(() => {
69822
+ if (!next.onCredentialsRotated) {
69823
+ throw new Error(
69824
+ "tiktok: credential rotation persistence callback is required before refreshing"
69825
+ );
69826
+ }
69827
+ return refresh(credentials);
69828
+ });
69829
+ next = {
69830
+ promise,
69831
+ onCredentialsRotated: invocation.onCredentialsRotated
69832
+ };
69833
+ pending = next;
69834
+ inFlightRefreshes.set(invocation.source.id, pending);
69835
+ } else if (!pending.onCredentialsRotated && invocation.onCredentialsRotated) {
69836
+ pending.onCredentialsRotated = invocation.onCredentialsRotated;
69837
+ }
69838
+ const current = pending;
69839
+ try {
69840
+ const refreshed = await current.promise;
69841
+ current.persistence ??= Promise.resolve().then(
69842
+ () => current.onCredentialsRotated?.(refreshed)
69843
+ );
69844
+ await current.persistence;
69845
+ return {
69846
+ ...invocation,
69847
+ source: { ...invocation.source, credentials: refreshed }
69848
+ };
69849
+ } finally {
69850
+ if (inFlightRefreshes.get(invocation.source.id) === current) {
69851
+ inFlightRefreshes.delete(invocation.source.id);
69852
+ }
69853
+ }
69854
+ };
69855
+ return {
69856
+ ...adapter,
69857
+ async executeRead(invocation) {
69858
+ return adapter.executeRead(await withFreshCredentials(invocation));
69859
+ },
69860
+ async executeMutation(invocation) {
69861
+ return adapter.executeMutation(await withFreshCredentials(invocation));
69862
+ },
69863
+ async test(source, onCredentialsRotated) {
69864
+ try {
69865
+ const invocation = await withFreshCredentials({
69866
+ source,
69867
+ capabilityName: "user.info",
69868
+ args: {},
69869
+ idempotencyKey: "tiktok-connection-test",
69870
+ onCredentialsRotated
69871
+ });
69872
+ return adapter.test(invocation.source);
69873
+ } catch (error) {
69874
+ return {
69875
+ ok: false,
69876
+ reason: error instanceof Error ? error.message : "unknown error"
69877
+ };
69878
+ }
69879
+ },
69880
+ async exchangeOAuth(input) {
69881
+ assertOAuthClient(options);
69882
+ const token = await tiktokTokenRequest(
69883
+ options,
69884
+ {
69885
+ grant_type: "authorization_code",
69886
+ code: input.code,
69887
+ redirect_uri: input.redirectUri
69888
+ },
69889
+ [input.code]
69890
+ );
69891
+ const grant = requireTikTokAuthorizationGrant(token);
69892
+ return {
69893
+ credentials: tokenCredentials(grant),
69894
+ scopes: grant.scopes,
69895
+ metadata: { openId: grant.openId }
69896
+ };
69897
+ },
69898
+ refreshToken: refresh
69899
+ };
69900
+ }
69901
+ function createTikTokConnector() {
69902
+ const base = declarativeRestConnector(TIKTOK_SPEC);
69903
+ const executeRead2 = async (invocation) => {
69904
+ const result = await base.executeRead(invocation);
69905
+ assertTikTokEnvelope(
69906
+ result.data,
69907
+ invocation.capabilityName,
69908
+ invocation.source.credentials
69909
+ );
69910
+ return result;
69911
+ };
69912
+ return {
69913
+ ...base,
69914
+ executeRead: executeRead2,
69915
+ async executeMutation(invocation) {
69916
+ validatePublishInput(invocation);
69917
+ const creator = await executeRead2({
69918
+ ...invocation,
69919
+ capabilityName: "publishing.creatorInfo",
69920
+ args: {}
69921
+ });
69922
+ validateCreatorLimits(invocation, creator.data);
69923
+ const result = await base.executeMutation(invocation);
69924
+ if (result.status === "committed") {
69925
+ assertTikTokPublishResult(
69926
+ result.data,
69927
+ invocation.capabilityName,
69928
+ invocation.source.credentials
69929
+ );
69930
+ }
69931
+ return result;
69932
+ },
69933
+ async test(source) {
69934
+ try {
69935
+ await executeRead2({
69936
+ source,
69937
+ capabilityName: "user.info",
69938
+ args: {},
69939
+ idempotencyKey: "tiktok-connection-test"
69940
+ });
69941
+ return { ok: true };
69942
+ } catch (error) {
69943
+ return {
69944
+ ok: false,
69945
+ reason: error instanceof Error ? error.message : "unknown error"
69946
+ };
69947
+ }
69948
+ }
69949
+ };
69950
+ }
69951
+ function validatePublishInput(invocation) {
69952
+ if (invocation.capabilityName === "publishing.videoFromUrl") {
69953
+ const url = requiredString7(invocation.args, "video_url");
69954
+ requireHttpsUrl(url, "video_url");
69955
+ const duration2 = requiredNumber(invocation.args, "video_duration_sec");
69956
+ if (duration2 <= 0) throw new Error("tiktok: video_duration_sec must be greater than zero");
69957
+ requiredPrivacy(invocation.args);
69958
+ requiredBoolean(invocation.args, "disable_duet");
69959
+ requiredBoolean(invocation.args, "disable_comment");
69960
+ requiredBoolean(invocation.args, "disable_stitch");
69961
+ requiredBoolean(invocation.args, "brand_content_toggle");
69962
+ requiredBoolean(invocation.args, "brand_organic_toggle");
69963
+ optionalUtf16Length(invocation.args, "title", 2200);
69964
+ return;
69965
+ }
69966
+ if (invocation.capabilityName === "publishing.photosFromUrls") {
69967
+ const photos = invocation.args.photo_images;
69968
+ if (!Array.isArray(photos) || photos.length < 1 || photos.length > 35) {
69969
+ throw new Error("tiktok: photo_images must contain between 1 and 35 URLs");
69970
+ }
69971
+ for (const [index, value] of photos.entries()) {
69972
+ if (typeof value !== "string") {
69973
+ throw new Error(`tiktok: photo_images[${index}] must be a string`);
69974
+ }
69975
+ requireHttpsUrl(value, `photo_images[${index}]`);
69976
+ }
69977
+ const cover = requiredNumber(invocation.args, "photo_cover_index");
69978
+ if (!Number.isInteger(cover) || cover < 0 || cover >= photos.length) {
69979
+ throw new Error("tiktok: photo_cover_index must identify one supplied photo");
69980
+ }
69981
+ requiredPrivacy(invocation.args);
69982
+ requiredBoolean(invocation.args, "disable_comment");
69983
+ requiredBoolean(invocation.args, "auto_add_music");
69984
+ requiredBoolean(invocation.args, "brand_content_toggle");
69985
+ requiredBoolean(invocation.args, "brand_organic_toggle");
69986
+ optionalUtf16Length(invocation.args, "title", 90);
69987
+ optionalUtf16Length(invocation.args, "description", 4e3);
69988
+ return;
69989
+ }
69990
+ throw new Error(`tiktok: unknown mutation capability ${invocation.capabilityName}`);
69991
+ }
69992
+ function validateCreatorLimits(invocation, envelope) {
69993
+ const data4 = readEnvelopeData(envelope, "publishing.creatorInfo");
69994
+ const privacy = requiredString7(invocation.args, "privacy_level");
69995
+ const choices = data4.privacy_level_options;
69996
+ if (!Array.isArray(choices) || !choices.every((value) => typeof value === "string")) {
69997
+ throw new Error("tiktok publishing.creatorInfo returned invalid privacy_level_options");
69998
+ }
69999
+ if (!choices.includes(privacy)) {
70000
+ throw new Error(`tiktok: privacy_level ${privacy} is unavailable for this creator`);
70001
+ }
70002
+ requireDisabledInteraction(invocation.args, data4, "disable_comment", "comment_disabled");
70003
+ if (invocation.capabilityName === "publishing.videoFromUrl") {
70004
+ requireDisabledInteraction(invocation.args, data4, "disable_duet", "duet_disabled");
70005
+ requireDisabledInteraction(invocation.args, data4, "disable_stitch", "stitch_disabled");
70006
+ const maximum = data4.max_video_post_duration_sec;
70007
+ if (typeof maximum !== "number" || !Number.isFinite(maximum) || maximum <= 0) {
70008
+ throw new Error("tiktok publishing.creatorInfo returned an invalid video-duration limit");
70009
+ }
70010
+ const duration2 = requiredNumber(invocation.args, "video_duration_sec");
70011
+ if (duration2 > maximum) {
70012
+ throw new Error(
70013
+ `tiktok: video duration ${duration2}s exceeds this creator's ${maximum}s limit`
70014
+ );
70015
+ }
70016
+ }
70017
+ }
70018
+ function assertTikTokEnvelope(value, capabilityName, credentials) {
70019
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
70020
+ throw new Error(`tiktok ${capabilityName} returned a malformed response`);
70021
+ }
70022
+ const error = value.error;
70023
+ if (!error || typeof error !== "object" || Array.isArray(error)) {
70024
+ throw new Error(`tiktok ${capabilityName} returned no error status`);
70025
+ }
70026
+ const code = error.code;
70027
+ if (code !== "ok") {
70028
+ const message = error.message;
70029
+ const detail = typeof message === "string" && message ? ` \u2014 ${redact2(message.slice(0, 200), credentialValues(credentials))}` : "";
70030
+ const safeCode = redact2(
70031
+ safeProviderValue(code),
70032
+ credentialValues(credentials)
70033
+ );
70034
+ throw new Error(`tiktok ${capabilityName} failed: ${safeCode}${detail}`);
70035
+ }
70036
+ }
70037
+ function requireDisabledInteraction(args, creator, argumentName, creatorField) {
70038
+ const disabled = creator[creatorField];
70039
+ if (typeof disabled !== "boolean") {
70040
+ throw new Error(`tiktok publishing.creatorInfo returned invalid ${creatorField}`);
70041
+ }
70042
+ if (disabled && args[argumentName] !== true) {
70043
+ throw new Error(
70044
+ `tiktok: ${argumentName} must be true because the creator disabled this interaction`
70045
+ );
70046
+ }
70047
+ }
70048
+ function readEnvelopeData(envelope, capabilityName, credentials) {
70049
+ assertTikTokEnvelope(envelope, capabilityName, credentials);
70050
+ const data4 = envelope.data;
70051
+ if (!data4 || typeof data4 !== "object" || Array.isArray(data4)) {
70052
+ throw new Error(`tiktok ${capabilityName} returned malformed data`);
70053
+ }
70054
+ return data4;
70055
+ }
70056
+ function assertTikTokPublishResult(envelope, capabilityName, credentials) {
70057
+ const data4 = readEnvelopeData(envelope, capabilityName, credentials);
70058
+ const publishId = data4.publish_id;
70059
+ if (typeof publishId !== "string" || !publishId.trim() || publishId.length > 64) {
70060
+ throw new Error(`tiktok ${capabilityName} returned an invalid publish_id`);
70061
+ }
70062
+ }
70063
+ function requiredString7(args, name) {
70064
+ const value = args[name];
70065
+ if (typeof value !== "string" || !value) {
70066
+ throw new Error(`tiktok: missing required argument: ${name}`);
70067
+ }
70068
+ return value;
70069
+ }
70070
+ function requiredNumber(args, name) {
70071
+ const value = args[name];
70072
+ if (typeof value !== "number" || !Number.isFinite(value)) {
70073
+ throw new Error(`tiktok: missing required argument: ${name}`);
70074
+ }
70075
+ return value;
70076
+ }
70077
+ function requiredBoolean(args, name) {
70078
+ const value = args[name];
70079
+ if (typeof value !== "boolean") {
70080
+ throw new Error(`tiktok: missing required argument: ${name}`);
70081
+ }
70082
+ return value;
70083
+ }
70084
+ function requiredPrivacy(args) {
70085
+ const value = requiredString7(args, "privacy_level");
70086
+ if (!PRIVACY_LEVELS.includes(value)) {
70087
+ throw new Error(`tiktok: unsupported privacy_level ${value}`);
70088
+ }
70089
+ return value;
70090
+ }
70091
+ function optionalUtf16Length(args, name, maximum) {
70092
+ const value = args[name];
70093
+ if (value === void 0) return;
70094
+ if (typeof value !== "string") throw new Error(`tiktok: ${name} must be a string`);
70095
+ if (value.length > maximum) {
70096
+ throw new Error(`tiktok: ${name} exceeds the ${maximum} UTF-16-unit limit`);
70097
+ }
70098
+ }
70099
+ function requireHttpsUrl(value, name) {
70100
+ let url;
70101
+ try {
70102
+ url = new URL(value);
70103
+ } catch {
70104
+ throw new Error(`tiktok: ${name} must be a valid HTTPS URL`);
70105
+ }
70106
+ if (url.protocol !== "https:" || url.username || url.password) {
70107
+ throw new Error(`tiktok: ${name} must be a valid HTTPS URL`);
70108
+ }
70109
+ }
70110
+ async function tiktokTokenRequest(options, grant, extraRedactions) {
70111
+ const body = new URLSearchParams({
70112
+ client_key: options.clientId,
70113
+ client_secret: options.clientSecret,
70114
+ ...grant
70115
+ });
70116
+ let response;
70117
+ try {
70118
+ response = await fetch(TOKEN_URL20, {
70119
+ method: "POST",
70120
+ headers: {
70121
+ accept: "application/json",
70122
+ "content-type": "application/x-www-form-urlencoded",
70123
+ "cache-control": "no-cache"
70124
+ },
70125
+ body,
70126
+ signal: AbortSignal.timeout(15e3)
70127
+ });
70128
+ } catch (cause) {
70129
+ const message = cause instanceof Error ? cause.message : "unknown transport error";
70130
+ throw new Error(`tiktok token request failed: ${redact2(message, [options.clientId, options.clientSecret, ...extraRedactions])}`);
70131
+ }
70132
+ if (!response.ok) {
70133
+ const detail = await response.text().catch(() => "");
70134
+ throw new Error(
70135
+ `tiktok token request failed: ${response.status} ${response.statusText} \u2014 ${redact2(
70136
+ detail.slice(0, 300),
70137
+ [options.clientId, options.clientSecret, ...extraRedactions]
70138
+ )}`
70139
+ );
70140
+ }
70141
+ const json = await response.json();
70142
+ if (typeof json.access_token !== "string" || !json.access_token) {
70143
+ throw new Error("tiktok token request returned no access_token");
70144
+ }
70145
+ return {
70146
+ accessToken: json.access_token,
70147
+ refreshToken: typeof json.refresh_token === "string" && json.refresh_token ? json.refresh_token : void 0,
70148
+ expiresIn: typeof json.expires_in === "number" && json.expires_in > 0 ? json.expires_in : void 0,
70149
+ scope: typeof json.scope === "string" ? json.scope : void 0,
70150
+ openId: typeof json.open_id === "string" ? json.open_id : void 0
70151
+ };
70152
+ }
70153
+ function tokenCredentials(token) {
70154
+ return {
70155
+ kind: "oauth2",
70156
+ accessToken: token.accessToken,
70157
+ refreshToken: token.refreshToken,
70158
+ expiresAt: token.expiresIn ? Date.now() + token.expiresIn * 1e3 : void 0
70159
+ };
70160
+ }
70161
+ function requireTikTokAuthorizationGrant(token) {
70162
+ const scopes2 = token.scope ? splitScopes(token.scope) : [];
70163
+ if (!token.refreshToken || !token.expiresIn || !token.openId || scopes2.length === 0) {
70164
+ throw new Error(
70165
+ "tiktok token request returned an incomplete authorization grant"
70166
+ );
70167
+ }
70168
+ return { ...token, scopes: scopes2 };
70169
+ }
70170
+ function splitScopes(scope) {
70171
+ return scope.split(",").map((value) => value.trim()).filter(Boolean);
70172
+ }
70173
+ function assertOAuthClient(options) {
70174
+ if (!options.clientId || !options.clientSecret) {
70175
+ throw new Error(
70176
+ "TikTok OAuth client not configured (TIKTOK_OAUTH_CLIENT_KEY / TIKTOK_OAUTH_CLIENT_SECRET)"
70177
+ );
70178
+ }
70179
+ }
70180
+ function redact2(value, secrets) {
70181
+ let redacted = value;
70182
+ for (const secret of secrets) {
70183
+ if (!secret) continue;
70184
+ redacted = redacted.split(secret).join("[REDACTED]");
70185
+ }
70186
+ return redacted;
70187
+ }
70188
+ function credentialValues(credentials) {
70189
+ if (!credentials) return [];
70190
+ switch (credentials.kind) {
70191
+ case "oauth2":
70192
+ return [credentials.accessToken, credentials.refreshToken ?? ""];
70193
+ case "api-key":
70194
+ return [credentials.apiKey];
70195
+ case "hmac":
70196
+ return [credentials.secret];
70197
+ case "custom":
70198
+ return Object.values(credentials.values).filter(
70199
+ (value) => typeof value === "string"
70200
+ );
70201
+ case "none":
70202
+ return [];
70203
+ }
70204
+ }
70205
+ function safeProviderValue(value) {
70206
+ if (typeof value === "string") return value.slice(0, 80);
70207
+ return "unknown_error";
70208
+ }
70209
+
68002
70210
  // src/connectors/adapters/twilio-sms.ts
68003
70211
  var API11 = "https://api.twilio.com/2010-04-01";
68004
70212
  var LOOKUP_API = "https://lookups.twilio.com/v1";
@@ -68459,9 +70667,9 @@ var voucheryIoConnector = declarativeRestConnector({
68459
70667
  });
68460
70668
 
68461
70669
  // src/connectors/adapters/whatsapp-business.ts
68462
- var SCOPES14 = ["whatsapp_business_messaging", "whatsapp_business_management", "business_management"];
70670
+ var SCOPES15 = ["whatsapp_business_messaging", "whatsapp_business_management", "business_management"];
68463
70671
  var AUTH_URL18 = "https://www.facebook.com/v21.0/dialog/oauth";
68464
- var TOKEN_URL20 = "https://graph.facebook.com/v21.0/oauth/access_token";
70672
+ var TOKEN_URL21 = "https://graph.facebook.com/v21.0/oauth/access_token";
68465
70673
  var API12 = "https://graph.facebook.com/v21.0";
68466
70674
  function whatsappBusiness(opts) {
68467
70675
  const { clientId, clientSecret } = opts;
@@ -68473,8 +70681,8 @@ function whatsappBusiness(opts) {
68473
70681
  auth: {
68474
70682
  kind: "oauth2",
68475
70683
  authorizationUrl: AUTH_URL18,
68476
- tokenUrl: TOKEN_URL20,
68477
- scopes: SCOPES14,
70684
+ tokenUrl: TOKEN_URL21,
70685
+ scopes: SCOPES15,
68478
70686
  clientIdEnv: "WHATSAPP_BUSINESS_OAUTH_CLIENT_ID",
68479
70687
  clientSecretEnv: "WHATSAPP_BUSINESS_OAUTH_CLIENT_SECRET"
68480
70688
  },
@@ -68744,7 +70952,7 @@ function whatsappBusiness(opts) {
68744
70952
  throw new Error("WhatsApp Business OAuth client not configured (WHATSAPP_BUSINESS_OAUTH_CLIENT_ID / _SECRET)");
68745
70953
  }
68746
70954
  const tokens = await exchangeAuthorizationCode({
68747
- tokenUrl: TOKEN_URL20,
70955
+ tokenUrl: TOKEN_URL21,
68748
70956
  clientId,
68749
70957
  clientSecret,
68750
70958
  code: input.code,
@@ -68760,7 +70968,7 @@ function whatsappBusiness(opts) {
68760
70968
  refreshToken: tokens.refreshToken,
68761
70969
  expiresAt: tokens.expiresIn ? Date.now() + tokens.expiresIn * 1e3 : void 0
68762
70970
  },
68763
- scopes: tokens.scope?.split(/[,\s]+/) ?? SCOPES14,
70971
+ scopes: tokens.scope?.split(/[,\s]+/) ?? SCOPES15,
68764
70972
  metadata: {}
68765
70973
  };
68766
70974
  },
@@ -78031,8 +80239,8 @@ var discourseConnector = declarativeRestConnector({
78031
80239
  });
78032
80240
 
78033
80241
  // src/connectors/adapters/digital-ocean.ts
78034
- var pagination2 = { page: { type: "integer", minimum: 1 }, perPage: { type: "integer", minimum: 1, maximum: 200 } };
78035
- var paginationQuery = { page: "{page}", per_page: "{perPage}" };
80242
+ var pagination3 = { page: { type: "integer", minimum: 1 }, perPage: { type: "integer", minimum: 1, maximum: 200 } };
80243
+ var paginationQuery2 = { page: "{page}", per_page: "{perPage}" };
78036
80244
  var digitalOceanConnector = declarativeRestConnector({
78037
80245
  kind: "digital-ocean",
78038
80246
  displayName: "DigitalOcean",
@@ -78045,24 +80253,24 @@ var digitalOceanConnector = declarativeRestConnector({
78045
80253
  test: { method: "GET", path: "/v2/account" },
78046
80254
  capabilities: [
78047
80255
  { name: "account.get", class: "read", description: "Read the current account and status.", parameters: { type: "object", properties: {} }, request: { method: "GET", path: "/v2/account" } },
78048
- { name: "projects.list", class: "read", description: "List projects.", parameters: { type: "object", properties: pagination2 }, request: { method: "GET", path: "/v2/projects", query: paginationQuery } },
80256
+ { name: "projects.list", class: "read", description: "List projects.", parameters: { type: "object", properties: pagination3 }, request: { method: "GET", path: "/v2/projects", query: paginationQuery2 } },
78049
80257
  { name: "projects.get", class: "read", description: "Read one project.", parameters: { type: "object", properties: { projectId: { type: "string" } }, required: ["projectId"] }, request: { method: "GET", path: "/v2/projects/{projectId}" } },
78050
80258
  { name: "projects.create", class: "mutation", description: "Create a project.", parameters: { type: "object", properties: { project: { type: "object" } }, required: ["project"] }, request: { method: "POST", path: "/v2/projects", body: "{project}" }, cas: "none", externalEffect: true },
78051
80259
  { name: "projects.update", class: "mutation", description: "Update a project.", parameters: { type: "object", properties: { projectId: { type: "string" }, project: { type: "object" } }, required: ["projectId", "project"] }, request: { method: "PATCH", path: "/v2/projects/{projectId}", body: "{project}" }, cas: "optimistic-read-verify", externalEffect: true },
78052
80260
  { name: "projects.delete", class: "mutation", description: "Delete a project.", parameters: { type: "object", properties: { projectId: { type: "string" } }, required: ["projectId"] }, request: { method: "DELETE", path: "/v2/projects/{projectId}" }, cas: "optimistic-read-verify", externalEffect: true },
78053
- { name: "droplets.list", class: "read", description: "List Droplets.", parameters: { type: "object", properties: { ...pagination2, tagName: { type: "string" }, name: { type: "string" } } }, request: { method: "GET", path: "/v2/droplets", query: { ...paginationQuery, tag_name: "{tagName}", name: "{name}" } } },
80261
+ { name: "droplets.list", class: "read", description: "List Droplets.", parameters: { type: "object", properties: { ...pagination3, tagName: { type: "string" }, name: { type: "string" } } }, request: { method: "GET", path: "/v2/droplets", query: { ...paginationQuery2, tag_name: "{tagName}", name: "{name}" } } },
78054
80262
  { name: "droplets.get", class: "read", description: "Read one Droplet.", parameters: { type: "object", properties: { dropletId: { type: "integer" } }, required: ["dropletId"] }, request: { method: "GET", path: "/v2/droplets/{dropletId}" } },
78055
80263
  { name: "droplets.create", class: "mutation", description: "Create one or more Droplets.", parameters: { type: "object", properties: { droplet: { type: "object" } }, required: ["droplet"] }, request: { method: "POST", path: "/v2/droplets", body: "{droplet}" }, cas: "none", externalEffect: true },
78056
80264
  { name: "droplets.action", class: "mutation", description: "Run a provider-native Droplet action such as power_on, shutdown, snapshot, resize, or rebuild.", parameters: { type: "object", properties: { dropletId: { type: "integer" }, action: { type: "object" } }, required: ["dropletId", "action"] }, request: { method: "POST", path: "/v2/droplets/{dropletId}/actions", body: "{action}" }, cas: "none", externalEffect: true },
78057
80265
  { name: "droplets.delete", class: "mutation", description: "Delete a Droplet.", parameters: { type: "object", properties: { dropletId: { type: "integer" } }, required: ["dropletId"] }, request: { method: "DELETE", path: "/v2/droplets/{dropletId}" }, cas: "optimistic-read-verify", externalEffect: true },
78058
- { name: "volumes.list", class: "read", description: "List block-storage volumes.", parameters: { type: "object", properties: { ...pagination2, region: { type: "string" }, name: { type: "string" } } }, request: { method: "GET", path: "/v2/volumes", query: { ...paginationQuery, region: "{region}", name: "{name}" } } },
80266
+ { name: "volumes.list", class: "read", description: "List block-storage volumes.", parameters: { type: "object", properties: { ...pagination3, region: { type: "string" }, name: { type: "string" } } }, request: { method: "GET", path: "/v2/volumes", query: { ...paginationQuery2, region: "{region}", name: "{name}" } } },
78059
80267
  { name: "volumes.create", class: "mutation", description: "Create a block-storage volume.", parameters: { type: "object", properties: { volume: { type: "object" } }, required: ["volume"] }, request: { method: "POST", path: "/v2/volumes", body: "{volume}" }, cas: "none", externalEffect: true },
78060
80268
  { name: "volumes.delete", class: "mutation", description: "Delete a block-storage volume.", parameters: { type: "object", properties: { volumeId: { type: "string" } }, required: ["volumeId"] }, request: { method: "DELETE", path: "/v2/volumes/{volumeId}" }, cas: "optimistic-read-verify", externalEffect: true },
78061
- { name: "databases.list", class: "read", description: "List managed database clusters.", parameters: { type: "object", properties: { ...pagination2, tagName: { type: "string" } } }, request: { method: "GET", path: "/v2/databases", query: { ...paginationQuery, tag_name: "{tagName}" } } },
80269
+ { name: "databases.list", class: "read", description: "List managed database clusters.", parameters: { type: "object", properties: { ...pagination3, tagName: { type: "string" } } }, request: { method: "GET", path: "/v2/databases", query: { ...paginationQuery2, tag_name: "{tagName}" } } },
78062
80270
  { name: "databases.get", class: "read", description: "Read a managed database cluster.", parameters: { type: "object", properties: { databaseId: { type: "string" } }, required: ["databaseId"] }, request: { method: "GET", path: "/v2/databases/{databaseId}" } },
78063
80271
  { name: "databases.create", class: "mutation", description: "Create a managed database cluster.", parameters: { type: "object", properties: { database: { type: "object" } }, required: ["database"] }, request: { method: "POST", path: "/v2/databases", body: "{database}" }, cas: "none", externalEffect: true },
78064
80272
  { name: "databases.delete", class: "mutation", description: "Delete a managed database cluster.", parameters: { type: "object", properties: { databaseId: { type: "string" } }, required: ["databaseId"] }, request: { method: "DELETE", path: "/v2/databases/{databaseId}" }, cas: "optimistic-read-verify", externalEffect: true },
78065
- { name: "apps.list", class: "read", description: "List App Platform apps.", parameters: { type: "object", properties: pagination2 }, request: { method: "GET", path: "/v2/apps", query: paginationQuery } },
80273
+ { name: "apps.list", class: "read", description: "List App Platform apps.", parameters: { type: "object", properties: pagination3 }, request: { method: "GET", path: "/v2/apps", query: paginationQuery2 } },
78066
80274
  { name: "apps.get", class: "read", description: "Read an App Platform app.", parameters: { type: "object", properties: { appId: { type: "string" } }, required: ["appId"] }, request: { method: "GET", path: "/v2/apps/{appId}" } },
78067
80275
  { name: "apps.create", class: "mutation", description: "Create an App Platform app.", parameters: { type: "object", properties: { spec: { type: "object" } }, required: ["spec"] }, request: { method: "POST", path: "/v2/apps", body: { spec: "{spec}" } }, cas: "none", externalEffect: true },
78068
80276
  { name: "apps.update", class: "mutation", description: "Update an App Platform app specification.", parameters: { type: "object", properties: { appId: { type: "string" }, spec: { type: "object" } }, required: ["appId", "spec"] }, request: { method: "PUT", path: "/v2/apps/{appId}", body: { spec: "{spec}" } }, cas: "optimistic-read-verify", externalEffect: true },
@@ -78071,11 +80279,11 @@ var digitalOceanConnector = declarativeRestConnector({
78071
80279
  });
78072
80280
 
78073
80281
  // src/connectors/adapters/clicksend.ts
78074
- var pagination3 = {
80282
+ var pagination4 = {
78075
80283
  page: { type: "integer", minimum: 1 },
78076
80284
  limit: { type: "integer", minimum: 1 }
78077
80285
  };
78078
- var paginationQuery2 = { page: "{page}", limit: "{limit}" };
80286
+ var paginationQuery3 = { page: "{page}", limit: "{limit}" };
78079
80287
  var listId = { listId: { type: "integer" } };
78080
80288
  var contactId = { contactId: { type: "integer" } };
78081
80289
  var clicksendConnector = declarativeRestConnector({
@@ -78107,8 +80315,8 @@ var clicksendConnector = declarativeRestConnector({
78107
80315
  name: "lists.list",
78108
80316
  class: "read",
78109
80317
  description: "List contact lists.",
78110
- parameters: { type: "object", properties: pagination3 },
78111
- request: { method: "GET", path: "/lists", query: paginationQuery2 }
80318
+ parameters: { type: "object", properties: pagination4 },
80319
+ request: { method: "GET", path: "/lists", query: paginationQuery3 }
78112
80320
  },
78113
80321
  {
78114
80322
  name: "lists.get",
@@ -78158,13 +80366,13 @@ var clicksendConnector = declarativeRestConnector({
78158
80366
  description: "List contacts in a list.",
78159
80367
  parameters: {
78160
80368
  type: "object",
78161
- properties: { ...listId, ...pagination3, updatedAfter: { type: "integer" } },
80369
+ properties: { ...listId, ...pagination4, updatedAfter: { type: "integer" } },
78162
80370
  required: ["listId"]
78163
80371
  },
78164
80372
  request: {
78165
80373
  method: "GET",
78166
80374
  path: "/lists/{listId}/contacts",
78167
- query: { ...paginationQuery2, updated_after: "{updatedAfter}" }
80375
+ query: { ...paginationQuery3, updated_after: "{updatedAfter}" }
78168
80376
  }
78169
80377
  },
78170
80378
  {
@@ -78234,7 +80442,7 @@ var clicksendConnector = declarativeRestConnector({
78234
80442
  query: { type: "string" },
78235
80443
  dateFrom: { type: "integer" },
78236
80444
  dateTo: { type: "integer" },
78237
- ...pagination3
80445
+ ...pagination4
78238
80446
  }
78239
80447
  },
78240
80448
  request: {
@@ -78244,7 +80452,7 @@ var clicksendConnector = declarativeRestConnector({
78244
80452
  q: "{query}",
78245
80453
  date_from: "{dateFrom}",
78246
80454
  date_to: "{dateTo}",
78247
- ...paginationQuery2
80455
+ ...paginationQuery3
78248
80456
  }
78249
80457
  }
78250
80458
  },
@@ -78254,16 +80462,16 @@ var clicksendConnector = declarativeRestConnector({
78254
80462
  description: "List inbound SMS messages.",
78255
80463
  parameters: {
78256
80464
  type: "object",
78257
- properties: { query: { type: "string" }, ...pagination3 }
80465
+ properties: { query: { type: "string" }, ...pagination4 }
78258
80466
  },
78259
- request: { method: "GET", path: "/sms/inbound", query: { q: "{query}", ...paginationQuery2 } }
80467
+ request: { method: "GET", path: "/sms/inbound", query: { q: "{query}", ...paginationQuery3 } }
78260
80468
  },
78261
80469
  {
78262
80470
  name: "sms.receipts.list",
78263
80471
  class: "read",
78264
80472
  description: "List SMS delivery receipts.",
78265
- parameters: { type: "object", properties: pagination3 },
78266
- request: { method: "GET", path: "/sms/receipts", query: paginationQuery2 }
80473
+ parameters: { type: "object", properties: pagination4 },
80474
+ request: { method: "GET", path: "/sms/receipts", query: paginationQuery3 }
78267
80475
  },
78268
80476
  {
78269
80477
  name: "sms.send",
@@ -78299,12 +80507,12 @@ var clicksendConnector = declarativeRestConnector({
78299
80507
  description: "List voice message history.",
78300
80508
  parameters: {
78301
80509
  type: "object",
78302
- properties: { dateFrom: { type: "integer" }, dateTo: { type: "integer" }, ...pagination3 }
80510
+ properties: { dateFrom: { type: "integer" }, dateTo: { type: "integer" }, ...pagination4 }
78303
80511
  },
78304
80512
  request: {
78305
80513
  method: "GET",
78306
80514
  path: "/voice/history",
78307
- query: { date_from: "{dateFrom}", date_to: "{dateTo}", ...paginationQuery2 }
80515
+ query: { date_from: "{dateFrom}", date_to: "{dateTo}", ...paginationQuery3 }
78308
80516
  }
78309
80517
  },
78310
80518
  {
@@ -79474,7 +81682,7 @@ function readQuery2(inv) {
79474
81682
  throw new Error(`Unknown MySQL read capability: ${inv.capabilityName}`);
79475
81683
  }
79476
81684
  function readStatementArgs(args) {
79477
- const statement = requiredString7(args.statement, "statement");
81685
+ const statement = requiredString8(args.statement, "statement");
79478
81686
  if (Buffer.byteLength(statement, "utf8") > 1024 * 1024) throw new Error("statement exceeds the 1 MiB limit");
79479
81687
  const parameters = args.parameters === void 0 ? [] : args.parameters;
79480
81688
  if (!Array.isArray(parameters) || parameters.length > MAX_PARAMETERS) {
@@ -79565,7 +81773,7 @@ function readDatabase(value, source) {
79565
81773
  function queryTimeout(source) {
79566
81774
  return readCredentials7(source).queryTimeoutMs;
79567
81775
  }
79568
- function requiredString7(value, label) {
81776
+ function requiredString8(value, label) {
79569
81777
  const parsed = readOptionalString(value, label);
79570
81778
  if (!parsed) throw new Error(`${label} is required`);
79571
81779
  return parsed;
@@ -79577,7 +81785,7 @@ function requiredCredentialString3(value, label, maxLength) {
79577
81785
  return parsed;
79578
81786
  }
79579
81787
  function readIdentifier2(value, label) {
79580
- const parsed = requiredString7(value, label);
81788
+ const parsed = requiredString8(value, label);
79581
81789
  if (parsed.length > 64) throw new Error(`${label} exceeds 64 characters`);
79582
81790
  return parsed;
79583
81791
  }
@@ -81147,6 +83355,8 @@ var CONNECTOR_ADAPTER_FACTORIES = [
81147
83355
  defineFactoryAdapter(() => segmentConnector, {}),
81148
83356
  defineFactoryAdapter(() => hightouchConnector, {}),
81149
83357
  defineFactoryAdapter(() => datadogConnector, {}),
83358
+ defineFactoryAdapter(() => amplitudeConnector, {}),
83359
+ defineFactoryAdapter(() => cloudflareConnector, {}),
81150
83360
  defineFactoryAdapter(() => discourseConnector, {}),
81151
83361
  defineFactoryAdapter(() => digitalOceanConnector, {}),
81152
83362
  defineFactoryAdapter(() => clicksendConnector, {}),
@@ -81177,6 +83387,10 @@ var CONNECTOR_ADAPTER_FACTORIES = [
81177
83387
  clientId: "TWITTER_OAUTH_CLIENT_ID",
81178
83388
  clientSecret: "TWITTER_OAUTH_CLIENT_SECRET"
81179
83389
  }),
83390
+ defineFactoryAdapter(tiktok, {
83391
+ clientId: "TIKTOK_OAUTH_CLIENT_KEY",
83392
+ clientSecret: "TIKTOK_OAUTH_CLIENT_SECRET"
83393
+ }),
81180
83394
  // Declarative OAuth2 connectors: the manifest already pins clientIdEnv /
81181
83395
  // clientSecretEnv; the envMap re-pins the same names so registration is
81182
83396
  // gated on the OAuth app actually being configured (no half-live connector).
@@ -81204,6 +83418,8 @@ var CONNECTOR_ADAPTER_FACTORIES = [
81204
83418
  // credentials from each connection; OAuth providers are registered only
81205
83419
  // when the shared application credentials are present.
81206
83420
  defineFactoryAdapter(() => amazonEventBridgeConnector, {}),
83421
+ defineFactoryAdapter(() => amazonLambdaConnector, {}),
83422
+ defineFactoryAdapter(() => amazonCloudWatchConnector, {}),
81207
83423
  defineFactoryAdapter(() => amazonS3Connector, {}),
81208
83424
  defineFactoryAdapter(() => amazonSnsConnector, {}),
81209
83425
  defineFactoryAdapter(() => amazonSqsConnector, {}),
@@ -81253,9 +83469,8 @@ var CONNECTOR_ADAPTER_FACTORIES = [
81253
83469
  clientId: "ACUITY_OAUTH_CLIENT_ID",
81254
83470
  clientSecret: "ACUITY_OAUTH_CLIENT_SECRET"
81255
83471
  }),
81256
- defineFactoryAdapter(() => calComConnector, {
81257
- clientId: "CALCOM_OAUTH_CLIENT_ID",
81258
- clientSecret: "CALCOM_OAUTH_CLIENT_SECRET"
83472
+ defineFactoryAdapter(calCom, {
83473
+ clientId: "CALCOM_OAUTH_CLIENT_ID"
81259
83474
  }),
81260
83475
  defineFactoryAdapter(() => savvycalConnector, {
81261
83476
  clientId: "SAVVYCAL_OAUTH_CLIENT_ID",
@@ -146552,7 +148767,10 @@ export {
146552
148767
  adobeSignConnector,
146553
148768
  aircallConnector,
146554
148769
  affinityConnector,
148770
+ amplitudeConnector,
146555
148771
  amazonEventBridgeConnector,
148772
+ amazonCloudWatchConnector,
148773
+ amazonLambdaConnector,
146556
148774
  amazonS3Connector,
146557
148775
  amazonSnsConnector,
146558
148776
  amazonSqsConnector,
@@ -146575,10 +148793,12 @@ export {
146575
148793
  billComConnector,
146576
148794
  billplzConnector,
146577
148795
  calComConnector,
148796
+ calCom,
146578
148797
  calendlyConnector,
146579
148798
  capsuleCrmConnector,
146580
148799
  closeConnector,
146581
148800
  clickupConnector,
148801
+ cloudflareConnector,
146582
148802
  cloudinaryConnector,
146583
148803
  codaConnector,
146584
148804
  confluenceConnector,
@@ -146723,6 +148943,8 @@ export {
146723
148943
  typeformConnector,
146724
148944
  twitterConnector,
146725
148945
  twitter,
148946
+ tiktokConnector,
148947
+ tiktok,
146726
148948
  twilioSmsConnector,
146727
148949
  voucheryIoConnector,
146728
148950
  whatsappBusiness,
@@ -147110,4 +149332,4 @@ export {
147110
149332
  getresponseConnector,
147111
149333
  adapters_exports
147112
149334
  };
147113
- //# sourceMappingURL=chunk-AGXTCR34.js.map
149335
+ //# sourceMappingURL=chunk-HNEEIMQC.js.map