@nyte-ai/host 0.0.0-stage → 0.0.18
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/LICENSE +21 -0
- package/README.md +6 -2
- package/THIRD-PARTY-NOTICES.md +800 -0
- package/dist/chunks/canvas-preview-0cmbkp2j.js +65 -0
- package/dist/chunks/canvas-preview-0nq75h9k.js +7 -0
- package/dist/chunks/canvas-preview-0nrnbt76.js +497 -0
- package/dist/chunks/canvas-preview-1sq7z9jq.js +17 -0
- package/dist/chunks/canvas-preview-1ta3avah.js +56 -0
- package/dist/chunks/canvas-preview-2zdyh9ny.js +26 -0
- package/dist/chunks/canvas-preview-31w7xm8z.js +34 -0
- package/dist/chunks/canvas-preview-4b6sayhg.js +295 -0
- package/dist/chunks/canvas-preview-4e0pxa32.js +63 -0
- package/dist/chunks/canvas-preview-518dh8by.js +169 -0
- package/dist/chunks/canvas-preview-5hxat7hh.js +239 -0
- package/dist/chunks/canvas-preview-5mex725c.js +14 -0
- package/dist/chunks/canvas-preview-5z63am63.js +295 -0
- package/dist/chunks/canvas-preview-65xqjw7f.js +20 -0
- package/dist/chunks/canvas-preview-69fkk9yn.js +95 -0
- package/dist/chunks/canvas-preview-75db60xy.js +457 -0
- package/dist/chunks/canvas-preview-76fwvd6e.js +272 -0
- package/dist/chunks/canvas-preview-8xgt67ka.js +598 -0
- package/dist/chunks/canvas-preview-98aj5p34.js +176 -0
- package/dist/chunks/canvas-preview-9aqczacs.js +73 -0
- package/dist/chunks/canvas-preview-a3yw0j70.js +72 -0
- package/dist/chunks/canvas-preview-azg56359.js +68 -0
- package/dist/chunks/canvas-preview-d9wwhbtz.js +240 -0
- package/dist/chunks/canvas-preview-ehf3vp31.js +411 -0
- package/dist/chunks/canvas-preview-evh92ywd.js +369 -0
- package/dist/chunks/canvas-preview-ewgspmsd.js +81 -0
- package/dist/chunks/canvas-preview-g3qj3y3k.js +156 -0
- package/dist/chunks/canvas-preview-h8hshnff.js +63 -0
- package/dist/chunks/canvas-preview-j1tnf51w.js +36 -0
- package/dist/chunks/canvas-preview-kdqgrstc.js +194 -0
- package/dist/chunks/canvas-preview-kn7kvbfj.js +12 -0
- package/dist/chunks/canvas-preview-m02v4yy6.js +386 -0
- package/dist/chunks/canvas-preview-mgcx2b2p.js +271 -0
- package/dist/chunks/canvas-preview-rp4x6y1h.js +144 -0
- package/dist/chunks/canvas-preview-rp6fz0w5.js +130 -0
- package/dist/chunks/canvas-preview-s94ebwf5.js +112 -0
- package/dist/chunks/canvas-preview-senpjwep.js +518 -0
- package/dist/chunks/canvas-preview-skzwvw4d.js +23 -0
- package/dist/chunks/canvas-preview-srgfpdmf.js +60 -0
- package/dist/chunks/canvas-preview-tjhabynd.js +252 -0
- package/dist/chunks/canvas-preview-vaatfznm.js +189 -0
- package/dist/chunks/canvas-preview-vax9ne4e.js +341 -0
- package/dist/chunks/canvas-preview-wg80rbc2.js +46 -0
- package/dist/chunks/canvas-preview-xn10d4f8.js +608 -0
- package/dist/chunks/canvas-preview-yjz0f7n4.js +50 -0
- package/dist/chunks/canvas-preview-ymgz0937.js +587 -0
- package/dist/chunks/canvas-preview-yrfz2ak6.js +134 -0
- package/dist/chunks/canvas-preview-zaaj99wd.js +244 -0
- package/dist/chunks/canvas-preview-zn2d0k9d.js +133 -0
- package/dist/src/canvas-preview.d.ts +29 -0
- package/dist/src/canvas-preview.js +267 -0
- package/dist/src/credentials.d.ts +44 -0
- package/dist/src/credentials.js +10 -0
- package/dist/src/deploy/cloudflare/worker.d.ts +50 -0
- package/dist/src/deploy/cloudflare/worker.js +196 -0
- package/dist/src/deploy/vercel/nitro.config.d.ts +2 -0
- package/dist/src/deploy/vercel/nitro.config.js +30 -0
- package/dist/src/deploy/vercel/server/routes/[...].d.ts +2 -0
- package/dist/src/deploy/vercel/server/routes/[...].js +18 -0
- package/dist/src/deploy/vercel/server/utils/host.d.ts +13 -0
- package/dist/src/deploy/vercel/server/utils/host.js +7 -0
- package/dist/src/deploy/vercel/server/utils/repair.d.ts +1 -0
- package/dist/src/deploy/vercel/server/utils/repair.js +6 -0
- package/dist/src/deploy/vercel/server/utils/step.d.ts +10 -0
- package/dist/src/deploy/vercel/server/utils/step.js +6 -0
- package/dist/src/deploy/vercel/server/workflows/drive.d.ts +14 -0
- package/dist/src/deploy/vercel/server/workflows/drive.js +13 -0
- package/dist/src/durable-object.d.ts +14 -0
- package/dist/src/durable-object.js +231 -0
- package/dist/src/hash.d.ts +1 -0
- package/dist/src/hash.js +6 -0
- package/dist/src/identity-key.d.ts +11 -0
- package/dist/src/identity-key.js +9 -0
- package/dist/src/identity.d.ts +12 -0
- package/dist/src/identity.js +6 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.js +120 -0
- package/dist/src/key-file.d.ts +1 -0
- package/dist/src/key-file.js +7 -0
- package/dist/src/listen-fetch.d.ts +8 -0
- package/dist/src/listen-fetch.js +9 -0
- package/dist/src/listen.d.ts +4 -0
- package/dist/src/listen.js +10 -0
- package/dist/src/local/command.d.ts +15 -0
- package/dist/src/local/command.js +8 -0
- package/dist/src/local/feed.d.ts +7 -0
- package/dist/src/local/feed.js +6 -0
- package/dist/src/local/files.d.ts +18 -0
- package/dist/src/local/files.js +13 -0
- package/dist/src/local/git-watch.d.ts +15 -0
- package/dist/src/local/git-watch.js +7 -0
- package/dist/src/local/git.d.ts +5 -0
- package/dist/src/local/git.js +13 -0
- package/dist/src/local/github.d.ts +30 -0
- package/dist/src/local/github.js +9 -0
- package/dist/src/local/identity.d.ts +3 -0
- package/dist/src/local/identity.js +7 -0
- package/dist/src/local/jobs.d.ts +7 -0
- package/dist/src/local/jobs.js +6 -0
- package/dist/src/local/legacy-trust.d.ts +10 -0
- package/dist/src/local/legacy-trust.js +6 -0
- package/dist/src/local/patch.d.ts +16 -0
- package/dist/src/local/patch.js +17 -0
- package/dist/src/local/provider.d.ts +11 -0
- package/dist/src/local/provider.js +20 -0
- package/dist/src/local/snapshots.d.ts +7 -0
- package/dist/src/local/snapshots.js +11 -0
- package/dist/src/local/text.d.ts +1 -0
- package/dist/src/local/text.js +6 -0
- package/dist/src/local/tree.d.ts +50 -0
- package/dist/src/local/tree.js +16 -0
- package/dist/src/local/workspace-migration.d.ts +2 -0
- package/dist/src/local/workspace-migration.js +7 -0
- package/dist/src/local/worktrees.d.ts +46 -0
- package/dist/src/local/worktrees.js +14 -0
- package/dist/src/mcp/config.d.ts +75 -0
- package/dist/src/mcp/config.js +12 -0
- package/dist/src/mcp/connect.d.ts +28 -0
- package/dist/src/mcp/connect.js +9 -0
- package/dist/src/mcp/hub.d.ts +19 -0
- package/dist/src/mcp/hub.js +11 -0
- package/dist/src/mcp/oauth.d.ts +46 -0
- package/dist/src/mcp/oauth.js +12 -0
- package/dist/src/mcp/tools.d.ts +29 -0
- package/dist/src/mcp/tools.js +12 -0
- package/dist/src/open.d.ts +42 -0
- package/dist/src/open.js +44 -0
- package/dist/src/plugins/loader.d.ts +21 -0
- package/dist/src/plugins/loader.js +11 -0
- package/dist/src/postgres.d.ts +19 -0
- package/dist/src/postgres.js +8 -0
- package/dist/src/providers.d.ts +16 -0
- package/dist/src/providers.js +112 -0
- package/dist/src/secrets.d.ts +12 -0
- package/dist/src/secrets.js +8 -0
- package/dist/src/serve/binding.d.ts +39 -0
- package/dist/src/serve/binding.js +6 -0
- package/dist/src/serve/handler.d.ts +15 -0
- package/dist/src/serve/handler.js +8 -0
- package/dist/src/serve/stream-server.d.ts +6 -0
- package/dist/src/serve/stream-server.js +6 -0
- package/dist/src/session-index.d.ts +11 -0
- package/dist/src/session-index.js +11 -0
- package/dist/src/shell-env.d.ts +14 -0
- package/dist/src/shell-env.js +108 -0
- package/dist/src/sqlite-workers.d.ts +6 -0
- package/dist/src/sqlite-workers.js +6 -0
- package/dist/src/sqlite.d.ts +7 -0
- package/dist/src/sqlite.js +10 -0
- package/dist/src/store-owner.d.ts +15 -0
- package/dist/src/store-owner.js +9 -0
- package/dist/src/store-rows.d.ts +13 -0
- package/dist/src/store-rows.js +26 -0
- package/dist/src/store-usage.d.ts +25 -0
- package/dist/src/store-usage.js +16 -0
- package/dist/src/usage-scan.d.ts +24 -0
- package/dist/src/usage-scan.js +65 -0
- package/dist/src/usage-service.d.ts +22 -0
- package/dist/src/usage-service.js +12 -0
- package/dist/src/usage-summary.d.ts +9 -0
- package/dist/src/usage-summary.js +16 -0
- package/dist/src/usage-types.d.ts +86 -0
- package/dist/src/usage-types.js +0 -0
- package/dist/src/usage-worker.d.ts +1 -0
- package/dist/src/usage-worker.js +25 -0
- package/dist/src/usage.d.ts +72 -0
- package/dist/src/usage.js +13 -0
- package/package.json +132 -3
- package/src/canvas-preview.ts +402 -0
- package/src/credentials.ts +294 -0
- package/src/deploy/cloudflare/README.md +3 -0
- package/src/deploy/cloudflare/worker.ts +306 -0
- package/src/deploy/cloudflare/wrangler.jsonc +12 -0
- package/src/deploy/vercel/README.md +3 -0
- package/src/deploy/vercel/nitro.config.ts +29 -0
- package/src/deploy/vercel/server/routes/[...].ts +10 -0
- package/src/deploy/vercel/server/utils/host.ts +104 -0
- package/src/deploy/vercel/server/utils/repair.ts +35 -0
- package/src/deploy/vercel/server/utils/step.ts +25 -0
- package/src/deploy/vercel/server/workflows/drive.ts +46 -0
- package/src/deploy/vercel/tsconfig.json +9 -0
- package/src/deploy/vercel/types/bun.d.ts +2 -0
- package/src/durable-object.ts +386 -0
- package/src/hash.ts +5 -0
- package/src/identity-key.ts +20 -0
- package/src/identity.ts +66 -0
- package/src/index.ts +21 -0
- package/src/key-file.ts +53 -0
- package/src/listen-fetch.ts +409 -0
- package/src/listen.ts +228 -0
- package/src/local/command.ts +109 -0
- package/src/local/feed.ts +70 -0
- package/src/local/files.ts +812 -0
- package/src/local/git-watch.ts +189 -0
- package/src/local/git.ts +914 -0
- package/src/local/github.ts +692 -0
- package/src/local/identity.ts +21 -0
- package/src/local/jobs.ts +587 -0
- package/src/local/legacy-trust.ts +105 -0
- package/src/local/patch.ts +334 -0
- package/src/local/provider.ts +184 -0
- package/src/local/snapshots.ts +776 -0
- package/src/local/text.ts +9 -0
- package/src/local/tree.ts +398 -0
- package/src/local/workspace-migration.ts +95 -0
- package/src/local/worktrees.ts +239 -0
- package/src/mcp/config.ts +330 -0
- package/src/mcp/connect.ts +105 -0
- package/src/mcp/hub.ts +836 -0
- package/src/mcp/oauth.ts +436 -0
- package/src/mcp/tools.ts +333 -0
- package/src/open.ts +469 -0
- package/src/plugins/loader.ts +186 -0
- package/src/postgres.ts +492 -0
- package/src/providers.ts +135 -0
- package/src/secrets.ts +31 -0
- package/src/serve/binding.ts +628 -0
- package/src/serve/handler.ts +362 -0
- package/src/serve/stream-server.ts +176 -0
- package/src/session-index.ts +99 -0
- package/src/shell-env.ts +153 -0
- package/src/sqlite-workers.ts +283 -0
- package/src/sqlite.ts +528 -0
- package/src/store-owner.ts +98 -0
- package/src/store-rows.ts +110 -0
- package/src/store-usage.ts +344 -0
- package/src/usage-scan.ts +81 -0
- package/src/usage-service.ts +73 -0
- package/src/usage-summary.ts +79 -0
- package/src/usage-types.ts +87 -0
- package/src/usage-worker.ts +24 -0
- package/src/usage.ts +701 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
vercelHost2
|
|
3
|
+
} from "./canvas-preview-ewgspmsd.js";
|
|
4
|
+
import {
|
|
5
|
+
stepFrom2
|
|
6
|
+
} from "./canvas-preview-65xqjw7f.js";
|
|
7
|
+
|
|
8
|
+
// src/deploy/vercel/server/workflows/drive.ts
|
|
9
|
+
import { sleep } from "workflow";
|
|
10
|
+
import { start } from "workflow/api";
|
|
11
|
+
async function dispatchHead2(target) {
|
|
12
|
+
await start(driveHead2, [target]);
|
|
13
|
+
}
|
|
14
|
+
async function driveHead2(input) {
|
|
15
|
+
"use workflow";
|
|
16
|
+
for (;; ) {
|
|
17
|
+
const next = stepFrom2(await advanceHead2(input), Date.now());
|
|
18
|
+
if (next.kind === "stop")
|
|
19
|
+
return;
|
|
20
|
+
if (next.kind === "sleep")
|
|
21
|
+
await sleep(next.ms);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function advanceHead2(input) {
|
|
25
|
+
"use step";
|
|
26
|
+
const { host } = await vercelHost2(dispatchHead2);
|
|
27
|
+
const coverage = await host.execution.cover({ kind: "sessions", sessions: [input.session] });
|
|
28
|
+
try {
|
|
29
|
+
await host.server.tick(Date.now());
|
|
30
|
+
return await host.execution.advance(input);
|
|
31
|
+
} finally {
|
|
32
|
+
await coverage.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { dispatchHead2, driveHead2, advanceHead2 };
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// src/mcp/config.ts
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { isJsonObject, McpExposureNameType, McpOAuthConfigType } from "@nyte-ai/schema";
|
|
6
|
+
import { isJson } from "@nyte-ai/schema";
|
|
7
|
+
import { Type } from "typebox";
|
|
8
|
+
import { Value } from "typebox/value";
|
|
9
|
+
var ExposureName = McpExposureNameType;
|
|
10
|
+
var Entry = Type.Object({
|
|
11
|
+
type: Type.Optional(Type.Enum(["stdio", "http", "streamable-http", "sse"])),
|
|
12
|
+
command: Type.Optional(Type.String({ minLength: 1 })),
|
|
13
|
+
args: Type.Optional(Type.Array(Type.String())),
|
|
14
|
+
env: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
15
|
+
cwd: Type.Optional(Type.String()),
|
|
16
|
+
url: Type.Optional(Type.String({ minLength: 1 })),
|
|
17
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
18
|
+
oauth: Type.Optional(McpOAuthConfigType),
|
|
19
|
+
enabled: Type.Optional(Type.Boolean()),
|
|
20
|
+
timeout: Type.Optional(Type.Number({ exclusiveMinimum: 0 })),
|
|
21
|
+
description: Type.Optional(Type.String()),
|
|
22
|
+
exposure: Type.Optional(ExposureName),
|
|
23
|
+
toolExposure: Type.Optional(Type.Record(Type.String(), ExposureName))
|
|
24
|
+
});
|
|
25
|
+
var ConfigFile = Type.Object({
|
|
26
|
+
mcpServers: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
|
|
27
|
+
});
|
|
28
|
+
var OVERRIDE_KEYS = new Set(["enabled", "exposure", "toolExposure"]);
|
|
29
|
+
var EXPOSURE = {
|
|
30
|
+
direct: "model",
|
|
31
|
+
deferred: "deferred",
|
|
32
|
+
codemode: "code",
|
|
33
|
+
"codemode-deferred": "code",
|
|
34
|
+
hidden: "hidden"
|
|
35
|
+
};
|
|
36
|
+
async function readMcpFile2(path) {
|
|
37
|
+
try {
|
|
38
|
+
return { kind: "text", text: await readFile(path, "utf8") };
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
41
|
+
return { kind: "missing" };
|
|
42
|
+
return { kind: "unreadable", message: error instanceof Error ? error.message : String(error) };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseMcpConfig2(files) {
|
|
46
|
+
const servers = new Map;
|
|
47
|
+
const canonical = new Map;
|
|
48
|
+
const issues = [];
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
if (file.contents.kind === "missing")
|
|
51
|
+
continue;
|
|
52
|
+
const fail = (path, message) => {
|
|
53
|
+
issues.push({
|
|
54
|
+
severity: "error",
|
|
55
|
+
path: ["mcpServers", ...path],
|
|
56
|
+
message,
|
|
57
|
+
source: { plugin: "mcp", file: file.path }
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
if (file.contents.kind === "unreadable") {
|
|
61
|
+
fail([], `The file cannot be read: ${file.contents.message}`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(file.contents.text);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
fail([], `The file is not valid JSON: ${error instanceof Error ? error.message : ""}`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (!Value.Check(ConfigFile, parsed)) {
|
|
72
|
+
fail([], 'The file must be an object with an "mcpServers" object.');
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
for (const [name, raw] of Object.entries(parsed.mcpServers ?? {})) {
|
|
76
|
+
if (!/^[A-Za-z0-9_-]+$/.test(name)) {
|
|
77
|
+
fail([name], `Server names may contain only letters, digits, "_" and "-": ${name}.`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const key = name.replaceAll("-", "_");
|
|
81
|
+
const taken = canonical.get(key);
|
|
82
|
+
if (taken !== undefined && taken !== name) {
|
|
83
|
+
fail([name], `${name} and ${taken} name the same server.`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (!Value.Check(Entry, raw)) {
|
|
87
|
+
const [first] = Value.Errors(Entry, raw);
|
|
88
|
+
fail([name], `${name}${first?.instancePath ?? ""} ${first?.message ?? "is invalid"}.`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const base = servers.get(name);
|
|
92
|
+
if (raw.command === undefined && raw.url === undefined && raw.type === undefined) {
|
|
93
|
+
const extra = Object.keys(raw).filter((field) => !OVERRIDE_KEYS.has(field));
|
|
94
|
+
if (file.scope !== "project" || base === undefined)
|
|
95
|
+
fail([name], `${name} needs "command" or "url".`);
|
|
96
|
+
else if (extra.length > 0)
|
|
97
|
+
fail([name], `An override of ${name} can only set enabled, exposure and toolExposure.`);
|
|
98
|
+
else
|
|
99
|
+
servers.set(name, { ...base, ...settings(raw, base), override: file.path });
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const transport = readTransport(raw);
|
|
103
|
+
if (typeof transport === "string") {
|
|
104
|
+
fail([name], `${name}: ${transport}`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
canonical.set(key, name);
|
|
108
|
+
servers.set(name, {
|
|
109
|
+
name,
|
|
110
|
+
scope: file.scope,
|
|
111
|
+
path: file.path,
|
|
112
|
+
override: null,
|
|
113
|
+
transport,
|
|
114
|
+
timeoutMs: (raw.timeout ?? 60) * 1000,
|
|
115
|
+
description: raw.description ?? null,
|
|
116
|
+
...settings(raw, null)
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { servers, issues };
|
|
121
|
+
}
|
|
122
|
+
function readTransport(raw) {
|
|
123
|
+
if (raw.type === "sse")
|
|
124
|
+
return `the SSE transport is not supported; use the server's streamable HTTP url, often ending in "/mcp".`;
|
|
125
|
+
if (raw.command !== undefined && raw.url !== undefined)
|
|
126
|
+
return 'set "command" or "url", not both.';
|
|
127
|
+
if (raw.command !== undefined && raw.type !== undefined && raw.type !== "stdio")
|
|
128
|
+
return `type ${raw.type} needs "url", not "command".`;
|
|
129
|
+
if (raw.command !== undefined)
|
|
130
|
+
return {
|
|
131
|
+
kind: "stdio",
|
|
132
|
+
command: raw.command,
|
|
133
|
+
args: raw.args ?? [],
|
|
134
|
+
env: raw.env ?? {},
|
|
135
|
+
cwd: raw.cwd ?? null
|
|
136
|
+
};
|
|
137
|
+
if (raw.url === undefined)
|
|
138
|
+
return `type ${raw.type ?? "stdio"} needs "command" or "url".`;
|
|
139
|
+
if (raw.type === "stdio")
|
|
140
|
+
return 'type stdio needs "command", not "url".';
|
|
141
|
+
const url = URL.parse(raw.url);
|
|
142
|
+
if (url === null || url.protocol !== "https:" && url.protocol !== "http:")
|
|
143
|
+
return `${raw.url} is not an http or https URL.`;
|
|
144
|
+
if (raw.command === undefined && raw.oauth?.callbackUrl !== undefined) {
|
|
145
|
+
const callback = URL.parse(raw.oauth.callbackUrl);
|
|
146
|
+
if (callback === null || callback.protocol !== "http:" || !["localhost", "127.0.0.1", "[::1]"].includes(callback.hostname))
|
|
147
|
+
return "oauth.callbackUrl must be an http URL on localhost, 127.0.0.1 or [::1].";
|
|
148
|
+
}
|
|
149
|
+
if (raw.oauth?.authServerMetadataUrl !== undefined) {
|
|
150
|
+
const metadata = URL.parse(raw.oauth.authServerMetadataUrl);
|
|
151
|
+
if (metadata === null || metadata.protocol !== "https:" && !["localhost", "127.0.0.1", "[::1]"].includes(metadata.hostname))
|
|
152
|
+
return "oauth.authServerMetadataUrl must use https, except on localhost.";
|
|
153
|
+
}
|
|
154
|
+
return { kind: "http", url: raw.url, headers: raw.headers ?? {}, oauth: raw.oauth ?? {} };
|
|
155
|
+
}
|
|
156
|
+
function settings(raw, base) {
|
|
157
|
+
return {
|
|
158
|
+
enabled: raw.enabled ?? base?.enabled ?? true,
|
|
159
|
+
exposure: raw.exposure === undefined ? base?.exposure ?? "code" : EXPOSURE[raw.exposure],
|
|
160
|
+
toolExposure: raw.toolExposure === undefined ? base?.toolExposure ?? [] : Object.entries(raw.toolExposure).map(([pattern, name]) => [pattern, EXPOSURE[name]])
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
async function planMcpEdit2(path, change) {
|
|
164
|
+
const contents = await readMcpFile2(path);
|
|
165
|
+
if (contents.kind === "unreadable")
|
|
166
|
+
return { kind: "invalid", message: `${path} cannot be read: ${contents.message}` };
|
|
167
|
+
let parsed = {};
|
|
168
|
+
if (contents.kind === "text") {
|
|
169
|
+
try {
|
|
170
|
+
parsed = JSON.parse(contents.text);
|
|
171
|
+
} catch {
|
|
172
|
+
return { kind: "invalid", message: `${path} is not valid JSON; fix it first.` };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!isJson(parsed) || !isJsonObject(parsed))
|
|
176
|
+
return { kind: "invalid", message: `${path} is not a JSON object.` };
|
|
177
|
+
const servers = parsed.mcpServers ?? {};
|
|
178
|
+
if (!isJsonObject(servers))
|
|
179
|
+
return { kind: "invalid", message: `${path} has an "mcpServers" that is not an object.` };
|
|
180
|
+
const next = change(servers);
|
|
181
|
+
if (next === null)
|
|
182
|
+
return { kind: "missing" };
|
|
183
|
+
return { kind: "planned", text: `${JSON.stringify({ ...parsed, mcpServers: next }, null, 2)}
|
|
184
|
+
` };
|
|
185
|
+
}
|
|
186
|
+
async function writeMcpFile2(path, text) {
|
|
187
|
+
const target = await realpath(path).catch(() => path);
|
|
188
|
+
const temporary = `${target}.${randomUUID()}.tmp`;
|
|
189
|
+
await mkdir(dirname(target), { recursive: true });
|
|
190
|
+
await writeFile(temporary, text, { mode: 384 });
|
|
191
|
+
await rename(temporary, target);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { readMcpFile2, parseMcpConfig2, planMcpEdit2, writeMcpFile2 };
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// src/serve/binding.ts
|
|
2
|
+
import { isJson, SdkError } from "@nyte-ai/schema";
|
|
3
|
+
import { mapped, viewFrames } from "@nyte-ai/protocol";
|
|
4
|
+
var LOGIN_LIFETIME = 10 * 60 * 1000;
|
|
5
|
+
var attempts = new WeakMap;
|
|
6
|
+
var holds = new WeakMap;
|
|
7
|
+
function bindConnection2(connection, options) {
|
|
8
|
+
const { wire } = options.server;
|
|
9
|
+
const { principal } = connection;
|
|
10
|
+
const logins = attempts.get(options.server) ?? new Map;
|
|
11
|
+
attempts.set(options.server, logins);
|
|
12
|
+
const pages = holds.get(options.server) ?? new Map;
|
|
13
|
+
holds.set(options.server, pages);
|
|
14
|
+
const session = (id) => connection.session(id);
|
|
15
|
+
const workspace = (id) => connection.workspace(id);
|
|
16
|
+
const files = async (id) => available(await workspace(id).files(), "files");
|
|
17
|
+
const git = async (id) => available(await workspace(id).git(), "git");
|
|
18
|
+
const github = async (id) => available(await workspace(id).github(), "github");
|
|
19
|
+
const browser = async (id) => available(await workspace(id).browser(), "browser");
|
|
20
|
+
const findLogin = (provider) => logins.get(principalKey(principal, provider)) ?? fail("unknown", `No login for ${provider} is in progress.`);
|
|
21
|
+
const endLogin = (provider, attempt) => {
|
|
22
|
+
clearTimeout(attempt.timer);
|
|
23
|
+
const key = principalKey(principal, provider);
|
|
24
|
+
if (logins.get(key) === attempt)
|
|
25
|
+
logins.delete(key);
|
|
26
|
+
attempt.steps?.return?.();
|
|
27
|
+
};
|
|
28
|
+
const hold = (page) => {
|
|
29
|
+
const key = principalKey(principal, page.id);
|
|
30
|
+
const known = pages.get(key) ?? [];
|
|
31
|
+
pages.set(key, known.includes(page) ? known : [...known, page]);
|
|
32
|
+
return page;
|
|
33
|
+
};
|
|
34
|
+
const release = async (page) => {
|
|
35
|
+
const key = principalKey(principal, page);
|
|
36
|
+
const [last, ...rest] = [...pages.get(key) ?? []].reverse();
|
|
37
|
+
if (rest.length === 0)
|
|
38
|
+
pages.delete(key);
|
|
39
|
+
else
|
|
40
|
+
pages.set(key, rest.reverse());
|
|
41
|
+
await last?.close();
|
|
42
|
+
};
|
|
43
|
+
const findPage = async (at, id) => pages.get(principalKey(principal, id))?.[0] ?? wire.page(id) ?? hold(await (await browser(at)).adopt(id));
|
|
44
|
+
const describePage = async (page) => {
|
|
45
|
+
const view = await page.view();
|
|
46
|
+
return { id: page.id, url: view.url, title: view.title, holders: wire.holders(page.id) };
|
|
47
|
+
};
|
|
48
|
+
const findReceipt = (at, id) => at === null ? wire.batchReceipt(id) : session(at).receipt(id);
|
|
49
|
+
const startedJob = (job) => ({
|
|
50
|
+
...wire.job(job.id) ?? fail("unknown", `Job ${job.id} is gone.`),
|
|
51
|
+
key: job.key
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
"connection.watch": async () => mapped(connection.watch(), (view) => hostWire(view, principal)),
|
|
55
|
+
"connection.blob": async ({ id }) => ({ reader: await connection.blob(id) }),
|
|
56
|
+
"models.list": () => connection.models.list(),
|
|
57
|
+
"models.accounts": ({ provider }) => connection.models.accounts(provider),
|
|
58
|
+
"models.selectAccount": async ({ provider, account }) => {
|
|
59
|
+
await connection.models.selectAccount(provider, account);
|
|
60
|
+
return null;
|
|
61
|
+
},
|
|
62
|
+
"models.usage": () => connection.models.usage(),
|
|
63
|
+
"models.refresh": async ({ provider }) => {
|
|
64
|
+
await connection.models.refresh(provider);
|
|
65
|
+
return null;
|
|
66
|
+
},
|
|
67
|
+
"models.setDefault": ({ ref }) => connection.models.setDefault(ref),
|
|
68
|
+
"models.verify": ({ provider }) => connection.models.verify(provider),
|
|
69
|
+
"models.login": async (input) => {
|
|
70
|
+
const { provider } = input;
|
|
71
|
+
const login = connection.models.login(input);
|
|
72
|
+
const key = principalKey(principal, provider);
|
|
73
|
+
const previous = logins.get(key);
|
|
74
|
+
if (previous !== undefined)
|
|
75
|
+
endLogin(provider, previous);
|
|
76
|
+
const attempt = {
|
|
77
|
+
login,
|
|
78
|
+
steps: null,
|
|
79
|
+
timer: setTimeout(() => endLogin(provider, attempt), LOGIN_LIFETIME)
|
|
80
|
+
};
|
|
81
|
+
logins.set(key, attempt);
|
|
82
|
+
return null;
|
|
83
|
+
},
|
|
84
|
+
"models.logout": async ({ provider }) => {
|
|
85
|
+
await connection.models.logout(provider);
|
|
86
|
+
return null;
|
|
87
|
+
},
|
|
88
|
+
"login.steps": async ({ provider }) => {
|
|
89
|
+
const attempt = findLogin(provider);
|
|
90
|
+
if (attempt.steps !== null)
|
|
91
|
+
fail("invalid", `The login for ${provider} is already streaming.`);
|
|
92
|
+
const steps = attempt.login.steps()[Symbol.asyncIterator]();
|
|
93
|
+
attempt.steps = steps;
|
|
94
|
+
return {
|
|
95
|
+
[Symbol.asyncIterator]: () => ({
|
|
96
|
+
async next() {
|
|
97
|
+
const next = await steps.next();
|
|
98
|
+
if (next.done === true || next.value.kind === "done" || next.value.kind === "failed")
|
|
99
|
+
endLogin(provider, attempt);
|
|
100
|
+
return next;
|
|
101
|
+
},
|
|
102
|
+
async return() {
|
|
103
|
+
endLogin(provider, attempt);
|
|
104
|
+
return { done: true, value: undefined };
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
"login.answer": async ({ provider, code }) => {
|
|
110
|
+
await findLogin(provider).login.answer(code);
|
|
111
|
+
return null;
|
|
112
|
+
},
|
|
113
|
+
"settings.apply": ({ id, value }) => connection.settings.apply(id, value),
|
|
114
|
+
"workspaces.list": () => connection.workspaces.list(),
|
|
115
|
+
"workspaces.inspect": ({ target }) => connection.workspaces.inspect(target),
|
|
116
|
+
"workspaces.add": ({ target, options }) => connection.workspaces.add(target, options),
|
|
117
|
+
"workspaces.forget": ({ id }) => connection.workspaces.forget(id),
|
|
118
|
+
"sessions.watch": async (input) => connection.sessions.watch(input),
|
|
119
|
+
"sessions.start": async (input) => {
|
|
120
|
+
const { session, receipt } = await connection.sessions.start(input);
|
|
121
|
+
return { session: session.id, receipt: receipt.id, message: receipt.message };
|
|
122
|
+
},
|
|
123
|
+
"sessions.list": (input) => connection.sessions.list(input),
|
|
124
|
+
"session.info": ({ session: id }) => session(id).info(),
|
|
125
|
+
"session.update": ({ session: id, patch }) => session(id).update(patch),
|
|
126
|
+
"session.remove": ({ session: id }) => session(id).remove(),
|
|
127
|
+
"session.stop": ({ session: id }) => session(id).stop(),
|
|
128
|
+
"session.command": ({ session: id, name, text }) => session(id).command(name, text),
|
|
129
|
+
"session.completeCommand": ({ session: id, name, prefix }) => session(id).completeCommand(name, prefix),
|
|
130
|
+
"head.send": async ({ session: id, head, content, options }) => {
|
|
131
|
+
const receipt = await session(id).head(head).send(content, options);
|
|
132
|
+
return { receipt: receipt.id, message: receipt.message };
|
|
133
|
+
},
|
|
134
|
+
"head.configure": ({ session: id, head, patch }) => session(id).head(head).configure(patch),
|
|
135
|
+
"head.view": ({ session: id, head, options }) => session(id).head(head).view(options),
|
|
136
|
+
"head.watch": async ({ session: id, head, options }) => {
|
|
137
|
+
await session(id).info();
|
|
138
|
+
return viewFrames(session(id).head(head).watch(options));
|
|
139
|
+
},
|
|
140
|
+
"head.history": ({ session: id, head, before, limit }) => session(id).head(head).history({ before, limit }),
|
|
141
|
+
"head.tree": ({ session: id, head }) => session(id).head(head).tree(),
|
|
142
|
+
"head.move": async ({ session: id, head, position, options, id: receipt }) => ({
|
|
143
|
+
receipt: (await wire.move(id, head, position, { ...options, id: receipt })).id
|
|
144
|
+
}),
|
|
145
|
+
"head.compact": ({ session: id, head, instructions }) => session(id).head(head).compact({ instructions }),
|
|
146
|
+
"heads.create": ({ session: id, name, input }) => session(id).heads.create(name, input),
|
|
147
|
+
"heads.merge": ({ session: id, name, options }) => session(id).heads.merge(name, options),
|
|
148
|
+
"heads.remove": ({ session: id, name, options }) => session(id).heads.remove(name, options),
|
|
149
|
+
"run.stop": ({ session: id, run }) => session(id).run(run).stop(),
|
|
150
|
+
"run.settled": ({ session: id, run }, { signal }) => session(id).run(run).settled({ signal }),
|
|
151
|
+
"receipt.status": async ({ session: id, receipt }) => {
|
|
152
|
+
const status = await findReceipt(id, receipt)?.status() ?? { kind: "missing" };
|
|
153
|
+
return status.kind === "settled" ? { kind: "settled", outcome: toJson(status.outcome) } : status;
|
|
154
|
+
},
|
|
155
|
+
"receipt.settled": async ({ session: id, receipt }, { signal }) => {
|
|
156
|
+
const handle = findReceipt(id, receipt) ?? fail("unknown", `No receipt has the id ${receipt}.`);
|
|
157
|
+
return toJson(await handle.settled({ signal }));
|
|
158
|
+
},
|
|
159
|
+
"receipt.stop": async ({ session: id, receipt }) => {
|
|
160
|
+
const stopped = await findReceipt(id, receipt)?.stop() ?? { kind: "missing" };
|
|
161
|
+
return stopped.kind === "settled" ? { kind: "settled", outcome: toJson(stopped.outcome) } : stopped;
|
|
162
|
+
},
|
|
163
|
+
"receipt.landed": async ({ session: id, receipt }) => wire.sendReceipt(id ?? fail("invalid", "Only a send's receipt has landed."), receipt).landed(),
|
|
164
|
+
"parts.create": async ({ session: id, kind, input }) => {
|
|
165
|
+
const definition = await wire.partDefinition(id, kind) ?? fail("unknown", `No part definition has the kind ${kind}.`);
|
|
166
|
+
return { part: (await session(id).parts.create(definition, input)).id };
|
|
167
|
+
},
|
|
168
|
+
"part.update": ({ session: id, part, next, options }) => session(id).part(part).update(next, options),
|
|
169
|
+
"part.act": async ({ session: id, part, action, input }) => {
|
|
170
|
+
const outcome = await session(id).part(part).act(action, input);
|
|
171
|
+
return outcome.kind === "ok" ? { kind: "ok", output: toJson(outcome.output) } : outcome;
|
|
172
|
+
},
|
|
173
|
+
"part.answer": async ({ session: id, part }, { signal }) => {
|
|
174
|
+
const answer = await session(id).part(part).answer({ signal });
|
|
175
|
+
return answer === null ? null : { action: String(answer.action), input: toJson(answer.input) };
|
|
176
|
+
},
|
|
177
|
+
"part.close": async ({ session: id, part }) => {
|
|
178
|
+
await session(id).part(part).close();
|
|
179
|
+
return null;
|
|
180
|
+
},
|
|
181
|
+
"workspace.info": ({ workspace: id }) => workspace(id).info(),
|
|
182
|
+
"workspace.catalog": ({ workspace: id }) => workspace(id).catalog(),
|
|
183
|
+
"workspace.command": ({ workspace: id, name, text }) => workspace(id).command(name, text),
|
|
184
|
+
"workspace.completeCommand": ({ workspace: id, name, prefix }) => workspace(id).completeCommand(name, prefix),
|
|
185
|
+
"workspace.watch": async ({ workspace: id }) => workspace(id).watch(),
|
|
186
|
+
"mcp.watch": async ({ workspace: id }) => workspace(id).mcp.watch(),
|
|
187
|
+
"mcp.reconnect": ({ workspace: id, server }) => workspace(id).mcp.reconnect(server),
|
|
188
|
+
"mcp.setEnabled": ({ workspace: id, server, enabled }) => workspace(id).mcp.setEnabled(server, enabled),
|
|
189
|
+
"mcp.login": async ({ workspace: id, server }) => {
|
|
190
|
+
const login = JSON.stringify(["mcp", id, server]);
|
|
191
|
+
const previous = logins.get(principalKey(principal, login));
|
|
192
|
+
if (previous !== undefined)
|
|
193
|
+
endLogin(login, previous);
|
|
194
|
+
const attempt = {
|
|
195
|
+
login: workspace(id).mcp.login(server),
|
|
196
|
+
steps: null,
|
|
197
|
+
timer: setTimeout(() => endLogin(login, attempt), LOGIN_LIFETIME)
|
|
198
|
+
};
|
|
199
|
+
logins.set(principalKey(principal, login), attempt);
|
|
200
|
+
return { login };
|
|
201
|
+
},
|
|
202
|
+
"mcp.logout": ({ workspace: id, server }) => workspace(id).mcp.logout(server),
|
|
203
|
+
"mcp.add": ({ workspace: id, server, config, scope }) => workspace(id).mcp.add(server, config, scope),
|
|
204
|
+
"mcp.remove": ({ workspace: id, server, scope }) => workspace(id).mcp.remove(server, scope),
|
|
205
|
+
"workspace.update": ({ workspace: id, patch }) => workspace(id).update(patch),
|
|
206
|
+
"workspace.reload": ({ workspace: id }) => workspace(id).reload(),
|
|
207
|
+
"workspace.changes": ({ workspace: id, run }) => workspace(id).changes(run),
|
|
208
|
+
"workspace.patches": async ({ workspace: id, run, paths, options }) => mapped(workspace(id).patches(run, paths, options), patchesWire),
|
|
209
|
+
"workspace.files": async ({ workspace: id }) => capabilityWire(await workspace(id).files()),
|
|
210
|
+
"workspace.git": async ({ workspace: id }) => capabilityWire(await workspace(id).git()),
|
|
211
|
+
"workspace.github": async ({ workspace: id }) => capabilityWire(await workspace(id).github()),
|
|
212
|
+
"workspace.browser": async ({ workspace: id }) => capabilityWire(await workspace(id).browser()),
|
|
213
|
+
"jobs.start": async ({ workspace: id, command, session, title, pty, id: job }) => startedJob(await workspace(id).jobs.start({ command, session, title, pty, id: job })),
|
|
214
|
+
"jobs.recover": async ({ workspace: id, key }) => {
|
|
215
|
+
const recovered = await workspace(id).jobs.recover(key);
|
|
216
|
+
return "id" in recovered ? startedJob(recovered) : recovered;
|
|
217
|
+
},
|
|
218
|
+
"jobs.list": ({ workspace: id }) => workspace(id).jobs.list(),
|
|
219
|
+
"jobs.watch": async ({ workspace: id }) => jobChanges(workspace(id).jobs.watch()),
|
|
220
|
+
"job.write": async ({ workspace: id, job }, { body }) => {
|
|
221
|
+
await workspace(id).job(job).write(await readBytes(body));
|
|
222
|
+
return null;
|
|
223
|
+
},
|
|
224
|
+
"job.output": async ({ workspace: id, job }) => workspace(id).job(job).output(),
|
|
225
|
+
"job.resize": ({ workspace: id, job, size }) => workspace(id).job(job).resize(size),
|
|
226
|
+
"job.idle": ({ workspace: id, job }) => workspace(id).job(job).idle(),
|
|
227
|
+
"job.stop": ({ workspace: id, job }) => workspace(id).job(job).stop(),
|
|
228
|
+
"job.settled": ({ workspace: id, job }, { signal }) => workspace(id).job(job).settled({ signal }),
|
|
229
|
+
"files.read": async ({ workspace: id, path }) => (await files(id)).read(path),
|
|
230
|
+
"files.bytes": async ({ workspace: id, path }) => {
|
|
231
|
+
const reader = await (await files(id)).bytes(path);
|
|
232
|
+
const version = "version" in reader && typeof reader.version === "string" ? reader.version : null;
|
|
233
|
+
return version === null ? { reader } : { reader, headers: { "X-Nyte-Version": version } };
|
|
234
|
+
},
|
|
235
|
+
"files.stat": async ({ workspace: id, path }) => (await files(id)).stat(path),
|
|
236
|
+
"files.write": async ({ workspace: id, path, options }, { body }) => (await files(id)).write(path, await readBytes(body), options),
|
|
237
|
+
"files.remove": async ({ workspace: id, path, options }) => (await files(id)).remove(path, options),
|
|
238
|
+
"files.batch": async ({ workspace: id, entries, id: receipt }) => ({
|
|
239
|
+
receipt: (await wire.batch(id, await files(id), entries, receipt)).id
|
|
240
|
+
}),
|
|
241
|
+
"files.format": async ({ workspace: id, path, contents }) => (await files(id)).format(path, contents),
|
|
242
|
+
"files.scan": async ({ workspace: id, directory, ignored }) => (await files(id)).scan({ directory, ignored }),
|
|
243
|
+
"files.find": async ({ workspace: id, query, limit }) => (await files(id)).find({ query, limit }),
|
|
244
|
+
"files.search": async ({ workspace: id, ...input }) => (await files(id)).search(input),
|
|
245
|
+
"files.watch": async ({ workspace: id, paths }) => (await files(id)).watch({ paths }),
|
|
246
|
+
"files.upload": async ({ workspace: id }, { body }) => (await files(id)).upload(readChunks(body)),
|
|
247
|
+
"git.status": async ({ workspace: id }) => (await git(id)).status(),
|
|
248
|
+
"git.watch": async ({ workspace: id }) => (await git(id)).watch(),
|
|
249
|
+
"git.changes": async ({ workspace: id, scope, options }) => (await git(id)).changes(scope, options),
|
|
250
|
+
"git.watchChanges": async ({ workspace: id, scope, options }) => (await git(id)).watchChanges(scope, options),
|
|
251
|
+
"git.patches": async ({ workspace: id, scope, paths, options }) => mapped((await git(id)).patches(scope, paths, options), patchesWire),
|
|
252
|
+
"git.contents": async ({ workspace: id, path, scope }) => (await git(id)).contents(path, scope),
|
|
253
|
+
"git.log": async ({ workspace: id, cursor, limit }) => (await git(id)).log({ cursor, limit }),
|
|
254
|
+
"git.refs": async ({ workspace: id }) => (await git(id)).refs(),
|
|
255
|
+
"git.blame": async ({ workspace: id, path }) => (await git(id)).blame(path),
|
|
256
|
+
"git.stage": async ({ workspace: id, paths, options }) => (await git(id)).stage(paths, options),
|
|
257
|
+
"git.unstage": async ({ workspace: id, paths, options }) => (await git(id)).unstage(paths, options),
|
|
258
|
+
"git.discard": async ({ workspace: id, paths, options }) => (await git(id)).discard(paths, options),
|
|
259
|
+
"git.commit": async ({ workspace: id, input, options }) => (await git(id)).commit(input, options),
|
|
260
|
+
"git.branch": async ({ workspace: id, input, options }) => (await git(id)).branch(input, options),
|
|
261
|
+
"git.push": async ({ workspace: id, input, options }) => (await git(id)).push(input, options),
|
|
262
|
+
"github.account": () => connection.github.account(),
|
|
263
|
+
"github.signIn": () => connection.github.signIn(),
|
|
264
|
+
"github.signOut": () => connection.github.signOut(),
|
|
265
|
+
"github.state": async ({ workspace: id }) => (await github(id)).state(),
|
|
266
|
+
"github.createPullRequest": async ({ workspace: id, input }) => (await github(id)).createPullRequest(input),
|
|
267
|
+
"browser.open": async ({ workspace: id, url, id: key }) => {
|
|
268
|
+
const api = await browser(id);
|
|
269
|
+
return describePage(hold(await wire.openPage({
|
|
270
|
+
id: key,
|
|
271
|
+
input: { workspace: id, url },
|
|
272
|
+
open: () => api.open({ url })
|
|
273
|
+
})));
|
|
274
|
+
},
|
|
275
|
+
"browser.adopt": async ({ workspace: id, id: page }) => describePage(hold(await (await browser(id)).adopt(page))),
|
|
276
|
+
"browser.list": async ({ workspace: id }) => (await browser(id)).list(),
|
|
277
|
+
"browser.watch": async ({ workspace: id }) => (await browser(id)).watch(),
|
|
278
|
+
"page.view": async ({ workspace: id, page }) => (await findPage(id, page)).view(),
|
|
279
|
+
"page.watch": async ({ workspace: id, page }) => (await findPage(id, page)).watch(),
|
|
280
|
+
"page.snapshot": async ({ workspace: id, page, ref }) => (await findPage(id, page)).snapshot({ ref }),
|
|
281
|
+
"page.navigate": async ({ workspace: id, page, url }) => (await findPage(id, page)).navigate(url),
|
|
282
|
+
"page.back": async ({ workspace: id, page }) => (await findPage(id, page)).back(),
|
|
283
|
+
"page.forward": async ({ workspace: id, page }) => (await findPage(id, page)).forward(),
|
|
284
|
+
"page.reload": async ({ workspace: id, page }) => (await findPage(id, page)).reload(),
|
|
285
|
+
"page.stopLoading": async ({ workspace: id, page }) => (await findPage(id, page)).stopLoading(),
|
|
286
|
+
"page.click": async ({ workspace: id, page, ref, button, double, expect }) => (await findPage(id, page)).click({ ref, button, double, expect }),
|
|
287
|
+
"page.type": async ({ workspace: id, page, ref, text, clear, submit, expect }) => (await findPage(id, page)).type({ ref, text, clear, submit, expect }),
|
|
288
|
+
"page.press": async ({ workspace: id, page, key, ref }) => (await findPage(id, page)).press({ key, ref }),
|
|
289
|
+
"page.scroll": async ({ workspace: id, page, direction, ref, pages: count }) => (await findPage(id, page)).scroll({ direction, ref, pages: count }),
|
|
290
|
+
"page.wait": async ({ workspace: id, page, condition }) => (await findPage(id, page)).wait(condition),
|
|
291
|
+
"page.console": async ({ workspace: id, page, limit, clear }) => (await findPage(id, page)).console({ limit, clear }),
|
|
292
|
+
"page.capture": async ({ workspace: id, page }) => ({
|
|
293
|
+
reader: await (await findPage(id, page)).capture()
|
|
294
|
+
}),
|
|
295
|
+
"page.evaluate": async ({ workspace: id, page, expression, options }) => (await findPage(id, page)).evaluate(expression, options),
|
|
296
|
+
"page.close": async ({ page }) => {
|
|
297
|
+
await release(page);
|
|
298
|
+
return null;
|
|
299
|
+
},
|
|
300
|
+
"plugins.replace": ({ plugins, scope }) => connection.plugins.replace(plugins, scope),
|
|
301
|
+
"plugins.check": ({ plugins }) => connection.plugins.check(plugins),
|
|
302
|
+
"principals.list": async () => (await connection.principals.list()).map((view) => ({
|
|
303
|
+
...view,
|
|
304
|
+
authority: [...view.authority]
|
|
305
|
+
})),
|
|
306
|
+
"principals.pair": ({ authority, label }) => connection.principals.pair({ authority: new Set(authority), label }),
|
|
307
|
+
"principals.revoke": async ({ id }) => {
|
|
308
|
+
await connection.principals.revoke(id);
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
async function* jobChanges(lists) {
|
|
314
|
+
let previous = null;
|
|
315
|
+
for await (const jobs of lists) {
|
|
316
|
+
if (previous === null)
|
|
317
|
+
yield { kind: "jobs", jobs };
|
|
318
|
+
else {
|
|
319
|
+
const kept = new Set(jobs.map((job) => job.id));
|
|
320
|
+
const unmoved = new Set(previous);
|
|
321
|
+
for (const job of previous)
|
|
322
|
+
if (!kept.has(job.id))
|
|
323
|
+
yield { kind: "forgotten", id: job.id };
|
|
324
|
+
for (const job of jobs)
|
|
325
|
+
if (!unmoved.has(job))
|
|
326
|
+
yield { kind: "job", job };
|
|
327
|
+
}
|
|
328
|
+
previous = jobs;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function* readChunks(body) {
|
|
332
|
+
if (body === null)
|
|
333
|
+
return;
|
|
334
|
+
const reader = body.getReader();
|
|
335
|
+
try {
|
|
336
|
+
for (;; ) {
|
|
337
|
+
const read = await reader.read();
|
|
338
|
+
if (read.done)
|
|
339
|
+
return;
|
|
340
|
+
yield read.value;
|
|
341
|
+
}
|
|
342
|
+
} finally {
|
|
343
|
+
reader.releaseLock();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async function readBytes(body) {
|
|
347
|
+
const chunks = [];
|
|
348
|
+
for await (const chunk of readChunks(body))
|
|
349
|
+
chunks.push(chunk);
|
|
350
|
+
const bytes = new Uint8Array(chunks.reduce((size, chunk) => size + chunk.byteLength, 0));
|
|
351
|
+
let offset = 0;
|
|
352
|
+
for (const chunk of chunks) {
|
|
353
|
+
bytes.set(chunk, offset);
|
|
354
|
+
offset += chunk.byteLength;
|
|
355
|
+
}
|
|
356
|
+
return bytes;
|
|
357
|
+
}
|
|
358
|
+
function hostWire(view, principal) {
|
|
359
|
+
return { ...view, authority: [...view.authority], principal };
|
|
360
|
+
}
|
|
361
|
+
function patchesWire(set) {
|
|
362
|
+
return { revision: set.revision, entries: Object.fromEntries(set.entries) };
|
|
363
|
+
}
|
|
364
|
+
function capabilityWire(capability) {
|
|
365
|
+
if (capability.kind !== "available")
|
|
366
|
+
return capability;
|
|
367
|
+
return { kind: "available" };
|
|
368
|
+
}
|
|
369
|
+
function available(capability, what) {
|
|
370
|
+
if (capability.kind === "available")
|
|
371
|
+
return capability.api;
|
|
372
|
+
if (capability.kind === "denied")
|
|
373
|
+
fail("denied", `${what}: ${capability.reason}`);
|
|
374
|
+
return fail("unavailable", `${what}: ${capability.reason}`);
|
|
375
|
+
}
|
|
376
|
+
function toJson(value) {
|
|
377
|
+
return isJson(value) ? value : null;
|
|
378
|
+
}
|
|
379
|
+
function principalKey(principal, name) {
|
|
380
|
+
return JSON.stringify([principal, name]);
|
|
381
|
+
}
|
|
382
|
+
function fail(code, message) {
|
|
383
|
+
throw new SdkError(code, message);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export { bindConnection2 };
|