@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.
- package/AGENTS.md +58 -30
- package/CHANGELOG.md +317 -1
- package/README.md +5 -6
- package/dist/advertised-schema.js +53 -0
- package/dist/auth/downstream-oauth.js +490 -106
- package/dist/branding.d.ts +31 -2
- package/dist/branding.js +116 -8
- 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 +3 -3
- package/dist/connectors/api.js +10 -2
- package/dist/connectors/guarded-fetch.js +34 -4
- package/dist/connectors/remote-mcp.d.ts +6 -5
- package/dist/connectors/remote-mcp.js +325 -245
- 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/errors.d.ts +11 -3
- package/dist/errors.js +2 -1
- 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 +11 -2
- package/dist/index.js +63 -21
- package/dist/invocation.js +324 -285
- package/dist/meta-tools.js +304 -114
- 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 +109 -2
- package/dist/program-source.js +205 -0
- package/dist/providers/cloudflare.d.ts +14 -2
- package/dist/providers/cloudflare.js +107 -16
- package/dist/providers/linear.d.ts +26 -4
- package/dist/providers/linear.js +19 -4
- package/dist/providers/mixpanel.d.ts +16 -3
- package/dist/providers/mixpanel.js +13 -2
- package/dist/providers/notion.d.ts +8 -1
- package/dist/providers/notion.js +85 -12
- package/dist/providers/revenuecat.d.ts +30 -4
- package/dist/providers/revenuecat.js +70 -5
- package/dist/providers/stripe.d.ts +10 -3
- package/dist/providers/stripe.js +30 -4
- package/dist/providers/vercel.js +12 -2
- package/dist/registry.d.ts +13 -5
- package/dist/registry.js +317 -258
- 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 +64 -7
- package/dist/ui.d.ts +16 -2
- package/dist/ui.js +68 -176
- package/dist/url-safety.js +157 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +368 -182
- package/documentation/auth.md +277 -176
- package/documentation/code-mode.md +479 -329
- package/documentation/meta-tools.md +494 -417
- package/ethos.md +44 -47
- package/examples/worker/AGENTS.md +2 -1
- package/examples/worker/README.md +62 -14
- package/examples/worker/src/d1-storage.ts +116 -0
- package/examples/worker/src/index.ts +18 -21
- package/examples/worker/wrangler.jsonc +16 -4
- package/package.json +11 -4
- package/templates/node/.env.example +3 -3
- package/templates/node/AGENTS.md +5 -4
- package/templates/node/README.md +2 -1
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +23 -22
- 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 -92
- 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 -151
- 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
- package/documentation/call-admission.md +0 -158
- package/documentation/cloudflare.md +0 -471
- package/documentation/connector-guides.md +0 -176
- package/documentation/connectors.md +0 -431
- package/documentation/linear.md +0 -193
- package/documentation/mixpanel.md +0 -160
- package/documentation/notion.md +0 -308
- package/documentation/operations.md +0 -359
- package/documentation/operator-ui.md +0 -135
- package/documentation/optional-modules-upgrade.md +0 -243
- package/documentation/provider-conventions.md +0 -729
- package/documentation/request-admission.md +0 -204
- package/documentation/revenuecat.md +0 -305
- package/documentation/storage-and-credentials.md +0 -254
- package/documentation/stripe.md +0 -262
- package/documentation/upgrading.md +0 -768
- package/documentation/vercel.md +0 -241
|
@@ -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. */
|
|
@@ -222,5 +231,5 @@ export { CONNECTA_VERSION } from "./version.js";
|
|
|
222
231
|
export type { Registry } from "./registry.js";
|
|
223
232
|
export type { RemoteMcpOptions, RemoteMcpAuth, RemoteMcpRedirectPolicy, } from "./connectors/remote-mcp.js";
|
|
224
233
|
export type { ApiOptions, ApiTool } from "./connectors/api.js";
|
|
225
|
-
export type { CatalogDriftCounts, CatalogDriftReport, ConnectaBranding, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
|
|
234
|
+
export type { CatalogDriftCounts, CatalogDriftReport, ConnectaBranding, ConnectaTheme, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
|
|
226
235
|
export type { ActivityActor, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, CatalogDriftActivityEvent, ToolCallActivityEvent, } from "./activity.js";
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,12 @@ import { credentialTestRule, describeCredentialTestMismatch, } from "./credentia
|
|
|
2
2
|
import { Registry } from "./registry.js";
|
|
3
3
|
import { parseConnectorAccess, POOL_NAME_RE } from "./connector-access.js";
|
|
4
4
|
import { createFetchHandler } from "./server.js";
|
|
5
|
-
import { droppedBrandingUrls, droppedUiAuthUrls } from "./branding.js";
|
|
5
|
+
import { droppedBrandingUrls, droppedThemeTokens, droppedUiAuthUrls, } from "./branding.js";
|
|
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(...)");
|
|
@@ -262,6 +257,17 @@ function warnInsecureConfig(config, inboundAuth, logger) {
|
|
|
262
257
|
"used as an href, so it must be an absolute http(s) URL (favicon.href " +
|
|
263
258
|
"may also be a root-relative path). The default is rendered instead.");
|
|
264
259
|
}
|
|
260
|
+
// Theme tokens are written into a `:root` block, so each is gated
|
|
261
|
+
// syntactically and a rejected value takes the stylesheet's default. Same
|
|
262
|
+
// reason as the branding URLs above: the page still renders, so without this
|
|
263
|
+
// line the only evidence is that the operator's color never showed up.
|
|
264
|
+
const droppedTheme = droppedThemeTokens(config.ui?.branding?.theme);
|
|
265
|
+
if (droppedTheme.length > 0) {
|
|
266
|
+
logger.warn(`[connecta] branding ${droppedTheme.join(", ")} dropped: accent must be ` +
|
|
267
|
+
"a hex color, radius a CSS length, the font families a plain " +
|
|
268
|
+
"font-family list, and colorScheme one of system/light/dark. The " +
|
|
269
|
+
"default is rendered instead.");
|
|
270
|
+
}
|
|
265
271
|
// Operator shells render exactly one provider's browser sign-in config — the
|
|
266
272
|
// first that offers one, matching the server route's `find` — and that
|
|
267
273
|
// provider's URLs reach the browser: frontendApiUrl as the loader's
|
|
@@ -285,18 +291,31 @@ function warnInsecureConfig(config, inboundAuth, logger) {
|
|
|
285
291
|
}
|
|
286
292
|
// A credential test hook that cannot test the declared credential shape.
|
|
287
293
|
// The shape picks the hook (see `credentialTestRule`) and the other one is
|
|
288
|
-
// never substituted, so the
|
|
289
|
-
//
|
|
290
|
-
//
|
|
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.
|
|
291
297
|
for (const connector of config.connectors) {
|
|
292
298
|
const { mismatch } = credentialTestRule(connector);
|
|
293
299
|
if (!mismatch)
|
|
294
300
|
continue;
|
|
295
301
|
logger.warn(`[connecta] connector "${connector.id}" cannot test its credential: ` +
|
|
296
|
-
`${describeCredentialTestMismatch(mismatch)}.
|
|
302
|
+
`${describeCredentialTestMismatch(mismatch)}. The connection in the operator UI offers no Test ` +
|
|
297
303
|
`action and POST /ui/credentials/${connector.id}/test answers 400 ` +
|
|
298
304
|
"until the matching hook is implemented.");
|
|
299
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
|
+
}
|
|
300
319
|
// OAuth connectors whose callback cannot perform a state/CSRF check. The
|
|
301
320
|
// public route refuses every callback for these connectors rather than hand
|
|
302
321
|
// an unverified code to finishAuth, so this warning explains why auth cannot
|
|
@@ -320,9 +339,7 @@ export function createConnecta(config) {
|
|
|
320
339
|
'"@cloudflare/codemode" on Workers.');
|
|
321
340
|
}
|
|
322
341
|
const storage = config.storage ?? memoryStorage();
|
|
323
|
-
const logger = config.logger
|
|
324
|
-
? { debug() { }, info() { }, warn() { }, error() { } }
|
|
325
|
-
: config.logger ?? defaultLogger();
|
|
342
|
+
const logger = resolveLogger(config.logger);
|
|
326
343
|
const credentialVault = config.vault;
|
|
327
344
|
const configuredAuth = normalizeAuth(config.auth);
|
|
328
345
|
const serverInfo = {
|
|
@@ -370,6 +387,22 @@ export function createConnecta(config) {
|
|
|
370
387
|
"implements acquire() and owns its admission pool; configure that " +
|
|
371
388
|
"executor's concurrency and queue options instead.");
|
|
372
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
|
+
});
|
|
373
406
|
const handler = createFetchHandler({
|
|
374
407
|
registry,
|
|
375
408
|
auth: inboundAuth,
|
|
@@ -393,6 +426,7 @@ export function createConnecta(config) {
|
|
|
393
426
|
maxEmittedBlocks: config.execute?.maxEmittedBlocks,
|
|
394
427
|
maxHostCalls: config.execute?.maxHostCalls,
|
|
395
428
|
hostCallTimeoutMs: config.execute?.hostCallTimeoutMs,
|
|
429
|
+
watchdogMs: config.execute?.watchdogMs,
|
|
396
430
|
credentialVault,
|
|
397
431
|
ui: config.ui,
|
|
398
432
|
deploymentInfo: config.deploymentInfo,
|
|
@@ -406,10 +440,18 @@ export function createConnecta(config) {
|
|
|
406
440
|
registry,
|
|
407
441
|
close: async () => {
|
|
408
442
|
closePromise ??= Promise.resolve().then(async () => {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
+
}
|
|
413
455
|
});
|
|
414
456
|
await closePromise;
|
|
415
457
|
},
|