@zackbart/connecta 0.29.0 → 0.31.0

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 (116) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +126 -134
  3. package/bin/connecta.mjs +13 -2
  4. package/bin/version.mjs +1 -1
  5. package/dist/argument-redaction.js +230 -0
  6. package/dist/auth-elicitation.js +14 -9
  7. package/dist/authorization-handoff.js +111 -0
  8. package/dist/call-recovery.js +25 -0
  9. package/dist/catalog-cache.js +2 -2
  10. package/dist/catalog-service.js +103 -63
  11. package/dist/config-schema.d.ts +14 -7
  12. package/dist/config-schema.js +29 -10
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.js +12 -7
  15. package/dist/connectors/guarded-fetch.d.ts +9 -1
  16. package/dist/connectors/guarded-fetch.js +17 -5
  17. package/dist/connectors/negotiation-cache.js +1 -1
  18. package/dist/downstream-input-context.js +9 -0
  19. package/dist/downstream-input.js +13 -11
  20. package/dist/errors.d.ts +38 -12
  21. package/dist/errors.js +19 -9
  22. package/dist/execute.js +375 -43
  23. package/dist/executor-result.js +11 -9
  24. package/dist/executors/quickjs-child.js +12 -5
  25. package/dist/executors/quickjs-protocol.js +5 -6
  26. package/dist/executors/quickjs-runtime.js +6 -1
  27. package/dist/executors/quickjs.js +20 -4
  28. package/dist/guest-runtime.js +52 -2
  29. package/dist/guest-types.d.ts +47 -5
  30. package/dist/index.d.ts +1 -1
  31. package/dist/invocation.js +72 -14
  32. package/dist/meta-output.js +0 -15
  33. package/dist/meta-tools.js +166 -95
  34. package/dist/oauth-handoff.js +88 -11
  35. package/dist/operator-ui/generated.js +2 -2
  36. package/dist/operator-ui/view.d.ts +9 -0
  37. package/dist/operator-ui/view.js +11 -0
  38. package/dist/program-result.js +5 -0
  39. package/dist/program-writes.js +7 -48
  40. package/dist/provider.d.ts +8 -6
  41. package/dist/provider.js +3 -4
  42. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  43. package/dist/providers/_shared/request-token.js +83 -0
  44. package/dist/providers/_shared/rest/dispatch.js +41 -0
  45. package/dist/providers/_shared/rest/operation-index.d.ts +133 -0
  46. package/dist/providers/_shared/rest/operation-index.js +527 -0
  47. package/dist/providers/_shared/rest/tools.d.ts +141 -0
  48. package/dist/providers/_shared/rest/tools.js +569 -0
  49. package/dist/providers/_shared/rest/value-safety.d.ts +151 -0
  50. package/dist/providers/_shared/rest/value-safety.js +580 -0
  51. package/dist/providers/cloudflare/graphql.js +385 -0
  52. package/dist/providers/cloudflare/index.d.ts +47 -51
  53. package/dist/providers/cloudflare/index.js +188 -1997
  54. package/dist/providers/cloudflare/openapi.generated.js +3347 -0
  55. package/dist/providers/cloudflare/rest.d.ts +37 -0
  56. package/dist/providers/cloudflare/rest.js +1056 -0
  57. package/dist/providers/cloudflare/skill.generated.js +7 -4
  58. package/dist/providers/cloudflare/value-safety.js +1247 -0
  59. package/dist/providers/infisical/index.d.ts +7 -0
  60. package/dist/providers/infisical/index.js +713 -0
  61. package/dist/providers/infisical/skill.generated.js +8 -0
  62. package/dist/providers/notion/index.d.ts +35 -31
  63. package/dist/providers/notion/index.js +60 -1499
  64. package/dist/providers/notion/openapi.generated.js +75 -0
  65. package/dist/providers/notion/rest.d.ts +24 -0
  66. package/dist/providers/notion/rest.js +1067 -0
  67. package/dist/providers/notion/skill.generated.js +5 -4
  68. package/dist/providers/notion/value-safety.js +31 -0
  69. package/dist/providers/stripe/index.d.ts +26 -20
  70. package/dist/providers/stripe/index.js +103 -130
  71. package/dist/providers/stripe/openapi.generated.js +649 -0
  72. package/dist/providers/stripe/rest.d.ts +14 -0
  73. package/dist/providers/stripe/rest.js +395 -0
  74. package/dist/providers/stripe/skill.generated.js +7 -5
  75. package/dist/providers/stripe/value-safety.js +705 -0
  76. package/dist/providers/vercel/index.d.ts +31 -22
  77. package/dist/providers/vercel/index.js +96 -853
  78. package/dist/providers/vercel/openapi.generated.js +456 -0
  79. package/dist/providers/vercel/rest.d.ts +20 -0
  80. package/dist/providers/vercel/rest.js +1002 -0
  81. package/dist/providers/vercel/skill.generated.js +4 -5
  82. package/dist/providers/vercel/value-safety.js +328 -0
  83. package/dist/registry.d.ts +8 -6
  84. package/dist/registry.js +134 -61
  85. package/dist/resource-read.js +4 -1
  86. package/dist/routes/mcp.js +11 -2
  87. package/dist/sent-secrets.d.ts +54 -13
  88. package/dist/sent-secrets.js +770 -231
  89. package/dist/skills.js +26 -16
  90. package/dist/sqlite.js +21 -6
  91. package/dist/storage/keys.js +20 -5
  92. package/dist/storage/memory.js +9 -4
  93. package/dist/storage/sql.js +18 -9
  94. package/dist/types.d.ts +17 -3
  95. package/dist/usage-guide.js +49 -40
  96. package/dist/version.d.ts +1 -1
  97. package/dist/version.js +1 -1
  98. package/dist/worker.js +2 -1
  99. package/dist/write-outcome.js +47 -0
  100. package/documentation/README.md +64 -0
  101. package/documentation/architecture.md +241 -97
  102. package/documentation/auth.md +138 -5
  103. package/documentation/code-mode.md +224 -107
  104. package/documentation/deploying.md +146 -0
  105. package/documentation/integrating.md +170 -0
  106. package/documentation/meta-tools.md +142 -30
  107. package/documentation/operating.md +135 -0
  108. package/documentation/operator-tests.md +4 -0
  109. package/documentation/operator-ui.md +132 -0
  110. package/documentation/provider-auth-migration.md +307 -0
  111. package/documentation/provider-migration-0.29.md +22 -5
  112. package/examples/worker/README.md +9 -2
  113. package/package.json +9 -2
  114. package/templates/node/README.md +9 -2
  115. package/templates/node/package.json +1 -1
  116. package/dist/providers/vercel/mcp-ownership.js +0 -212
@@ -0,0 +1,385 @@
1
+ // Read-only admission for Cloudflare's GraphQL Analytics API. A document is
2
+ // tokenized by the GraphQL lexical grammar (strings, block strings, comments
3
+ // and commas are skipped as the spec skips them) and its top-level
4
+ // definitions are walked, so a `mutation` hidden in a string, a comment, or
5
+ // after an anonymous query is still found, and anything that is not a query
6
+ // or a fragment is refused. Nothing here does I/O.
7
+ import { ConnectorCallError } from "../../errors.js";
8
+ const SCOPED_FIELDS = new Set(["accounts", "zones"]);
9
+ function refuse(message) {
10
+ throw new ConnectorCallError("invalid_args", message);
11
+ }
12
+ function tokenize(source) {
13
+ const tokens = [];
14
+ let at = 0;
15
+ const length = source.length;
16
+ while (at < length) {
17
+ const character = source[at];
18
+ if (character === " " || character === "\t" || character === "\n" || character === "\r" || character === ",") {
19
+ at += 1;
20
+ continue;
21
+ }
22
+ if (character === "") {
23
+ at += 1;
24
+ continue;
25
+ }
26
+ if (character === "#") {
27
+ while (at < length && source[at] !== "\n" && source[at] !== "\r")
28
+ at += 1;
29
+ continue;
30
+ }
31
+ if (source.startsWith("...", at)) {
32
+ tokens.push({ kind: "punct", value: "..." });
33
+ at += 3;
34
+ continue;
35
+ }
36
+ if ("!$&()[]{}:=@|".includes(character)) {
37
+ tokens.push({ kind: "punct", value: character });
38
+ at += 1;
39
+ continue;
40
+ }
41
+ if (/[_A-Za-z]/.test(character)) {
42
+ const start = at;
43
+ while (at < length && /[_0-9A-Za-z]/.test(source[at]))
44
+ at += 1;
45
+ tokens.push({ kind: "name", value: source.slice(start, at) });
46
+ continue;
47
+ }
48
+ if (character === "-" || /[0-9]/.test(character)) {
49
+ const match = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/.exec(source.slice(at));
50
+ if (!match)
51
+ refuse("The GraphQL document has a malformed number.");
52
+ tokens.push({ kind: "number", value: match[0] });
53
+ at += match[0].length;
54
+ continue;
55
+ }
56
+ if (source.startsWith('"""', at)) {
57
+ let end = at + 3;
58
+ let text = "";
59
+ for (;;) {
60
+ if (end >= length)
61
+ refuse("The GraphQL document has an unterminated block string.");
62
+ if (source.startsWith('\\"""', end)) {
63
+ text += '"""';
64
+ end += 4;
65
+ continue;
66
+ }
67
+ if (source.startsWith('"""', end))
68
+ break;
69
+ text += source[end];
70
+ end += 1;
71
+ }
72
+ tokens.push({ kind: "string", value: text });
73
+ at = end + 3;
74
+ continue;
75
+ }
76
+ if (character === '"') {
77
+ let end = at + 1;
78
+ let text = "";
79
+ for (;;) {
80
+ const next = source[end];
81
+ if (next === undefined || next === "\n" || next === "\r")
82
+ refuse("The GraphQL document has an unterminated string.");
83
+ if (next === '"')
84
+ break;
85
+ if (next === "\\") {
86
+ const escape = source[end + 1];
87
+ if (escape === "u") {
88
+ const hex = source.slice(end + 2, end + 6);
89
+ if (!/^[0-9A-Fa-f]{4}$/.test(hex))
90
+ refuse("The GraphQL document has a malformed string escape.");
91
+ text += String.fromCharCode(parseInt(hex, 16));
92
+ end += 6;
93
+ continue;
94
+ }
95
+ const simple = {
96
+ '"': '"',
97
+ "\\": "\\",
98
+ "/": "/",
99
+ b: "\b",
100
+ f: "\f",
101
+ n: "\n",
102
+ r: "\r",
103
+ t: "\t",
104
+ };
105
+ if (escape === undefined || !(escape in simple))
106
+ refuse("The GraphQL document has a malformed string escape.");
107
+ text += simple[escape];
108
+ end += 2;
109
+ continue;
110
+ }
111
+ text += next;
112
+ end += 1;
113
+ }
114
+ tokens.push({ kind: "string", value: text });
115
+ at = end + 1;
116
+ continue;
117
+ }
118
+ refuse(`The GraphQL document has an unexpected character at offset ${at}.`);
119
+ }
120
+ return tokens;
121
+ }
122
+ const OPENERS = { "(": ")", "[": "]", "{": "}" };
123
+ /**
124
+ * Refuse anything but queries and fragments, and report the account and zone
125
+ * tags the document names. `variables` resolves `$name` tag values.
126
+ */
127
+ export function inspectGraphqlQuery(source, variables, options = {}) {
128
+ const tokens = tokenize(source);
129
+ if (tokens.length === 0)
130
+ refuse("The GraphQL document is empty.");
131
+ let index = 0;
132
+ let operations = 0;
133
+ // Skip one balanced group starting at `index` (an opener); returns the index after its closer.
134
+ const skipGroup = (start) => {
135
+ const stack = [];
136
+ for (let at = start; at < tokens.length; at += 1) {
137
+ const token = tokens[at];
138
+ if (token.kind !== "punct")
139
+ continue;
140
+ if (OPENERS[token.value])
141
+ stack.push(OPENERS[token.value]);
142
+ else if (token.value === ")" || token.value === "]" || token.value === "}") {
143
+ if (stack.pop() !== token.value)
144
+ refuse("The GraphQL document has unbalanced brackets.");
145
+ if (stack.length === 0)
146
+ return at + 1;
147
+ }
148
+ }
149
+ return refuse("The GraphQL document has unbalanced brackets.");
150
+ };
151
+ // From a definition keyword, consume the header (name, variables,
152
+ // directives) and its selection set.
153
+ const skipDefinition = (start) => {
154
+ for (let at = start; at < tokens.length; at += 1) {
155
+ const token = tokens[at];
156
+ if (token.kind !== "punct")
157
+ continue;
158
+ if (token.value === "{")
159
+ return skipGroup(at);
160
+ if (token.value === "(" || token.value === "[")
161
+ at = skipGroup(at) - 1;
162
+ else if (token.value === "}" || token.value === ")" || token.value === "]") {
163
+ refuse("The GraphQL document has unbalanced brackets.");
164
+ }
165
+ }
166
+ return refuse("A GraphQL definition has no selection set.");
167
+ };
168
+ // Each top-level definition's token range, for the strict checks below.
169
+ const definitions = [];
170
+ const nameAfter = (at) => {
171
+ const token = tokens[at];
172
+ return token?.kind === "name" ? token.value : undefined;
173
+ };
174
+ while (index < tokens.length) {
175
+ const token = tokens[index];
176
+ if (token.kind === "punct" && token.value === "{") {
177
+ operations += 1;
178
+ const end = skipGroup(index);
179
+ definitions.push({ kind: "query", name: undefined, start: index, end });
180
+ index = end;
181
+ continue;
182
+ }
183
+ if (token.kind === "name" && token.value === "query") {
184
+ operations += 1;
185
+ const end = skipDefinition(index + 1);
186
+ definitions.push({ kind: "query", name: nameAfter(index + 1), start: index, end });
187
+ index = end;
188
+ continue;
189
+ }
190
+ if (token.kind === "name" && token.value === "fragment") {
191
+ const end = skipDefinition(index + 1);
192
+ definitions.push({ kind: "fragment", name: nameAfter(index + 1), start: index, end });
193
+ index = end;
194
+ continue;
195
+ }
196
+ if (token.kind === "name" && (token.value === "mutation" || token.value === "subscription")) {
197
+ refuse(`graphql_query runs read-only queries; this document contains a ${token.value}, which it never sends.`);
198
+ }
199
+ refuse("graphql_query accepts only query operations and fragments.");
200
+ }
201
+ if (operations === 0)
202
+ refuse("The GraphQL document has no query operation.");
203
+ if (options.strict) {
204
+ // One operation, so every variable default belongs to the query that
205
+ // runs; and every fragment reachable from it, defined, used, and acyclic,
206
+ // so the fields checked below are exactly the fields that execute.
207
+ if (operations !== 1)
208
+ refuse("A pinned connector sends one query operation per GraphQL document.");
209
+ const operation = definitions.find((definition) => definition.kind === "query");
210
+ if (options.operationName !== undefined && options.operationName !== operation.name) {
211
+ refuse(`operationName ${options.operationName} names no query in this document.`);
212
+ }
213
+ const fragments = new Map();
214
+ for (const definition of definitions) {
215
+ if (definition.kind !== "fragment")
216
+ continue;
217
+ if (!definition.name || definition.name === "on" || fragments.has(definition.name)) {
218
+ refuse("A GraphQL fragment must have one unique name.");
219
+ }
220
+ fragments.set(definition.name, definition);
221
+ }
222
+ const spreads = (range) => {
223
+ const names = [];
224
+ for (let at = range.start; at < range.end; at += 1) {
225
+ if (tokens[at].value === "..." && tokens[at + 1]?.kind === "name" && tokens[at + 1].value !== "on") {
226
+ names.push(tokens[at + 1].value);
227
+ }
228
+ }
229
+ return names;
230
+ };
231
+ const used = new Set();
232
+ const visit = (range, path) => {
233
+ for (const name of spreads(range)) {
234
+ const fragment = fragments.get(name);
235
+ if (!fragment)
236
+ refuse(`The GraphQL document spreads an undefined fragment ${name}.`);
237
+ if (path.includes(name))
238
+ refuse(`The GraphQL fragment ${name} spreads itself.`);
239
+ used.add(name);
240
+ visit(fragment, [...path, name]);
241
+ }
242
+ };
243
+ visit(operation, []);
244
+ const unused = [...fragments.keys()].filter((name) => !used.has(name));
245
+ if (unused.length > 0)
246
+ refuse(`The GraphQL document defines unused fragments: ${unused.join(", ")}.`);
247
+ }
248
+ const accountTags = [];
249
+ const zoneTags = [];
250
+ const openTags = [];
251
+ const unscopedFields = [];
252
+ const UNRESOLVED = Symbol("unresolved");
253
+ // Variable declarations (`$zoneTag: String! = "…"`) are not filters; record
254
+ // their defaults so a variable resolves as the server would resolve it.
255
+ const defaults = new Map();
256
+ const declared = new Set();
257
+ const resolveVariable = (name) => Object.hasOwn(variables, name) ? variables[name] : defaults.has(name) ? defaults.get(name) : UNRESOLVED;
258
+ /** Parse one GraphQL input value at `at`, resolving variables; returns the value and the index after it. */
259
+ const parseValue = (at) => {
260
+ const token = tokens[at];
261
+ if (token === undefined)
262
+ return { value: UNRESOLVED, end: at };
263
+ if (token.kind === "string")
264
+ return { value: token.value, end: at + 1 };
265
+ if (token.kind === "number")
266
+ return { value: Number(token.value), end: at + 1 };
267
+ if (token.kind === "name") {
268
+ const literal = { true: true, false: false, null: null };
269
+ return { value: Object.hasOwn(literal, token.value) ? literal[token.value] : { enum: token.value }, end: at + 1 };
270
+ }
271
+ if (token.value === "$" && tokens[at + 1]?.kind === "name") {
272
+ return { value: resolveVariable(tokens[at + 1].value), end: at + 2 };
273
+ }
274
+ if (token.value === "[") {
275
+ const items = [];
276
+ let next = at + 1;
277
+ while (next < tokens.length && tokens[next].value !== "]") {
278
+ const item = parseValue(next);
279
+ if (item.end === next)
280
+ return { value: UNRESOLVED, end: skipGroup(at) };
281
+ items.push(item.value);
282
+ next = item.end;
283
+ }
284
+ return { value: items, end: next + 1 };
285
+ }
286
+ if (token.value === "{") {
287
+ const object = {};
288
+ let next = at + 1;
289
+ while (next < tokens.length && tokens[next].value !== "}") {
290
+ const key = tokens[next];
291
+ if (key?.kind !== "name" || tokens[next + 1]?.value !== ":")
292
+ return { value: UNRESOLVED, end: skipGroup(at) };
293
+ const item = parseValue(next + 2);
294
+ if (item.end === next + 2)
295
+ return { value: UNRESOLVED, end: skipGroup(at) };
296
+ object[key.value] = item.value;
297
+ next = item.end;
298
+ }
299
+ return { value: object, end: next + 1 };
300
+ }
301
+ return { value: UNRESOLVED, end: at };
302
+ };
303
+ for (let at = 0; at + 2 < tokens.length; at += 1) {
304
+ const [dollar, name, colon] = [tokens[at], tokens[at + 1], tokens[at + 2]];
305
+ if (dollar.value !== "$" || name.kind !== "name" || colon.value !== ":")
306
+ continue;
307
+ declared.add(at + 1);
308
+ for (let scan = at + 3; scan < tokens.length; scan += 1) {
309
+ const token = tokens[scan];
310
+ if (token.kind === "punct" && (token.value === "$" || token.value === ")"))
311
+ break;
312
+ if (token.kind === "punct" && token.value === "=") {
313
+ const parsed = parseValue(scan + 1);
314
+ if (parsed.value !== UNRESOLVED)
315
+ defaults.set(name.value, parsed.value);
316
+ break;
317
+ }
318
+ }
319
+ }
320
+ /**
321
+ * Validate one `zones` or `accounts` field's resolved `filter`: an object
322
+ * whose only keys are the tag equality or `_in`, with string values. Each
323
+ * field is checked on its own, so a valid alias cannot carry an unpinned one.
324
+ */
325
+ const checkField = (field, filter) => {
326
+ const prefix = field === "zones" ? "zone" : "account";
327
+ if (filter === UNRESOLVED || typeof filter !== "object" || filter === null || Array.isArray(filter)) {
328
+ unscopedFields.push(field);
329
+ return;
330
+ }
331
+ const target = prefix === "zone" ? zoneTags : accountTags;
332
+ let tagged = false;
333
+ for (const [key, value] of Object.entries(filter)) {
334
+ if (key === `${prefix}Tag` && typeof value === "string") {
335
+ target.push(value);
336
+ tagged = true;
337
+ }
338
+ else if (key === `${prefix}Tag_in` &&
339
+ Array.isArray(value) &&
340
+ value.length > 0 &&
341
+ value.every((item) => typeof item === "string")) {
342
+ target.push(...value);
343
+ tagged = true;
344
+ }
345
+ else {
346
+ openTags.push(`${field}.${key}`);
347
+ }
348
+ }
349
+ if (!tagged)
350
+ unscopedFields.push(field);
351
+ };
352
+ for (let at = 0; at < tokens.length; at += 1) {
353
+ const token = tokens[at];
354
+ if (token.kind !== "name" || !SCOPED_FIELDS.has(token.value) || declared.has(at))
355
+ continue;
356
+ const previous = tokens[at - 1]?.value;
357
+ const next = tokens[at + 1];
358
+ if (previous === "$" || previous === "on" || previous === "...")
359
+ continue;
360
+ // `zones: accounts(…)` aliases, and object keys inside arguments.
361
+ if (next?.kind === "punct" && next.value === ":")
362
+ continue;
363
+ if (next?.kind !== "punct" || next.value !== "(") {
364
+ unscopedFields.push(token.value);
365
+ continue;
366
+ }
367
+ let filter = UNRESOLVED;
368
+ let cursor = at + 2;
369
+ while (cursor < tokens.length && tokens[cursor].value !== ")") {
370
+ const key = tokens[cursor];
371
+ if (key?.kind !== "name" || tokens[cursor + 1]?.value !== ":") {
372
+ filter = UNRESOLVED;
373
+ break;
374
+ }
375
+ const parsed = parseValue(cursor + 2);
376
+ if (parsed.end === cursor + 2)
377
+ break;
378
+ if (key.value === "filter")
379
+ filter = parsed.value;
380
+ cursor = parsed.end;
381
+ }
382
+ checkField(token.value, filter);
383
+ }
384
+ return { accountTags, zoneTags, openTags, unscopedFields };
385
+ }
@@ -1,29 +1,11 @@
1
- import { type RemoteMcpAuth } from "../../connectors/remote-mcp.js";
2
- import type { ConnectorCallAdmissionPolicy, ConnectorCredentialConfig } from "../../types.js";
3
- /** Cloudflare's v4 REST base. Override only for a proxy or a test double. */
4
- export declare const CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4";
1
+ import type { ConnectorCallAdmissionPolicy } from "../../types.js";
2
+ import { type CloudflarePin } from "./rest.js";
3
+ export { CLOUDFLARE_API_BASE } from "./rest.js";
4
+ export type { CloudflarePin } from "./rest.js";
5
5
  /** Cloudflare's official whole-API hosted MCP endpoint. */
6
6
  export declare const CLOUDFLARE_MCP_ENDPOINT = "https://mcp.cloudflare.com/mcp";
7
- /** Authentication schemes accepted by Cloudflare's v4 API. */
8
- export type CloudflareAuthentication = "apiToken" | "globalApiKey";
9
- /**
10
- * The 21 record types Cloudflare accepts. Eight carry a single `content`
11
- * string; the other thirteen carry a per-type structured `data` object.
12
- * `list_dns_records` filters on all 21 because reading them costs nothing.
13
- */
14
- export declare const CLOUDFLARE_DNS_RECORD_TYPES: readonly ["A", "AAAA", "CAA", "CERT", "CNAME", "DNSKEY", "DS", "HTTPS", "LOC", "MX", "NAPTR", "NS", "OPENPGPKEY", "PTR", "SMIMEA", "SRV", "SSHFP", "SVCB", "TLSA", "TXT", "URI"];
15
- /**
16
- * Content-valued types only, and the only types `create_dns_record` and
17
- * `update_dns_record` accept. Covering the thirteen structured-`data` types
18
- * would mean either a free-form `data` passthrough — the untyped body this
19
- * connection exists to avoid — or thirteen more hand-written schemas for record
20
- * types that are rare in day-to-day zone administration. They stay fully
21
- * readable; writing one goes through the approval-gated raw mutation tool with
22
- * Cloudflare's documented per-type `data` body.
23
- */
24
- export declare const CLOUDFLARE_CONTENT_DNS_RECORD_TYPES: readonly ["A", "AAAA", "CNAME", "MX", "NS", "OPENPGPKEY", "PTR", "TXT"];
25
7
  interface CloudflareCommonOptions {
26
- /** Human-readable display name; defaults identify the selected interface. */
8
+ /** Human-readable display name; defaults identify the implementation. */
27
9
  title?: string;
28
10
  /** Downstream auth ownership. Defaults to one shared deployment grant. */
29
11
  authScope?: "shared" | "personal";
@@ -34,44 +16,58 @@ interface CloudflareCommonOptions {
34
16
  /** Connector-specific inline result limit; omit to inherit the deployment. */
35
17
  maxResultBytes?: number;
36
18
  }
37
- export interface CloudflareApiOptions extends CloudflareCommonOptions {
38
- /** Select the REST complement explicitly; hosted MCP is the default. */
39
- surface: "api";
19
+ /** Cloudflare's hosted MCP server (`search` and `execute`) over OAuth. */
20
+ export interface CloudflareOAuthOptions extends CloudflareCommonOptions {
21
+ auth: {
22
+ type: "oauth";
23
+ };
24
+ /** Optional per-runtime downstream call-admission policy. */
25
+ callAdmission?: ConnectorCallAdmissionPolicy;
26
+ }
27
+ interface CloudflareKeyOptions extends CloudflareCommonOptions {
40
28
  /**
41
- * Default account id for account-scoped tools. When set, `accountId` becomes
42
- * an optional argument; when omitted, agents must pass one and can find it
43
- * with `list_accounts`.
29
+ * Default account id: fills `{account_id}` in paths and verifies an
30
+ * account-owned token. Routing only; `pin` is the boundary.
44
31
  */
45
32
  accountId?: string;
46
- /**
47
- * Default zone id for zone-scoped tools. When set, `zoneId` becomes an
48
- * optional argument; when omitted, agents must pass one and can find it with
49
- * `list_zones`.
50
- */
33
+ /** Default zone id: fills `{zone_id}` in paths. Routing only; `pin` is the boundary. */
51
34
  zoneId?: string;
52
35
  /** API base override for a proxy or a test double. Defaults to the v4 API. */
53
36
  baseUrl?: string;
54
- /** Authentication scheme. Defaults to the recommended scoped API token. */
55
- authentication?: CloudflareAuthentication;
56
- /** Credential presentation override; credentials are always operator-managed. */
57
- credential?: ConnectorCredentialConfig;
58
37
  /** Simultaneous downstream calls. Defaults to 6. */
59
38
  maxConcurrency?: number;
60
39
  }
61
- export interface CloudflareMcpOptions extends CloudflareCommonOptions {
62
- surface?: "mcp";
63
- /** OAuth by default, or a scoped API token for a headless deployment. */
64
- auth?: RemoteMcpAuth;
65
- /** Optional per-runtime downstream call-admission policy. */
66
- callAdmission?: ConnectorCallAdmissionPolicy;
40
+ /**
41
+ * Connecta's REST connector with one operator-managed, scoped API token. A
42
+ * `pin` restricts it further to named accounts and zones.
43
+ */
44
+ export interface CloudflareApiTokenOptions extends CloudflareKeyOptions {
45
+ auth: {
46
+ type: "apiToken";
47
+ };
48
+ /** Accounts and zones this connector may touch, enforced on every call. */
49
+ pin?: CloudflarePin;
67
50
  }
68
- /** Backward-compatible API options; existing consumers may extend this interface. */
69
- export interface CloudflareOptions extends CloudflareApiOptions {
51
+ /**
52
+ * Connecta's REST connector with a legacy Global API Key and its user's
53
+ * email. The key acts as the user everywhere, so the connector requires a
54
+ * `pin` unless `unpinned: true` states the whole estate is intended.
55
+ */
56
+ export interface CloudflareGlobalApiKeyOptions extends CloudflareKeyOptions {
57
+ auth: {
58
+ type: "globalApiKey";
59
+ };
60
+ /** Accounts and zones this connector may touch; required unless `unpinned`. */
61
+ pin?: CloudflarePin;
62
+ /** Accept every account and zone the key's user can reach. */
63
+ unpinned?: true;
70
64
  }
71
- /** Select one Cloudflare interface when deployment configuration constructs it. */
72
- export type CloudflareConnectionOptions = CloudflareOptions | CloudflareMcpOptions;
73
- /** A maintained Cloudflare connection using the selected provider interface. */
74
- export declare const cloudflare: import("../../provider.js").ProviderFactory<CloudflareConnectionOptions>;
65
+ export type CloudflareOptions = CloudflareOAuthOptions | CloudflareApiTokenOptions | CloudflareGlobalApiKeyOptions;
66
+ /**
67
+ * A maintained Cloudflare connection. `auth` selects the implementation:
68
+ * OAuth reaches Cloudflare's hosted MCP server; an API token or a Global API
69
+ * Key reaches Connecta's REST connector to the v4 API.
70
+ */
71
+ export declare const cloudflare: import("../../provider.js").ProviderFactory<CloudflareOptions>;
75
72
  /** @deprecated Read `cloudflare.definition.classify` instead. Kept for existing imports. */
76
73
  export declare const CLOUDFLARE_MCP_VETTED_CATALOG: import("../../catalog-drift.js").VettedCatalog;
77
- export {};