@zackbart/connecta 0.24.4 → 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.
- package/AGENTS.md +40 -10
- package/CHANGELOG.md +253 -0
- package/dist/advertised-schema.js +53 -0
- package/dist/auth/downstream-oauth.js +490 -106
- package/dist/call-admission.js +139 -113
- package/dist/catalog-service.js +141 -105
- package/dist/catalog.js +258 -33
- package/dist/concurrency.js +24 -23
- package/dist/connector-scope.js +6 -37
- package/dist/connectors/api.d.ts +2 -2
- package/dist/connectors/remote-mcp.d.ts +6 -5
- package/dist/connectors/remote-mcp.js +317 -241
- package/dist/credential-contract.d.ts +9 -0
- package/dist/credential-rules.js +2 -2
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +45 -3
- package/dist/execute.js +363 -257
- package/dist/executor-admission.js +67 -50
- package/dist/executors/quickjs-runtime.js +4 -2
- package/dist/executors/quickjs.js +251 -210
- package/dist/fix-prompt.js +37 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +51 -20
- package/dist/invocation.js +324 -285
- package/dist/meta-tools.js +206 -92
- package/dist/oauth-callback-outcome.js +94 -0
- package/dist/oauth-sealing.js +29 -0
- package/dist/operator-ui/fix-prompts.js +87 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/model.d.ts +46 -1
- package/dist/operator-ui/setup-commands.js +53 -0
- package/dist/operator-ui/view.js +38 -2
- package/dist/program-source.js +205 -0
- package/dist/providers/notion.js +2 -2
- package/dist/providers/revenuecat.js +32 -5
- package/dist/providers/stripe.d.ts +3 -2
- package/dist/providers/vercel.js +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +305 -260
- package/dist/routes/activity.js +120 -137
- package/dist/routes/credentials.js +174 -163
- package/dist/routes/mcp.js +129 -70
- package/dist/routes/oauth-management.js +60 -71
- package/dist/routes/oauth.js +44 -16
- package/dist/routes/operator.js +82 -0
- package/dist/routes/shared.d.ts +2 -0
- package/dist/routes/ui-data.js +210 -0
- package/dist/routes/ui.js +64 -32
- package/dist/runtime/admission.js +43 -0
- package/dist/runtime/call-admission.js +67 -0
- package/dist/runtime/connector-scope.js +72 -0
- package/dist/runtime/run.js +174 -0
- package/dist/runtime/services.js +130 -0
- package/dist/runtime/storage.js +66 -0
- package/dist/server.js +111 -89
- package/dist/skills.js +1 -1
- package/dist/storage/file.js +39 -2
- package/dist/storage/memory.js +28 -16
- package/dist/timeout.js +17 -47
- package/dist/types.d.ts +27 -7
- package/dist/ui.d.ts +16 -2
- package/dist/ui.js +50 -166
- package/dist/url-safety.js +157 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +184 -10
- package/documentation/auth.md +80 -0
- package/documentation/code-mode.md +69 -24
- package/documentation/meta-tools.md +164 -27
- package/ethos.md +44 -47
- package/examples/worker/README.md +51 -5
- package/examples/worker/src/d1-storage.ts +116 -0
- package/examples/worker/src/index.ts +6 -6
- package/examples/worker/wrangler.jsonc +16 -4
- package/package.json +11 -3
- package/templates/node/package.json +1 -1
- package/dist/auth/downstream-oauth.d.ts +0 -200
- package/dist/catalog-fingerprint.d.ts +0 -19
- package/dist/catalog-limits.d.ts +0 -9
- package/dist/catalog-service.d.ts +0 -263
- package/dist/catalog.d.ts +0 -87
- package/dist/concurrency.d.ts +0 -3
- package/dist/connectors/guarded-fetch.d.ts +0 -96
- package/dist/credential-rules.d.ts +0 -85
- package/dist/execute.d.ts +0 -154
- package/dist/executor-result.d.ts +0 -10
- package/dist/executors/quickjs-child.d.ts +0 -1
- package/dist/executors/quickjs-protocol.d.ts +0 -67
- package/dist/favicon.d.ts +0 -1
- package/dist/identity.d.ts +0 -4
- package/dist/invocation.d.ts +0 -74
- package/dist/mcp-result.d.ts +0 -8
- package/dist/meta-tools.d.ts +0 -129
- package/dist/operator-ui/generated.d.ts +0 -2
- package/dist/operator-ui/view.d.ts +0 -188
- package/dist/result-shapes.d.ts +0 -13
- package/dist/retired-toolkits.d.ts +0 -2
- package/dist/routes/activity.d.ts +0 -2
- package/dist/routes/credentials.d.ts +0 -2
- package/dist/routes/mcp.d.ts +0 -10
- package/dist/routes/oauth-management.d.ts +0 -2
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/ui.d.ts +0 -2
- package/dist/server.d.ts +0 -9
- package/dist/skills.d.ts +0 -44
- package/dist/timeout.d.ts +0 -21
- package/dist/tool-safety.d.ts +0 -9
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frame every copyable fix prompt shares: the operator page's failure
|
|
3
|
+
* notices and the OAuth callback page both hand an operator text to paste into
|
|
4
|
+
* a coding agent working in the deployment's repository.
|
|
5
|
+
*
|
|
6
|
+
* A prompt is assembled from fixed catalogue text and, at most, a configured
|
|
7
|
+
* connector id. It has no parameter an error message, a downstream body, a
|
|
8
|
+
* token, or a URL could arrive through — which is the whole guarantee: the
|
|
9
|
+
* text leaves the page on a clipboard, into a tool the deployment does not
|
|
10
|
+
* control, so it must be something the deployment would be content to publish.
|
|
11
|
+
* The agent finds the underlying cause where it belongs, in the deployment's
|
|
12
|
+
* own logs and a local reproduction.
|
|
13
|
+
*/
|
|
14
|
+
const CONNECTOR_ID_RE = /^[a-z0-9_-]+$/;
|
|
15
|
+
/**
|
|
16
|
+
* Render one prompt. A connector id is the only variable part, and only when
|
|
17
|
+
* it has the shape configuration enforces; anything else is dropped rather
|
|
18
|
+
* than escaped, since a value that is not a connector id is not config.
|
|
19
|
+
*/
|
|
20
|
+
export function renderFixPrompt(spec, connectorId) {
|
|
21
|
+
const id = connectorId !== undefined && CONNECTOR_ID_RE.test(connectorId)
|
|
22
|
+
? connectorId
|
|
23
|
+
: undefined;
|
|
24
|
+
return [
|
|
25
|
+
"Diagnose and fix a problem in this connecta deployment (the @zackbart/connecta package). " +
|
|
26
|
+
"It is configured as code: connectors, credential slots, OAuth clients, pools, and inbound auth " +
|
|
27
|
+
"are declared in the deployment's source and environment, so the fix belongs there and not in the operator page.",
|
|
28
|
+
`Problem: ${spec.problem}` + (id ? `\nConnector id: ${id}` : ""),
|
|
29
|
+
`Where to look:\n${spec.steps.map((step) => `- ${step}`).join("\n")}`,
|
|
30
|
+
"This prompt deliberately carries no error text, tokens, or URLs. Find the underlying cause in the deployment's " +
|
|
31
|
+
"own logs (lines prefixed [connecta]) or by reproducing the failure locally. Never put a secret in source, " +
|
|
32
|
+
"a log line, or your reply: secrets belong in the deployment's environment or its credential vault.",
|
|
33
|
+
"Make the smallest change that fixes it, then verify it by redeploying and refreshing the connection on the " +
|
|
34
|
+
"operator Connections page. If the fix needs something you cannot do yourself — a provider console setting, " +
|
|
35
|
+
"a secret only the operator holds — name that exact step instead.",
|
|
36
|
+
].join("\n\n");
|
|
37
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export interface ConnectaCallsConfig {
|
|
|
47
47
|
/**
|
|
48
48
|
* Max inline result size (bytes) before truncation and `get_result` paging.
|
|
49
49
|
* Must be a finite whole number >= 1; invalid values warn and fall back to
|
|
50
|
-
*
|
|
50
|
+
* 24_000. Connectors may override it individually.
|
|
51
51
|
*/
|
|
52
52
|
maxResultBytes?: number;
|
|
53
53
|
}
|
|
@@ -81,6 +81,15 @@ export interface ConnectaExecuteConfig {
|
|
|
81
81
|
* values fall back to the default.
|
|
82
82
|
*/
|
|
83
83
|
hostCallTimeoutMs?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Hard ceiling on one execution, in milliseconds, enforced outside the
|
|
86
|
+
* sandbox. Default 120_000, above both executors' own deadlines (QuickJS
|
|
87
|
+
* 30_000, the Dynamic Worker 60_000), so it only ends a run whose executor
|
|
88
|
+
* never settled; that run fails as unresponsive and its admission slot is
|
|
89
|
+
* released. Keep it above any raised executor deadline. Invalid values
|
|
90
|
+
* fall back to the default.
|
|
91
|
+
*/
|
|
92
|
+
watchdogMs?: number;
|
|
84
93
|
}
|
|
85
94
|
export interface AdmissionPoolConfig {
|
|
86
95
|
/** Simultaneous work admitted to this pool. */
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { droppedBrandingUrls, droppedThemeTokens, droppedUiAuthUrls, } from "./b
|
|
|
6
6
|
import { memoryStorage } from "./storage/memory.js";
|
|
7
7
|
import { CONNECTA_VERSION } from "./version.js";
|
|
8
8
|
import { AdmissionController, executorName, isAdmittingExecutor, withExecutorAdmission, } from "./executor-admission.js";
|
|
9
|
+
import { disposeEdgeRuntime } from "./runtime/run.js";
|
|
10
|
+
import { createCoreRuntime, resolveLogger } from "./runtime/services.js";
|
|
9
11
|
const REQUEST_ADMISSION_DEFAULTS = {
|
|
10
12
|
concurrency: 16,
|
|
11
13
|
maxQueueSize: 32,
|
|
@@ -26,14 +28,6 @@ function admissionController(options, defaults) {
|
|
|
26
28
|
retryAfterMs: options?.retryAfterMs ?? defaults.retryAfterMs,
|
|
27
29
|
});
|
|
28
30
|
}
|
|
29
|
-
function defaultLogger() {
|
|
30
|
-
return {
|
|
31
|
-
debug: (...a) => console.debug("[connecta]", ...a),
|
|
32
|
-
info: (...a) => console.info("[connecta]", ...a),
|
|
33
|
-
warn: (...a) => console.warn("[connecta]", ...a),
|
|
34
|
-
error: (...a) => console.error("[connecta]", ...a),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
31
|
/** Bearer providers are checked before Clerk (per spec). */
|
|
38
32
|
function normalizeAuth(auth) {
|
|
39
33
|
const list = auth ? (Array.isArray(auth) ? auth : [auth]) : [];
|
|
@@ -84,6 +78,7 @@ const CONFIG_SCHEMA = {
|
|
|
84
78
|
maxEmittedBlocks: null,
|
|
85
79
|
maxHostCalls: null,
|
|
86
80
|
hostCallTimeoutMs: null,
|
|
81
|
+
watchdogMs: null,
|
|
87
82
|
},
|
|
88
83
|
admission: {
|
|
89
84
|
requests: admissionPoolSchema,
|
|
@@ -151,7 +146,7 @@ function assertKnownConfig(config) {
|
|
|
151
146
|
}
|
|
152
147
|
}
|
|
153
148
|
}
|
|
154
|
-
if (config.vault && ["get", "getAll", "set", "setAll", "metadata", "delete"].some(key => typeof config.vault[key] !== "function"))
|
|
149
|
+
if (config.vault && (["get", "getAll", "set", "setAll", "metadata", "delete"].some(key => typeof config.vault[key] !== "function") || ["seal", "open"].some(key => !["undefined", "function"].includes(typeof config.vault[key]))))
|
|
155
150
|
throw new Error("ConnectaConfig.vault must implement CredentialVault");
|
|
156
151
|
if (config.ui && (typeof config.ui.handle !== "function" || typeof config.ui.credentialHandoffUrl !== "function" || !Array.isArray(config.ui.reservedPaths)))
|
|
157
152
|
throw new Error("ConnectaConfig.ui must be created with operatorUi(...)");
|
|
@@ -296,18 +291,31 @@ function warnInsecureConfig(config, inboundAuth, logger) {
|
|
|
296
291
|
}
|
|
297
292
|
// A credential test hook that cannot test the declared credential shape.
|
|
298
293
|
// The shape picks the hook (see `credentialTestRule`) and the other one is
|
|
299
|
-
// never substituted, so the
|
|
300
|
-
//
|
|
301
|
-
//
|
|
294
|
+
// never substituted, so the connection offers no Test action in the operator
|
|
295
|
+
// UI and the route answers 400. Without this line the only way to discover
|
|
296
|
+
// the mistake is to click a button that isn't there.
|
|
302
297
|
for (const connector of config.connectors) {
|
|
303
298
|
const { mismatch } = credentialTestRule(connector);
|
|
304
299
|
if (!mismatch)
|
|
305
300
|
continue;
|
|
306
301
|
logger.warn(`[connecta] connector "${connector.id}" cannot test its credential: ` +
|
|
307
|
-
`${describeCredentialTestMismatch(mismatch)}.
|
|
302
|
+
`${describeCredentialTestMismatch(mismatch)}. The connection in the operator UI offers no Test ` +
|
|
308
303
|
`action and POST /ui/credentials/${connector.id}/test answers 400 ` +
|
|
309
304
|
"until the matching hook is implemented.");
|
|
310
305
|
}
|
|
306
|
+
// A vault written before seal/open existed encrypts credentials but cannot
|
|
307
|
+
// seal downstream OAuth state, so tokens stay plaintext at rest beside them.
|
|
308
|
+
const vault = config.vault;
|
|
309
|
+
if (vault && (typeof vault.seal !== "function" || typeof vault.open !== "function")) {
|
|
310
|
+
for (const connector of config.connectors) {
|
|
311
|
+
if (!connector.startAuth)
|
|
312
|
+
continue;
|
|
313
|
+
logger.warn(`[connecta] connector "${connector.id}" stores its downstream OAuth ` +
|
|
314
|
+
"tokens, client registration, and PKCE verifier as plaintext: the " +
|
|
315
|
+
"configured vault implements no `seal`/`open`. Use " +
|
|
316
|
+
"encryptedCredentialVault(...) or add both methods to seal them.");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
311
319
|
// OAuth connectors whose callback cannot perform a state/CSRF check. The
|
|
312
320
|
// public route refuses every callback for these connectors rather than hand
|
|
313
321
|
// an unverified code to finishAuth, so this warning explains why auth cannot
|
|
@@ -331,9 +339,7 @@ export function createConnecta(config) {
|
|
|
331
339
|
'"@cloudflare/codemode" on Workers.');
|
|
332
340
|
}
|
|
333
341
|
const storage = config.storage ?? memoryStorage();
|
|
334
|
-
const logger = config.logger
|
|
335
|
-
? { debug() { }, info() { }, warn() { }, error() { } }
|
|
336
|
-
: config.logger ?? defaultLogger();
|
|
342
|
+
const logger = resolveLogger(config.logger);
|
|
337
343
|
const credentialVault = config.vault;
|
|
338
344
|
const configuredAuth = normalizeAuth(config.auth);
|
|
339
345
|
const serverInfo = {
|
|
@@ -381,6 +387,22 @@ export function createConnecta(config) {
|
|
|
381
387
|
"implements acquire() and owns its admission pool; configure that " +
|
|
382
388
|
"executor's concurrency and queue options instead.");
|
|
383
389
|
}
|
|
390
|
+
// Every structural check has passed, so this is the configuration the
|
|
391
|
+
// deployment runs with. Creating the runtime builds nothing — a Worker may
|
|
392
|
+
// construct its Connecta at global scope, where no fiber may start.
|
|
393
|
+
const runtime = createCoreRuntime(registry, {
|
|
394
|
+
storage,
|
|
395
|
+
logger,
|
|
396
|
+
vault: credentialVault,
|
|
397
|
+
activity: config.activity,
|
|
398
|
+
config: {
|
|
399
|
+
config,
|
|
400
|
+
serverInfo,
|
|
401
|
+
auth: inboundAuth,
|
|
402
|
+
pools,
|
|
403
|
+
executorName: configuredExecutorName,
|
|
404
|
+
},
|
|
405
|
+
});
|
|
384
406
|
const handler = createFetchHandler({
|
|
385
407
|
registry,
|
|
386
408
|
auth: inboundAuth,
|
|
@@ -404,6 +426,7 @@ export function createConnecta(config) {
|
|
|
404
426
|
maxEmittedBlocks: config.execute?.maxEmittedBlocks,
|
|
405
427
|
maxHostCalls: config.execute?.maxHostCalls,
|
|
406
428
|
hostCallTimeoutMs: config.execute?.hostCallTimeoutMs,
|
|
429
|
+
watchdogMs: config.execute?.watchdogMs,
|
|
407
430
|
credentialVault,
|
|
408
431
|
ui: config.ui,
|
|
409
432
|
deploymentInfo: config.deploymentInfo,
|
|
@@ -417,10 +440,18 @@ export function createConnecta(config) {
|
|
|
417
440
|
registry,
|
|
418
441
|
close: async () => {
|
|
419
442
|
closePromise ??= Promise.resolve().then(async () => {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
443
|
+
try {
|
|
444
|
+
requestAdmission.close();
|
|
445
|
+
codeAdmission?.close();
|
|
446
|
+
registry.closeCallAdmission();
|
|
447
|
+
await config.executor?.close?.();
|
|
448
|
+
}
|
|
449
|
+
finally {
|
|
450
|
+
// Last, and whether or not the executor closed cleanly. A fiber
|
|
451
|
+
// already running keeps the services it was given; only a run
|
|
452
|
+
// started after this is refused.
|
|
453
|
+
await disposeEdgeRuntime(runtime);
|
|
454
|
+
}
|
|
424
455
|
});
|
|
425
456
|
await closePromise;
|
|
426
457
|
},
|