@zackbart/connecta 0.24.3 → 0.25.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 (145) hide show
  1. package/AGENTS.md +58 -30
  2. package/CHANGELOG.md +317 -1
  3. package/README.md +5 -6
  4. package/dist/advertised-schema.js +53 -0
  5. package/dist/auth/downstream-oauth.js +490 -106
  6. package/dist/branding.d.ts +31 -2
  7. package/dist/branding.js +116 -8
  8. package/dist/call-admission.js +139 -113
  9. package/dist/catalog-service.js +141 -105
  10. package/dist/catalog.js +258 -33
  11. package/dist/concurrency.js +24 -23
  12. package/dist/connector-scope.js +6 -37
  13. package/dist/connectors/api.d.ts +3 -3
  14. package/dist/connectors/api.js +10 -2
  15. package/dist/connectors/guarded-fetch.js +34 -4
  16. package/dist/connectors/remote-mcp.d.ts +6 -5
  17. package/dist/connectors/remote-mcp.js +325 -245
  18. package/dist/credential-contract.d.ts +9 -0
  19. package/dist/credential-rules.js +2 -2
  20. package/dist/credentials.d.ts +6 -1
  21. package/dist/credentials.js +45 -3
  22. package/dist/errors.d.ts +11 -3
  23. package/dist/errors.js +2 -1
  24. package/dist/execute.js +363 -257
  25. package/dist/executor-admission.js +67 -50
  26. package/dist/executors/quickjs-runtime.js +4 -2
  27. package/dist/executors/quickjs.js +251 -210
  28. package/dist/fix-prompt.js +37 -0
  29. package/dist/index.d.ts +11 -2
  30. package/dist/index.js +63 -21
  31. package/dist/invocation.js +324 -285
  32. package/dist/meta-tools.js +304 -114
  33. package/dist/oauth-callback-outcome.js +94 -0
  34. package/dist/oauth-sealing.js +29 -0
  35. package/dist/operator-ui/fix-prompts.js +87 -0
  36. package/dist/operator-ui/generated.js +2 -2
  37. package/dist/operator-ui/model.d.ts +46 -1
  38. package/dist/operator-ui/setup-commands.js +53 -0
  39. package/dist/operator-ui/view.js +109 -2
  40. package/dist/program-source.js +205 -0
  41. package/dist/providers/cloudflare.d.ts +14 -2
  42. package/dist/providers/cloudflare.js +107 -16
  43. package/dist/providers/linear.d.ts +26 -4
  44. package/dist/providers/linear.js +19 -4
  45. package/dist/providers/mixpanel.d.ts +16 -3
  46. package/dist/providers/mixpanel.js +13 -2
  47. package/dist/providers/notion.d.ts +8 -1
  48. package/dist/providers/notion.js +85 -12
  49. package/dist/providers/revenuecat.d.ts +30 -4
  50. package/dist/providers/revenuecat.js +70 -5
  51. package/dist/providers/stripe.d.ts +10 -3
  52. package/dist/providers/stripe.js +30 -4
  53. package/dist/providers/vercel.js +12 -2
  54. package/dist/registry.d.ts +13 -5
  55. package/dist/registry.js +317 -258
  56. package/dist/routes/activity.js +120 -137
  57. package/dist/routes/credentials.js +174 -163
  58. package/dist/routes/mcp.js +129 -70
  59. package/dist/routes/oauth-management.js +60 -71
  60. package/dist/routes/oauth.js +44 -16
  61. package/dist/routes/operator.js +82 -0
  62. package/dist/routes/shared.d.ts +2 -0
  63. package/dist/routes/ui-data.js +210 -0
  64. package/dist/routes/ui.js +64 -32
  65. package/dist/runtime/admission.js +43 -0
  66. package/dist/runtime/call-admission.js +67 -0
  67. package/dist/runtime/connector-scope.js +72 -0
  68. package/dist/runtime/run.js +174 -0
  69. package/dist/runtime/services.js +130 -0
  70. package/dist/runtime/storage.js +66 -0
  71. package/dist/server.js +111 -89
  72. package/dist/skills.js +1 -1
  73. package/dist/storage/file.js +39 -2
  74. package/dist/storage/memory.js +28 -16
  75. package/dist/timeout.js +17 -47
  76. package/dist/types.d.ts +64 -7
  77. package/dist/ui.d.ts +16 -2
  78. package/dist/ui.js +68 -176
  79. package/dist/url-safety.js +157 -0
  80. package/dist/version.d.ts +1 -1
  81. package/dist/version.js +1 -1
  82. package/documentation/architecture.md +368 -182
  83. package/documentation/auth.md +277 -176
  84. package/documentation/code-mode.md +479 -329
  85. package/documentation/meta-tools.md +494 -417
  86. package/ethos.md +44 -47
  87. package/examples/worker/AGENTS.md +2 -1
  88. package/examples/worker/README.md +62 -14
  89. package/examples/worker/src/d1-storage.ts +116 -0
  90. package/examples/worker/src/index.ts +18 -21
  91. package/examples/worker/wrangler.jsonc +16 -4
  92. package/package.json +11 -4
  93. package/templates/node/.env.example +3 -3
  94. package/templates/node/AGENTS.md +5 -4
  95. package/templates/node/README.md +2 -1
  96. package/templates/node/package.json +1 -1
  97. package/templates/node/src/index.ts +23 -22
  98. package/dist/auth/downstream-oauth.d.ts +0 -200
  99. package/dist/catalog-fingerprint.d.ts +0 -19
  100. package/dist/catalog-limits.d.ts +0 -9
  101. package/dist/catalog-service.d.ts +0 -263
  102. package/dist/catalog.d.ts +0 -87
  103. package/dist/concurrency.d.ts +0 -3
  104. package/dist/connectors/guarded-fetch.d.ts +0 -92
  105. package/dist/credential-rules.d.ts +0 -85
  106. package/dist/execute.d.ts +0 -154
  107. package/dist/executor-result.d.ts +0 -10
  108. package/dist/executors/quickjs-child.d.ts +0 -1
  109. package/dist/executors/quickjs-protocol.d.ts +0 -67
  110. package/dist/favicon.d.ts +0 -1
  111. package/dist/identity.d.ts +0 -4
  112. package/dist/invocation.d.ts +0 -74
  113. package/dist/mcp-result.d.ts +0 -8
  114. package/dist/meta-tools.d.ts +0 -129
  115. package/dist/operator-ui/generated.d.ts +0 -2
  116. package/dist/operator-ui/view.d.ts +0 -151
  117. package/dist/result-shapes.d.ts +0 -13
  118. package/dist/retired-toolkits.d.ts +0 -2
  119. package/dist/routes/activity.d.ts +0 -2
  120. package/dist/routes/credentials.d.ts +0 -2
  121. package/dist/routes/mcp.d.ts +0 -10
  122. package/dist/routes/oauth-management.d.ts +0 -2
  123. package/dist/routes/oauth.d.ts +0 -2
  124. package/dist/routes/ui.d.ts +0 -2
  125. package/dist/server.d.ts +0 -9
  126. package/dist/skills.d.ts +0 -44
  127. package/dist/timeout.d.ts +0 -21
  128. package/dist/tool-safety.d.ts +0 -9
  129. package/documentation/call-admission.md +0 -158
  130. package/documentation/cloudflare.md +0 -471
  131. package/documentation/connector-guides.md +0 -176
  132. package/documentation/connectors.md +0 -431
  133. package/documentation/linear.md +0 -193
  134. package/documentation/mixpanel.md +0 -160
  135. package/documentation/notion.md +0 -308
  136. package/documentation/operations.md +0 -359
  137. package/documentation/operator-ui.md +0 -135
  138. package/documentation/optional-modules-upgrade.md +0 -243
  139. package/documentation/provider-conventions.md +0 -729
  140. package/documentation/request-admission.md +0 -204
  141. package/documentation/revenuecat.md +0 -305
  142. package/documentation/storage-and-credentials.md +0 -254
  143. package/documentation/stripe.md +0 -262
  144. package/documentation/upgrading.md +0 -768
  145. package/documentation/vercel.md +0 -241
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Syntactic destination checks for URLs a downstream hands connecta to fetch.
3
+ *
4
+ * A remote MCP server's OAuth metadata names further URLs — authorization
5
+ * servers, token and registration endpoints — that connecta then requests
6
+ * server-side. Config is the security model: the connector's configured
7
+ * origin is trusted because an operator wrote it down. Everything else was
8
+ * learned from the downstream, and a compromised downstream must not be able
9
+ * to steer connecta at the host's own network (cloud metadata, a LAN admin
10
+ * panel, a sidecar on loopback).
11
+ *
12
+ * The check is by syntax only. The WHATWG URL parser has already folded every
13
+ * legacy IPv4 spelling (`2130706433`, `0x7f.1`, `0177.0.0.1`) into dotted
14
+ * decimal and every IPv6 literal into compressed hex, so one canonical form is
15
+ * all this module reads. It never resolves a name: that needs DNS, which the
16
+ * Workers-safe core cannot do, and a name that resolves somewhere private — or
17
+ * rebinds after the check — is out of scope. Pure Web API, no `node:` import.
18
+ */
19
+ function classifyIpv4(octets) {
20
+ const [a = 0, b = 0] = octets;
21
+ if (a === 127)
22
+ return "loopback";
23
+ if (a === 0 ||
24
+ a === 10 ||
25
+ (a === 172 && b >= 16 && b <= 31) ||
26
+ (a === 192 && b === 168) ||
27
+ (a === 169 && b === 254) ||
28
+ (a === 100 && b >= 64 && b <= 127)) {
29
+ return "private";
30
+ }
31
+ return "public";
32
+ }
33
+ const IPV4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
34
+ const HEXTET = /^[0-9a-f]{1,4}$/;
35
+ function ipv4Octets(host) {
36
+ const match = IPV4.exec(host);
37
+ if (!match)
38
+ return undefined;
39
+ const octets = match.slice(1).map(Number);
40
+ return octets.every((octet) => octet <= 255) ? octets : undefined;
41
+ }
42
+ /** Eight 16-bit pieces of a bracketed IPv6 literal, or undefined. */
43
+ function ipv6Pieces(host) {
44
+ const body = host.slice(1, -1);
45
+ const halves = body.split("::");
46
+ if (halves.length > 2)
47
+ return undefined;
48
+ const pieces = (part) => {
49
+ if (!part)
50
+ return [];
51
+ const parsed = part.split(":").map((piece) => HEXTET.test(piece) ? Number.parseInt(piece, 16) : Number.NaN);
52
+ return parsed.some(Number.isNaN) ? undefined : parsed;
53
+ };
54
+ const head = pieces(halves[0]);
55
+ const tail = pieces(halves[1]);
56
+ if (!head || !tail)
57
+ return undefined;
58
+ const missing = 8 - head.length - tail.length;
59
+ if (halves.length === 1 ? missing !== 0 : missing < 0)
60
+ return undefined;
61
+ return [...head, ...Array.from({ length: missing }, () => 0), ...tail];
62
+ }
63
+ function classifyIpv6(pieces) {
64
+ const [first = 0] = pieces;
65
+ const leadingZeros = pieces.slice(0, 5).every((piece) => piece === 0);
66
+ if (leadingZeros && pieces[5] === 0 && pieces[6] === 0) {
67
+ if (pieces[7] === 0)
68
+ return "private"; // ::
69
+ if (pieces[7] === 1)
70
+ return "loopback"; // ::1
71
+ }
72
+ // ::ffff:a.b.c.d reaches the mapped IPv4 destination; classify that.
73
+ if (leadingZeros && pieces[5] === 0xffff) {
74
+ const high = pieces[6] ?? 0;
75
+ const low = pieces[7] ?? 0;
76
+ return classifyIpv4([high >> 8, high & 0xff, low >> 8, low & 0xff]);
77
+ }
78
+ if ((first & 0xfe00) === 0xfc00)
79
+ return "private"; // fc00::/7
80
+ if ((first & 0xffc0) === 0xfe80)
81
+ return "private"; // fe80::/10
82
+ return "public";
83
+ }
84
+ /**
85
+ * The hostname the WHATWG parser settles on. Idempotent for a `URL.hostname`;
86
+ * anything else — a bare IPv6 literal, a legacy IPv4 spelling — is folded the
87
+ * same way the parser would fold it on the way to a fetch.
88
+ */
89
+ function canonicalHost(hostname) {
90
+ if (/[/\\?#@]/.test(hostname))
91
+ return undefined;
92
+ const bracketed = hostname.includes(":") && !hostname.startsWith("[")
93
+ ? `[${hostname}]`
94
+ : hostname;
95
+ try {
96
+ return new URL(`http://${bracketed}/`).hostname;
97
+ }
98
+ catch {
99
+ return undefined;
100
+ }
101
+ }
102
+ /**
103
+ * Classify a URL host by syntax. A host that does not parse is `private`:
104
+ * the check fails closed rather than guessing.
105
+ */
106
+ export function classifyHost(hostname) {
107
+ const host = canonicalHost(hostname);
108
+ if (!host)
109
+ return "private";
110
+ if (host.startsWith("[")) {
111
+ const pieces = ipv6Pieces(host);
112
+ return pieces ? classifyIpv6(pieces) : "private";
113
+ }
114
+ const octets = ipv4Octets(host);
115
+ if (octets)
116
+ return classifyIpv4(octets);
117
+ const name = host.endsWith(".") ? host.slice(0, -1) : host;
118
+ if (name === "localhost" || name.endsWith(".localhost"))
119
+ return "loopback";
120
+ return "public";
121
+ }
122
+ /** True for loopback and private hosts alike. */
123
+ export function isPrivateHost(hostname) {
124
+ return classifyHost(hostname) !== "public";
125
+ }
126
+ /**
127
+ * Why connecta must not fetch `target`, a URL the downstream advertised, for a
128
+ * connector configured at `configured` — or undefined when it may.
129
+ *
130
+ * - The configured origin is trusted outright: the operator chose it.
131
+ * - Anything else must be `https` on a host that is not private by syntax.
132
+ * - A loopback-configured connector (local development) may also learn
133
+ * loopback URLs, over `http` too, so a local MCP server with a local
134
+ * authorization server keeps working. It still may not learn a LAN or
135
+ * link-local address.
136
+ *
137
+ * The reason names only the host, never the path, query, or credentials a
138
+ * learned URL may carry.
139
+ */
140
+ export function learnedUrlRefusal(configured, target) {
141
+ if (target.protocol !== "https:" && target.protocol !== "http:") {
142
+ return `${target.host || "the target"} uses ${target.protocol}, not HTTPS`;
143
+ }
144
+ if (target.origin === configured.origin)
145
+ return undefined;
146
+ const targetClass = classifyHost(target.hostname);
147
+ if (targetClass === "loopback" &&
148
+ classifyHost(configured.hostname) === "loopback") {
149
+ return undefined;
150
+ }
151
+ if (targetClass !== "public") {
152
+ return `${target.host} is a private, loopback, or link-local address`;
153
+ }
154
+ if (target.protocol !== "https:")
155
+ return `${target.host} is not HTTPS`;
156
+ return undefined;
157
+ }
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export declare const CONNECTA_VERSION = "0.24.3";
7
+ export declare const CONNECTA_VERSION = "0.25.0";
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.24.3";
7
+ export const CONNECTA_VERSION = "0.25.0";