@zackbart/connecta 0.15.1 → 0.16.1
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 -20
- package/CHANGELOG.md +653 -0
- package/README.md +25 -5
- package/bin/connecta.mjs +44 -3
- package/dist/access-tokens.d.ts +0 -1
- package/dist/access-tokens.js +0 -1
- package/dist/activity.d.ts +50 -2
- package/dist/activity.js +34 -1
- package/dist/apps-shell.d.ts +0 -1
- package/dist/apps-shell.js +0 -1
- package/dist/auth/bearer.d.ts +0 -1
- package/dist/auth/bearer.js +0 -1
- package/dist/auth/clerk.d.ts +0 -1
- package/dist/auth/clerk.js +45 -9
- package/dist/auth/downstream-oauth.d.ts +0 -1
- package/dist/auth/downstream-oauth.js +0 -1
- package/dist/call-admission.d.ts +0 -1
- package/dist/call-admission.js +0 -1
- package/dist/catalog-drift.d.ts +99 -0
- package/dist/catalog-drift.js +251 -0
- package/dist/catalog-fingerprint.d.ts +0 -1
- package/dist/catalog-fingerprint.js +0 -1
- package/dist/catalog-limits.d.ts +0 -1
- package/dist/catalog-limits.js +0 -1
- package/dist/catalog-service.d.ts +0 -1
- package/dist/catalog-service.js +41 -5
- package/dist/catalog.d.ts +11 -1
- package/dist/catalog.js +20 -1
- package/dist/concurrency.d.ts +0 -1
- package/dist/concurrency.js +0 -1
- package/dist/connector-scope.d.ts +0 -1
- package/dist/connector-scope.js +0 -1
- package/dist/connectors/api.d.ts +29 -21
- package/dist/connectors/api.js +45 -19
- package/dist/connectors/guarded-fetch.d.ts +106 -0
- package/dist/connectors/guarded-fetch.js +289 -0
- package/dist/connectors/remote-mcp.d.ts +0 -1
- package/dist/connectors/remote-mcp.js +0 -1
- package/dist/credentials.d.ts +0 -1
- package/dist/credentials.js +0 -1
- package/dist/errors.d.ts +30 -3
- package/dist/errors.js +1 -1
- package/dist/execute.d.ts +0 -1
- package/dist/execute.js +0 -1
- package/dist/executor-admission.d.ts +11 -1
- package/dist/executor-admission.js +28 -1
- package/dist/executor-result.d.ts +0 -1
- package/dist/executor-result.js +0 -1
- package/dist/executors/quickjs-child.d.ts +0 -1
- package/dist/executors/quickjs-child.js +0 -1
- package/dist/executors/quickjs-protocol.d.ts +0 -1
- package/dist/executors/quickjs-protocol.js +0 -1
- package/dist/executors/quickjs-runtime.d.ts +0 -1
- package/dist/executors/quickjs-runtime.js +0 -1
- package/dist/executors/quickjs.d.ts +0 -1
- package/dist/executors/quickjs.js +2 -1
- package/dist/favicon.d.ts +0 -1
- package/dist/favicon.js +0 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +24 -7
- package/dist/invocation.d.ts +0 -1
- package/dist/invocation.js +0 -1
- package/dist/json-schema.d.ts +0 -1
- package/dist/json-schema.js +0 -1
- package/dist/mcp-result.d.ts +0 -1
- package/dist/mcp-result.js +0 -1
- package/dist/meta-tools.d.ts +0 -1
- package/dist/meta-tools.js +0 -1
- package/dist/node.d.ts +0 -1
- package/dist/node.js +0 -1
- package/dist/operator-ui/generated.d.ts +2 -3
- package/dist/operator-ui/generated.js +3 -4
- package/dist/operator-ui/model.d.ts +10 -1
- package/dist/operator-ui/model.js +0 -1
- package/dist/operator-ui/view.d.ts +167 -0
- package/dist/operator-ui/view.js +270 -0
- package/dist/providers/cloudflare.d.ts +0 -1
- package/dist/providers/cloudflare.js +261 -299
- package/dist/providers/linear.d.ts +26 -5
- package/dist/providers/linear.js +32 -61
- package/dist/providers/mixpanel.d.ts +35 -4
- package/dist/providers/mixpanel.js +53 -79
- package/dist/providers/notion.d.ts +0 -1
- package/dist/providers/notion.js +87 -42
- package/dist/providers/stripe.d.ts +13 -1
- package/dist/providers/stripe.js +31 -60
- package/dist/registry.d.ts +34 -2
- package/dist/registry.js +85 -5
- package/dist/retired-toolkits.d.ts +0 -1
- package/dist/retired-toolkits.js +0 -1
- package/dist/routes/access-tokens.d.ts +0 -1
- package/dist/routes/access-tokens.js +0 -1
- package/dist/routes/activity.d.ts +0 -1
- package/dist/routes/activity.js +0 -1
- package/dist/routes/credentials.d.ts +0 -1
- package/dist/routes/credentials.js +0 -1
- package/dist/routes/mcp.d.ts +0 -1
- package/dist/routes/mcp.js +0 -1
- package/dist/routes/oauth.d.ts +0 -1
- package/dist/routes/oauth.js +0 -1
- package/dist/routes/shared.d.ts +2 -1
- package/dist/routes/shared.js +0 -1
- package/dist/routes/ui.d.ts +0 -1
- package/dist/routes/ui.js +0 -1
- package/dist/server.d.ts +0 -1
- package/dist/server.js +11 -1
- package/dist/skills.d.ts +0 -1
- package/dist/skills.js +0 -1
- package/dist/storage/file.d.ts +0 -1
- package/dist/storage/file.js +0 -1
- package/dist/storage/memory.d.ts +0 -1
- package/dist/storage/memory.js +0 -1
- package/dist/timeout.d.ts +0 -1
- package/dist/timeout.js +0 -1
- package/dist/tool-safety.d.ts +0 -1
- package/dist/tool-safety.js +0 -1
- package/dist/types.d.ts +45 -1
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +0 -1
- package/dist/ui.js +13 -137
- package/dist/validate.d.ts +13 -15
- package/dist/validate.js +24 -11
- package/dist/version.d.ts +1 -2
- package/dist/version.js +1 -2
- package/documentation/architecture.md +186 -5
- package/documentation/auth.md +11 -0
- package/documentation/call-admission.md +142 -6
- package/documentation/cloudflare.md +92 -10
- package/documentation/code-first-exploration.md +2 -2
- package/documentation/code-mode.md +14 -14
- package/documentation/connector-guides.md +172 -5
- package/documentation/connectors.md +89 -0
- package/documentation/linear.md +20 -2
- package/documentation/mcp-ui-design.md +2 -2
- package/documentation/meta-tools.md +7 -1
- package/documentation/mixpanel.md +42 -9
- package/documentation/notion.md +23 -2
- package/documentation/operations.md +325 -5
- package/documentation/operator-ui.md +120 -5
- package/documentation/provider-audit.md +160 -0
- package/documentation/provider-conventions.md +667 -0
- package/documentation/request-admission.md +167 -5
- package/documentation/rich-output-design.md +1 -2
- package/documentation/stripe.md +15 -0
- package/documentation/upgrading.md +454 -0
- package/ethos.md +14 -9
- package/examples/worker/README.md +102 -12
- package/examples/worker/src/index.ts +46 -1
- package/examples/worker/wrangler.jsonc +14 -1
- package/package.json +10 -6
- package/templates/node/.dockerignore +10 -0
- package/templates/node/.env.example +40 -3
- package/templates/node/AGENTS.md +16 -1
- package/templates/node/Dockerfile +49 -0
- package/templates/node/README.md +117 -2
- package/templates/node/docker-compose.yml +39 -0
- package/templates/node/package.json +1 -1
- package/templates/node/src/file-activity.ts +182 -0
- package/templates/node/src/index.ts +80 -4
- package/assets/connecta-clay-hero.png +0 -0
- package/dist/access-tokens.d.ts.map +0 -1
- package/dist/access-tokens.js.map +0 -1
- package/dist/activity.d.ts.map +0 -1
- package/dist/activity.js.map +0 -1
- package/dist/apps-shell.d.ts.map +0 -1
- package/dist/apps-shell.js.map +0 -1
- package/dist/auth/bearer.d.ts.map +0 -1
- package/dist/auth/bearer.js.map +0 -1
- package/dist/auth/clerk.d.ts.map +0 -1
- package/dist/auth/clerk.js.map +0 -1
- package/dist/auth/downstream-oauth.d.ts.map +0 -1
- package/dist/auth/downstream-oauth.js.map +0 -1
- package/dist/call-admission.d.ts.map +0 -1
- package/dist/call-admission.js.map +0 -1
- package/dist/catalog-fingerprint.d.ts.map +0 -1
- package/dist/catalog-fingerprint.js.map +0 -1
- package/dist/catalog-limits.d.ts.map +0 -1
- package/dist/catalog-limits.js.map +0 -1
- package/dist/catalog-service.d.ts.map +0 -1
- package/dist/catalog-service.js.map +0 -1
- package/dist/catalog.d.ts.map +0 -1
- package/dist/catalog.js.map +0 -1
- package/dist/concurrency.d.ts.map +0 -1
- package/dist/concurrency.js.map +0 -1
- package/dist/connector-scope.d.ts.map +0 -1
- package/dist/connector-scope.js.map +0 -1
- package/dist/connectors/api.d.ts.map +0 -1
- package/dist/connectors/api.js.map +0 -1
- package/dist/connectors/remote-mcp.d.ts.map +0 -1
- package/dist/connectors/remote-mcp.js.map +0 -1
- package/dist/credentials.d.ts.map +0 -1
- package/dist/credentials.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/execute.d.ts.map +0 -1
- package/dist/execute.js.map +0 -1
- package/dist/executor-admission.d.ts.map +0 -1
- package/dist/executor-admission.js.map +0 -1
- package/dist/executor-result.d.ts.map +0 -1
- package/dist/executor-result.js.map +0 -1
- package/dist/executors/quickjs-child.d.ts.map +0 -1
- package/dist/executors/quickjs-child.js.map +0 -1
- package/dist/executors/quickjs-protocol.d.ts.map +0 -1
- package/dist/executors/quickjs-protocol.js.map +0 -1
- package/dist/executors/quickjs-runtime.d.ts.map +0 -1
- package/dist/executors/quickjs-runtime.js.map +0 -1
- package/dist/executors/quickjs.d.ts.map +0 -1
- package/dist/executors/quickjs.js.map +0 -1
- package/dist/favicon.d.ts.map +0 -1
- package/dist/favicon.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/invocation.d.ts.map +0 -1
- package/dist/invocation.js.map +0 -1
- package/dist/json-schema.d.ts.map +0 -1
- package/dist/json-schema.js.map +0 -1
- package/dist/mcp-result.d.ts.map +0 -1
- package/dist/mcp-result.js.map +0 -1
- package/dist/meta-tools.d.ts.map +0 -1
- package/dist/meta-tools.js.map +0 -1
- package/dist/node.d.ts.map +0 -1
- package/dist/node.js.map +0 -1
- package/dist/operator-ui/generated.d.ts.map +0 -1
- package/dist/operator-ui/generated.js.map +0 -1
- package/dist/operator-ui/model.d.ts.map +0 -1
- package/dist/operator-ui/model.js.map +0 -1
- package/dist/providers/cloudflare.d.ts.map +0 -1
- package/dist/providers/cloudflare.js.map +0 -1
- package/dist/providers/linear.d.ts.map +0 -1
- package/dist/providers/linear.js.map +0 -1
- package/dist/providers/mixpanel.d.ts.map +0 -1
- package/dist/providers/mixpanel.js.map +0 -1
- package/dist/providers/notion.d.ts.map +0 -1
- package/dist/providers/notion.js.map +0 -1
- package/dist/providers/stripe.d.ts.map +0 -1
- package/dist/providers/stripe.js.map +0 -1
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/retired-toolkits.d.ts.map +0 -1
- package/dist/retired-toolkits.js.map +0 -1
- package/dist/routes/access-tokens.d.ts.map +0 -1
- package/dist/routes/access-tokens.js.map +0 -1
- package/dist/routes/activity.d.ts.map +0 -1
- package/dist/routes/activity.js.map +0 -1
- package/dist/routes/credentials.d.ts.map +0 -1
- package/dist/routes/credentials.js.map +0 -1
- package/dist/routes/mcp.d.ts.map +0 -1
- package/dist/routes/mcp.js.map +0 -1
- package/dist/routes/oauth.d.ts.map +0 -1
- package/dist/routes/oauth.js.map +0 -1
- package/dist/routes/shared.d.ts.map +0 -1
- package/dist/routes/shared.js.map +0 -1
- package/dist/routes/ui.d.ts.map +0 -1
- package/dist/routes/ui.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js.map +0 -1
- package/dist/storage/file.d.ts.map +0 -1
- package/dist/storage/file.js.map +0 -1
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js.map +0 -1
- package/dist/timeout.d.ts.map +0 -1
- package/dist/timeout.js.map +0 -1
- package/dist/tool-safety.d.ts.map +0 -1
- package/dist/tool-safety.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js.map +0 -1
- package/examples/node/README.md +0 -52
- package/examples/node/src/index.ts +0 -71
- package/src/access-tokens.ts +0 -289
- package/src/activity.ts +0 -234
- package/src/apps-shell.ts +0 -370
- package/src/auth/bearer.ts +0 -61
- package/src/auth/clerk.ts +0 -553
- package/src/auth/downstream-oauth.ts +0 -575
- package/src/call-admission.ts +0 -521
- package/src/catalog-fingerprint.ts +0 -52
- package/src/catalog-limits.ts +0 -11
- package/src/catalog-service.ts +0 -1153
- package/src/catalog.ts +0 -790
- package/src/concurrency.ts +0 -39
- package/src/connector-scope.ts +0 -66
- package/src/connectors/api.ts +0 -159
- package/src/connectors/remote-mcp.ts +0 -1090
- package/src/credentials.ts +0 -428
- package/src/errors.ts +0 -364
- package/src/execute.ts +0 -1406
- package/src/executor-admission.ts +0 -328
- package/src/executor-result.ts +0 -107
- package/src/executors/quickjs-child.ts +0 -172
- package/src/executors/quickjs-protocol.ts +0 -99
- package/src/executors/quickjs-runtime.ts +0 -470
- package/src/executors/quickjs.ts +0 -776
- package/src/favicon.ts +0 -53
- package/src/index.ts +0 -666
- package/src/invocation.ts +0 -655
- package/src/json-schema.ts +0 -11
- package/src/mcp-result.ts +0 -43
- package/src/meta-tools.ts +0 -1607
- package/src/node.ts +0 -206
- package/src/operator-ui/browser.css +0 -423
- package/src/operator-ui/browser.ts +0 -1281
- package/src/operator-ui/generated.ts +0 -4
- package/src/operator-ui/model.ts +0 -111
- package/src/providers/cloudflare.ts +0 -3999
- package/src/providers/linear.ts +0 -302
- package/src/providers/mixpanel.ts +0 -229
- package/src/providers/notion.ts +0 -1879
- package/src/providers/stripe.ts +0 -307
- package/src/registry.ts +0 -1085
- package/src/retired-toolkits.ts +0 -14
- package/src/routes/access-tokens.ts +0 -115
- package/src/routes/activity.ts +0 -215
- package/src/routes/credentials.ts +0 -254
- package/src/routes/mcp.ts +0 -429
- package/src/routes/oauth.ts +0 -322
- package/src/routes/shared.ts +0 -247
- package/src/routes/ui.ts +0 -152
- package/src/server.ts +0 -195
- package/src/skills.ts +0 -271
- package/src/storage/file.ts +0 -123
- package/src/storage/memory.ts +0 -44
- package/src/timeout.ts +0 -84
- package/src/tool-safety.ts +0 -15
- package/src/types.ts +0 -523
- package/src/ui.ts +0 -744
- package/src/validate.ts +0 -387
- package/src/version.ts +0 -7
package/src/node.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { createServer } from "node:http";
|
|
2
|
-
import type { IncomingMessage, Server, ServerResponse } from "node:http";
|
|
3
|
-
import { Readable } from "node:stream";
|
|
4
|
-
import { pipeline } from "node:stream/promises";
|
|
5
|
-
import type { Connecta } from "./index.js";
|
|
6
|
-
|
|
7
|
-
export { fileStorage } from "./storage/file.js";
|
|
8
|
-
export type { FileStorageOptions } from "./storage/file.js";
|
|
9
|
-
|
|
10
|
-
/** 10 MiB. Tool arguments are JSON; nothing legitimate approaches this. */
|
|
11
|
-
const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
12
|
-
|
|
13
|
-
export interface ListenOptions {
|
|
14
|
-
port: number;
|
|
15
|
-
/** Interface to bind. Defaults to Node's own (all interfaces). */
|
|
16
|
-
host?: string;
|
|
17
|
-
/** Reject request bodies larger than this with 413. Default 10 MiB. */
|
|
18
|
-
maxBodyBytes?: number;
|
|
19
|
-
/**
|
|
20
|
-
* Stop accepting connections on SIGTERM/SIGINT, let in-flight requests
|
|
21
|
-
* finish, drain deferred work, then exit. Default true — Docker sends
|
|
22
|
-
* SIGTERM on every `compose up` recreate and Node's default is to die
|
|
23
|
-
* mid-request. Set false to install your own handlers.
|
|
24
|
-
*/
|
|
25
|
-
gracefulShutdown?: boolean;
|
|
26
|
-
/** Shutdown deadline before forcing exit. Default 10s (Docker's own grace). */
|
|
27
|
-
shutdownTimeoutMs?: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const BODY_TOO_LARGE = Symbol("body-too-large");
|
|
31
|
-
|
|
32
|
-
async function toRequest(
|
|
33
|
-
req: IncomingMessage,
|
|
34
|
-
maxBodyBytes: number,
|
|
35
|
-
signal: AbortSignal,
|
|
36
|
-
): Promise<Request | typeof BODY_TOO_LARGE> {
|
|
37
|
-
const host = req.headers.host ?? "localhost";
|
|
38
|
-
const proto =
|
|
39
|
-
(req.headers["x-forwarded-proto"] as string | undefined) ?? "http";
|
|
40
|
-
const url = `${proto}://${host}${req.url ?? "/"}`;
|
|
41
|
-
const method = req.method ?? "GET";
|
|
42
|
-
const headers = new Headers();
|
|
43
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
44
|
-
if (value == null) continue;
|
|
45
|
-
headers.set(key, Array.isArray(value) ? value.join(", ") : value);
|
|
46
|
-
}
|
|
47
|
-
let body: Uint8Array | undefined;
|
|
48
|
-
if (method !== "GET" && method !== "HEAD") {
|
|
49
|
-
const chunks: Buffer[] = [];
|
|
50
|
-
let size = 0;
|
|
51
|
-
for await (const chunk of req) {
|
|
52
|
-
size += (chunk as Buffer).length;
|
|
53
|
-
// Stop reading as soon as the cap is passed rather than buffering the
|
|
54
|
-
// rest of a body we have already decided to reject.
|
|
55
|
-
if (size > maxBodyBytes) return BODY_TOO_LARGE;
|
|
56
|
-
chunks.push(chunk as Buffer);
|
|
57
|
-
}
|
|
58
|
-
if (chunks.length) body = new Uint8Array(Buffer.concat(chunks));
|
|
59
|
-
}
|
|
60
|
-
return new Request(url, {
|
|
61
|
-
method,
|
|
62
|
-
headers,
|
|
63
|
-
body,
|
|
64
|
-
signal,
|
|
65
|
-
// Required by Node's fetch when sending a body stream.
|
|
66
|
-
...(body ? { duplex: "half" } : {}),
|
|
67
|
-
} as RequestInit);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function writeResponse(
|
|
71
|
-
res: ServerResponse,
|
|
72
|
-
response: Response,
|
|
73
|
-
): Promise<void> {
|
|
74
|
-
res.statusCode = response.status;
|
|
75
|
-
response.headers.forEach((value, key) => res.setHeader(key, value));
|
|
76
|
-
if (!response.body) {
|
|
77
|
-
res.end();
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
// Stream rather than buffer: a connector-served route may return a large
|
|
81
|
-
// proxied file body, and materializing it would hold the whole thing in
|
|
82
|
-
// memory before the first byte reaches the client.
|
|
83
|
-
await pipeline(
|
|
84
|
-
Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]),
|
|
85
|
-
res,
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Serve a Connecta over node:http. Thin adapter: IncomingMessage → Request,
|
|
91
|
-
* Response → ServerResponse, plus the process-level concerns a long-running
|
|
92
|
-
* container needs (body cap, response streaming, graceful shutdown). No
|
|
93
|
-
* dependencies beyond node core.
|
|
94
|
-
*/
|
|
95
|
-
export function listen(
|
|
96
|
-
connecta: Connecta,
|
|
97
|
-
portOrOptions: number | ListenOptions,
|
|
98
|
-
): Server {
|
|
99
|
-
const opts: ListenOptions =
|
|
100
|
-
typeof portOrOptions === "number" ? { port: portOrOptions } : portOrOptions;
|
|
101
|
-
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
102
|
-
|
|
103
|
-
// Node has no ExecutionContext, so deferred work (activity sinks) would
|
|
104
|
-
// otherwise be an untracked floating promise. Track it here and drain it on
|
|
105
|
-
// shutdown so both runtimes behave the same.
|
|
106
|
-
const pending = new Set<Promise<unknown>>();
|
|
107
|
-
const ctx = {
|
|
108
|
-
waitUntil(promise: Promise<unknown>): void {
|
|
109
|
-
pending.add(promise);
|
|
110
|
-
void promise.finally(() => pending.delete(promise));
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const server = createServer((req, res) => {
|
|
115
|
-
void (async () => {
|
|
116
|
-
const controller = new AbortController();
|
|
117
|
-
const abortRequest = () => {
|
|
118
|
-
if (!controller.signal.aborted) {
|
|
119
|
-
controller.abort(new Error("HTTP client disconnected."));
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
const abortIncompleteRequest = () => {
|
|
123
|
-
if (!req.complete) abortRequest();
|
|
124
|
-
};
|
|
125
|
-
const abortIncompleteResponse = () => {
|
|
126
|
-
if (!res.writableFinished) abortRequest();
|
|
127
|
-
};
|
|
128
|
-
req.once("aborted", abortRequest);
|
|
129
|
-
req.once("close", abortIncompleteRequest);
|
|
130
|
-
res.once("close", abortIncompleteResponse);
|
|
131
|
-
try {
|
|
132
|
-
const request = await toRequest(
|
|
133
|
-
req,
|
|
134
|
-
maxBodyBytes,
|
|
135
|
-
controller.signal,
|
|
136
|
-
);
|
|
137
|
-
if (request === BODY_TOO_LARGE) {
|
|
138
|
-
res.statusCode = 413;
|
|
139
|
-
// The request stream was abandoned mid-body, so this connection
|
|
140
|
-
// cannot be reused — say so rather than leaving the client to
|
|
141
|
-
// discover it as a reset.
|
|
142
|
-
res.setHeader("Connection", "close");
|
|
143
|
-
res.end("Payload Too Large");
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const response = await connecta.fetch(request, undefined, ctx);
|
|
147
|
-
await writeResponse(res, response);
|
|
148
|
-
} catch (error) {
|
|
149
|
-
// A client that deliberately went away can make either the request
|
|
150
|
-
// handler or response pipeline reject. The request's abort signal is
|
|
151
|
-
// the authoritative classification: there is no caller left to answer,
|
|
152
|
-
// and logging an expected disconnect would turn cancellation into an
|
|
153
|
-
// error-log spam vector.
|
|
154
|
-
if (controller.signal.aborted) return;
|
|
155
|
-
// A headless deployment has nothing else to go on; never swallow this.
|
|
156
|
-
console.error("[connecta] request failed", error);
|
|
157
|
-
if (res.headersSent) {
|
|
158
|
-
// Mid-stream failure: appending an error string here would corrupt
|
|
159
|
-
// the partial body the client has already begun reading. Cutting
|
|
160
|
-
// the connection is the only honest signal left.
|
|
161
|
-
res.destroy();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
res.statusCode = 500;
|
|
165
|
-
res.end("Internal Server Error");
|
|
166
|
-
} finally {
|
|
167
|
-
req.removeListener("aborted", abortRequest);
|
|
168
|
-
req.removeListener("close", abortIncompleteRequest);
|
|
169
|
-
res.removeListener("close", abortIncompleteResponse);
|
|
170
|
-
}
|
|
171
|
-
})();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
if (opts.gracefulShutdown !== false) {
|
|
175
|
-
const timeoutMs = opts.shutdownTimeoutMs ?? 10_000;
|
|
176
|
-
let shuttingDown = false;
|
|
177
|
-
const shutdown = (signal: string): void => {
|
|
178
|
-
if (shuttingDown) return;
|
|
179
|
-
shuttingDown = true;
|
|
180
|
-
console.info(`[connecta] ${signal} received, draining`);
|
|
181
|
-
const forced = setTimeout(() => {
|
|
182
|
-
console.warn("[connecta] shutdown timed out, exiting");
|
|
183
|
-
process.exit(1);
|
|
184
|
-
}, timeoutMs);
|
|
185
|
-
forced.unref?.();
|
|
186
|
-
// Stop queued/running sandbox work now, not after server.close has
|
|
187
|
-
// waited for the very requests those children are holding open.
|
|
188
|
-
const executorClose = connecta.close();
|
|
189
|
-
// close() alone waits on idle keep-alive sockets, so a single browser
|
|
190
|
-
// tab would stall every shutdown until the force-exit deadline.
|
|
191
|
-
server.closeIdleConnections();
|
|
192
|
-
server.close(() => {
|
|
193
|
-
void Promise.allSettled([...pending, executorClose]).then(() => {
|
|
194
|
-
clearTimeout(forced);
|
|
195
|
-
process.exit(0);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
};
|
|
199
|
-
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
200
|
-
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (opts.host) server.listen(opts.port, opts.host);
|
|
204
|
-
else server.listen(opts.port);
|
|
205
|
-
return server;
|
|
206
|
-
}
|
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
color-scheme: light;
|
|
3
|
-
--ink: #000;
|
|
4
|
-
--paper: #fff;
|
|
5
|
-
--rule: #ccc;
|
|
6
|
-
--muted: #666;
|
|
7
|
-
--trace: #f5f5f5;
|
|
8
|
-
--shell: 70rem;
|
|
9
|
-
--pad: 1rem;
|
|
10
|
-
--gap: 1.5rem;
|
|
11
|
-
--sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
12
|
-
--mono: ui-monospace, "SF Mono", Menlo, Monaco, "Cascadia Code", Consolas,
|
|
13
|
-
monospace;
|
|
14
|
-
}
|
|
15
|
-
* { border-radius: 0; box-sizing: border-box; }
|
|
16
|
-
html {
|
|
17
|
-
background: var(--paper);
|
|
18
|
-
color: var(--ink);
|
|
19
|
-
font-family: var(--sans);
|
|
20
|
-
font-size: 16px;
|
|
21
|
-
line-height: 1.5;
|
|
22
|
-
-webkit-font-smoothing: antialiased;
|
|
23
|
-
text-rendering: optimizeLegibility;
|
|
24
|
-
}
|
|
25
|
-
body { margin: 0; min-height: 100vh; }
|
|
26
|
-
::selection { background: var(--ink); color: var(--paper); }
|
|
27
|
-
:is(h1, h2, h3, p, ul, ol) { margin: 0; padding: 0; }
|
|
28
|
-
:is(h1, h2, h3) { font-size: inherit; font-weight: 400; }
|
|
29
|
-
:is(ul, ol) { list-style: none; }
|
|
30
|
-
a { color: inherit; }
|
|
31
|
-
button, input { font: inherit; }
|
|
32
|
-
button {
|
|
33
|
-
background: none;
|
|
34
|
-
border: 0;
|
|
35
|
-
color: inherit;
|
|
36
|
-
cursor: pointer;
|
|
37
|
-
margin: 0;
|
|
38
|
-
padding: 0;
|
|
39
|
-
text-align: left;
|
|
40
|
-
}
|
|
41
|
-
button:disabled { cursor: wait; opacity: .5; }
|
|
42
|
-
input {
|
|
43
|
-
background: var(--paper);
|
|
44
|
-
border: 1px solid var(--rule);
|
|
45
|
-
color: var(--ink);
|
|
46
|
-
min-height: 2rem;
|
|
47
|
-
padding: .2rem .5rem;
|
|
48
|
-
}
|
|
49
|
-
input:focus-visible { outline-offset: -1px; }
|
|
50
|
-
:is(a, button, input, summary):focus-visible {
|
|
51
|
-
outline: 1px solid var(--ink);
|
|
52
|
-
}
|
|
53
|
-
:is(a, button, summary):focus-visible { outline-offset: 2px; }
|
|
54
|
-
.skip-link {
|
|
55
|
-
background: var(--paper);
|
|
56
|
-
left: var(--pad);
|
|
57
|
-
padding: .5rem;
|
|
58
|
-
position: fixed;
|
|
59
|
-
top: -4rem;
|
|
60
|
-
z-index: 10;
|
|
61
|
-
}
|
|
62
|
-
.skip-link:focus { top: var(--pad); }
|
|
63
|
-
|
|
64
|
-
.shell {
|
|
65
|
-
margin: 0 auto;
|
|
66
|
-
max-width: var(--shell);
|
|
67
|
-
padding-left: var(--pad);
|
|
68
|
-
padding-right: var(--pad);
|
|
69
|
-
}
|
|
70
|
-
.pgrid {
|
|
71
|
-
column-gap: var(--gap);
|
|
72
|
-
display: grid;
|
|
73
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
74
|
-
row-gap: 1rem;
|
|
75
|
-
}
|
|
76
|
-
.pcap { grid-column: 1; }
|
|
77
|
-
.pbody { grid-column: 2 / -1; min-width: 0; }
|
|
78
|
-
.cap, .meta { color: var(--muted); font-size: .9em; }
|
|
79
|
-
.mono { font-family: var(--mono); font-size: .78rem; }
|
|
80
|
-
.hidden { display: none !important; }
|
|
81
|
-
.visually-hidden {
|
|
82
|
-
clip: rect(0 0 0 0);
|
|
83
|
-
clip-path: inset(50%);
|
|
84
|
-
height: 1px;
|
|
85
|
-
overflow: hidden;
|
|
86
|
-
position: absolute;
|
|
87
|
-
white-space: nowrap;
|
|
88
|
-
width: 1px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.masthead {
|
|
92
|
-
align-items: start;
|
|
93
|
-
padding-bottom: var(--pad);
|
|
94
|
-
padding-top: var(--pad);
|
|
95
|
-
}
|
|
96
|
-
.brand {
|
|
97
|
-
font-weight: 500;
|
|
98
|
-
grid-column: 1;
|
|
99
|
-
text-decoration: none;
|
|
100
|
-
}
|
|
101
|
-
.mast-nav {
|
|
102
|
-
display: flex;
|
|
103
|
-
gap: var(--gap);
|
|
104
|
-
grid-column: 2 / -1;
|
|
105
|
-
justify-content: space-between;
|
|
106
|
-
min-width: 0;
|
|
107
|
-
}
|
|
108
|
-
.mast-actions {
|
|
109
|
-
display: flex;
|
|
110
|
-
gap: var(--gap);
|
|
111
|
-
justify-content: flex-end;
|
|
112
|
-
min-width: 0;
|
|
113
|
-
}
|
|
114
|
-
.page-nav,
|
|
115
|
-
.session-actions {
|
|
116
|
-
display: flex;
|
|
117
|
-
flex-wrap: wrap;
|
|
118
|
-
gap: .5rem var(--gap);
|
|
119
|
-
}
|
|
120
|
-
.mast-actions :is(a, button) {
|
|
121
|
-
align-items: center;
|
|
122
|
-
display: inline-flex;
|
|
123
|
-
min-height: 2rem;
|
|
124
|
-
}
|
|
125
|
-
.navlink,
|
|
126
|
-
.linklike {
|
|
127
|
-
text-decoration: underline;
|
|
128
|
-
text-decoration-thickness: 1.5px;
|
|
129
|
-
text-underline-offset: .22em;
|
|
130
|
-
}
|
|
131
|
-
.navlink { text-decoration-color: transparent; }
|
|
132
|
-
.navlink:hover,
|
|
133
|
-
.navlink:focus-visible,
|
|
134
|
-
.navlink[aria-current="page"] { text-decoration-color: currentColor; }
|
|
135
|
-
.linklike { text-decoration-color: currentColor; }
|
|
136
|
-
.linklike:hover,
|
|
137
|
-
.linklike:focus-visible { text-decoration-color: transparent; }
|
|
138
|
-
|
|
139
|
-
.page { padding-bottom: 5rem; }
|
|
140
|
-
.lead { margin-top: 6rem; }
|
|
141
|
-
.section,
|
|
142
|
-
.section + .section { margin-top: 3rem; }
|
|
143
|
-
.lead-copy,
|
|
144
|
-
.body-copy { max-width: 34em; }
|
|
145
|
-
.lead-copy > * + *,
|
|
146
|
-
.body-copy > * + * { margin-top: 1.5rem; }
|
|
147
|
-
.row,
|
|
148
|
-
.actions {
|
|
149
|
-
align-items: center;
|
|
150
|
-
display: flex;
|
|
151
|
-
flex-wrap: wrap;
|
|
152
|
-
gap: var(--gap);
|
|
153
|
-
}
|
|
154
|
-
.row input { flex: 1; min-width: 12rem; }
|
|
155
|
-
|
|
156
|
-
.gate-actions { margin-top: 1.5rem; }
|
|
157
|
-
#err { margin-top: 1.5rem; text-decoration: underline; }
|
|
158
|
-
|
|
159
|
-
.endpoint { border-bottom: 1px solid var(--rule); border-top: 1px solid var(--rule); }
|
|
160
|
-
.endpoint-row {
|
|
161
|
-
align-items: baseline;
|
|
162
|
-
display: flex;
|
|
163
|
-
gap: var(--gap);
|
|
164
|
-
min-width: 0;
|
|
165
|
-
padding: .75rem 0;
|
|
166
|
-
}
|
|
167
|
-
.endpoint-row code {
|
|
168
|
-
flex: 1;
|
|
169
|
-
min-width: 0;
|
|
170
|
-
overflow-x: auto;
|
|
171
|
-
white-space: nowrap;
|
|
172
|
-
}
|
|
173
|
-
.endpoint-row button { flex: none; }
|
|
174
|
-
|
|
175
|
-
.connector-tools { border-bottom: 1px solid var(--rule); }
|
|
176
|
-
.toolbar { margin-bottom: 1.5rem; }
|
|
177
|
-
.toolbar input { flex-basis: 18rem; }
|
|
178
|
-
#notice { margin-bottom: .75rem; }
|
|
179
|
-
#notice:empty { display: none; }
|
|
180
|
-
#notice:not(:empty) { text-decoration: underline; }
|
|
181
|
-
#oauthNotice { margin-bottom: .75rem; }
|
|
182
|
-
#oauthNotice:empty { display: none; }
|
|
183
|
-
.error-notice, .msg { text-decoration: underline; }
|
|
184
|
-
.card,
|
|
185
|
-
.credential-card,
|
|
186
|
-
.activity-item {
|
|
187
|
-
padding-left: 1.25rem;
|
|
188
|
-
position: relative;
|
|
189
|
-
}
|
|
190
|
-
.card::before,
|
|
191
|
-
.credential-card::before,
|
|
192
|
-
.activity-item::before {
|
|
193
|
-
background: var(--rule);
|
|
194
|
-
bottom: 0;
|
|
195
|
-
content: "";
|
|
196
|
-
left: .25rem;
|
|
197
|
-
position: absolute;
|
|
198
|
-
top: 0;
|
|
199
|
-
width: 1px;
|
|
200
|
-
}
|
|
201
|
-
.card { border-top: 1px solid var(--rule); padding-bottom: .75rem; padding-top: .75rem; }
|
|
202
|
-
.connector-head {
|
|
203
|
-
display: grid;
|
|
204
|
-
gap: var(--gap);
|
|
205
|
-
grid-template-columns: minmax(0, 2fr) minmax(10rem, 1fr);
|
|
206
|
-
}
|
|
207
|
-
.connector-title {
|
|
208
|
-
align-items: baseline;
|
|
209
|
-
display: flex;
|
|
210
|
-
gap: .5rem;
|
|
211
|
-
}
|
|
212
|
-
.connector-title .dot,
|
|
213
|
-
.activity-stamp .dot {
|
|
214
|
-
margin-left: -1.25rem;
|
|
215
|
-
}
|
|
216
|
-
.activity-stamp {
|
|
217
|
-
align-items: baseline;
|
|
218
|
-
display: flex;
|
|
219
|
-
gap: .75rem;
|
|
220
|
-
}
|
|
221
|
-
.card h2 { overflow-wrap: anywhere; }
|
|
222
|
-
.connector-state { text-align: right; }
|
|
223
|
-
.dot {
|
|
224
|
-
background: var(--paper);
|
|
225
|
-
border: 1px solid var(--ink);
|
|
226
|
-
display: inline-block;
|
|
227
|
-
flex: none;
|
|
228
|
-
height: .5rem;
|
|
229
|
-
width: .5rem;
|
|
230
|
-
z-index: 1;
|
|
231
|
-
}
|
|
232
|
-
.dot.ok { background: var(--ink); }
|
|
233
|
-
.dot.auth_required {
|
|
234
|
-
background: linear-gradient(90deg, var(--ink) 50%, var(--paper) 50%);
|
|
235
|
-
}
|
|
236
|
-
.connector-description { margin-top: .25rem; max-width: 40rem; }
|
|
237
|
-
.connector-message,
|
|
238
|
-
.connector-auth { margin-top: .75rem; }
|
|
239
|
-
.credential-ledger { border-bottom: 1px solid var(--rule); }
|
|
240
|
-
.credential-card { border-top: 1px solid var(--rule); padding-bottom: .75rem; padding-top: .75rem; }
|
|
241
|
-
.credential-head {
|
|
242
|
-
align-items: baseline;
|
|
243
|
-
display: flex;
|
|
244
|
-
flex-wrap: wrap;
|
|
245
|
-
gap: .25rem var(--gap);
|
|
246
|
-
justify-content: space-between;
|
|
247
|
-
}
|
|
248
|
-
.credential-copy { margin-top: .25rem; max-width: 40rem; }
|
|
249
|
-
.credential-field-summary {
|
|
250
|
-
border-top: 1px solid var(--rule);
|
|
251
|
-
margin-top: .75rem;
|
|
252
|
-
}
|
|
253
|
-
.credential-field-summary > div {
|
|
254
|
-
border-bottom: 1px solid var(--rule);
|
|
255
|
-
display: flex;
|
|
256
|
-
flex-wrap: wrap;
|
|
257
|
-
gap: .25rem var(--gap);
|
|
258
|
-
justify-content: space-between;
|
|
259
|
-
padding: .5rem 0;
|
|
260
|
-
}
|
|
261
|
-
.credential-actions { display: flex; flex-wrap: wrap; gap: var(--gap); margin-top: .75rem; }
|
|
262
|
-
.credential-actions button,
|
|
263
|
-
.credential-form button,
|
|
264
|
-
.activity-controls button,
|
|
265
|
-
.activity-more {
|
|
266
|
-
align-items: center;
|
|
267
|
-
display: inline-flex;
|
|
268
|
-
min-height: 2.75rem;
|
|
269
|
-
}
|
|
270
|
-
.credential-form {
|
|
271
|
-
align-items: center;
|
|
272
|
-
display: flex;
|
|
273
|
-
flex-wrap: wrap;
|
|
274
|
-
gap: .75rem var(--gap);
|
|
275
|
-
margin-top: .75rem;
|
|
276
|
-
}
|
|
277
|
-
.credential-form > input { flex: 1 1 18rem; }
|
|
278
|
-
.credential-fields { display: grid; flex: 1 1 100%; gap: .75rem; }
|
|
279
|
-
.credential-field {
|
|
280
|
-
align-items: center;
|
|
281
|
-
display: grid;
|
|
282
|
-
gap: var(--gap);
|
|
283
|
-
grid-template-columns: minmax(9rem, 12rem) 1fr;
|
|
284
|
-
}
|
|
285
|
-
.credential-field input { min-width: 0; width: 100%; }
|
|
286
|
-
.danger { text-decoration-style: double; }
|
|
287
|
-
|
|
288
|
-
.token-create {
|
|
289
|
-
border-bottom: 1px solid var(--rule);
|
|
290
|
-
border-top: 1px solid var(--rule);
|
|
291
|
-
padding: .75rem 0;
|
|
292
|
-
}
|
|
293
|
-
.token-create > label {
|
|
294
|
-
display: block;
|
|
295
|
-
margin-bottom: .5rem;
|
|
296
|
-
}
|
|
297
|
-
.token-create input { flex: 1 1 18rem; }
|
|
298
|
-
.token-create button,
|
|
299
|
-
.token-card button,
|
|
300
|
-
.token-reveal button {
|
|
301
|
-
align-items: center;
|
|
302
|
-
display: inline-flex;
|
|
303
|
-
min-height: 2.75rem;
|
|
304
|
-
}
|
|
305
|
-
.token-reveal {
|
|
306
|
-
background: var(--ink);
|
|
307
|
-
color: var(--paper);
|
|
308
|
-
margin-top: 1.5rem;
|
|
309
|
-
padding: 1rem 1.25rem;
|
|
310
|
-
}
|
|
311
|
-
.token-reveal .meta,
|
|
312
|
-
.token-reveal .cap { color: #bbb; }
|
|
313
|
-
.token-reveal-head,
|
|
314
|
-
.token-card-head {
|
|
315
|
-
align-items: baseline;
|
|
316
|
-
display: flex;
|
|
317
|
-
flex-wrap: wrap;
|
|
318
|
-
gap: .25rem var(--gap);
|
|
319
|
-
justify-content: space-between;
|
|
320
|
-
}
|
|
321
|
-
.token-secret {
|
|
322
|
-
border-bottom: 1px solid #555;
|
|
323
|
-
border-top: 1px solid #555;
|
|
324
|
-
margin-top: .75rem;
|
|
325
|
-
}
|
|
326
|
-
.token-secret code {
|
|
327
|
-
color: var(--paper);
|
|
328
|
-
user-select: all;
|
|
329
|
-
}
|
|
330
|
-
.token-ledger {
|
|
331
|
-
border-bottom: 1px solid var(--rule);
|
|
332
|
-
margin-top: 1.5rem;
|
|
333
|
-
}
|
|
334
|
-
.token-card {
|
|
335
|
-
border-top: 1px solid var(--rule);
|
|
336
|
-
padding: .75rem 0 .75rem 1.25rem;
|
|
337
|
-
position: relative;
|
|
338
|
-
}
|
|
339
|
-
.token-card::before {
|
|
340
|
-
background: var(--ink);
|
|
341
|
-
bottom: 0;
|
|
342
|
-
content: "";
|
|
343
|
-
left: .25rem;
|
|
344
|
-
position: absolute;
|
|
345
|
-
top: 0;
|
|
346
|
-
width: 1px;
|
|
347
|
-
}
|
|
348
|
-
.token-card.revoked { color: var(--muted); }
|
|
349
|
-
.token-card.revoked::before { background: var(--rule); }
|
|
350
|
-
|
|
351
|
-
details { margin-top: .75rem; }
|
|
352
|
-
summary { cursor: pointer; list-style: none; width: max-content; }
|
|
353
|
-
summary::-webkit-details-marker { display: none; }
|
|
354
|
-
.tool-list { border-bottom: 1px solid var(--rule); margin-top: .5rem; }
|
|
355
|
-
.tool {
|
|
356
|
-
border-top: 1px solid var(--rule);
|
|
357
|
-
display: grid;
|
|
358
|
-
gap: .25rem var(--gap);
|
|
359
|
-
grid-template-columns: minmax(12rem, 1fr) minmax(0, 2fr);
|
|
360
|
-
padding: .5rem 0;
|
|
361
|
-
}
|
|
362
|
-
.tool code { font-family: var(--mono); font-size: .78rem; overflow-wrap: anywhere; }
|
|
363
|
-
.tool .td { color: var(--muted); font-size: .9em; }
|
|
364
|
-
.empty { border-top: 1px solid var(--rule); padding: .75rem 0; }
|
|
365
|
-
|
|
366
|
-
.activity-copy { margin-bottom: 1.5rem; }
|
|
367
|
-
.activity-controls { margin-bottom: 1.5rem; }
|
|
368
|
-
.activity-controls input { flex: 1 1 18rem; }
|
|
369
|
-
#activityNotice { margin-bottom: .75rem; }
|
|
370
|
-
.activity-ledger { border-bottom: 1px solid var(--rule); }
|
|
371
|
-
.activity-item {
|
|
372
|
-
border-top: 1px solid var(--rule);
|
|
373
|
-
display: grid;
|
|
374
|
-
gap: .25rem var(--gap);
|
|
375
|
-
grid-template-columns: minmax(9rem, .85fr) minmax(12rem, 1.4fr) minmax(8rem, .9fr);
|
|
376
|
-
padding-bottom: .75rem;
|
|
377
|
-
padding-top: .75rem;
|
|
378
|
-
}
|
|
379
|
-
.activity-time,
|
|
380
|
-
.activity-actor,
|
|
381
|
-
.activity-detail { color: var(--muted); font-size: .82rem; }
|
|
382
|
-
.activity-actor-id { color: var(--muted); margin-top: .1rem; }
|
|
383
|
-
.activity-address { font-family: var(--mono); font-size: .78rem; overflow-wrap: anywhere; }
|
|
384
|
-
.activity-outcome { font-size: .9em; }
|
|
385
|
-
.activity-item.error .activity-outcome,
|
|
386
|
-
.activity-item.timeout .activity-outcome,
|
|
387
|
-
.activity-item.cancelled .activity-outcome { text-decoration: underline; }
|
|
388
|
-
.activity-empty { border-top: 1px solid var(--rule); padding: .75rem 0; }
|
|
389
|
-
.activity-more { margin-top: .75rem; }
|
|
390
|
-
.unavailable {
|
|
391
|
-
background: var(--trace);
|
|
392
|
-
border-bottom: 1px solid var(--rule);
|
|
393
|
-
border-top: 1px solid var(--rule);
|
|
394
|
-
padding: .75rem;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
@media (prefers-reduced-motion: reduce) {
|
|
398
|
-
html:focus-within { scroll-behavior: auto; }
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
@media (max-width: 36.99rem) {
|
|
402
|
-
.pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
403
|
-
.pcap,
|
|
404
|
-
.pbody { grid-column: 1 / -1; }
|
|
405
|
-
.masthead .brand { grid-column: 1; }
|
|
406
|
-
.mast-nav { grid-column: 1 / -1; grid-row: 2; justify-content: flex-start; }
|
|
407
|
-
.product { display: none; }
|
|
408
|
-
.mast-actions {
|
|
409
|
-
align-items: flex-start;
|
|
410
|
-
flex-direction: column;
|
|
411
|
-
font-size: .875rem;
|
|
412
|
-
gap: .25rem;
|
|
413
|
-
}
|
|
414
|
-
.lead { margin-top: 4rem; }
|
|
415
|
-
.section,
|
|
416
|
-
.section + .section { margin-top: 2.5rem; }
|
|
417
|
-
.connector-head,
|
|
418
|
-
.tool,
|
|
419
|
-
.activity-item { grid-template-columns: 1fr; }
|
|
420
|
-
.connector-state { text-align: left; }
|
|
421
|
-
.credential-field { align-items: start; grid-template-columns: 1fr; gap: .25rem; }
|
|
422
|
-
input { min-height: 2.75rem; }
|
|
423
|
-
}
|