@vornrun/connector-sdk 0.7.0-beta.8 → 0.7.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/README.md +268 -3
- package/dist/check-62s2GvcO.d.ts +1137 -0
- package/dist/chunk-ZKHXHE3O.js +3511 -0
- package/dist/cli.d.ts +9 -2
- package/dist/cli.js +83 -13
- package/dist/index.d.ts +180 -121
- package/dist/index.js +86 -34
- package/package.json +2 -2
- package/dist/chunk-NXZBUV63.js +0 -922
- package/dist/pack-C3ZJx9d4.d.ts +0 -340
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { B as BundleRequest, a as BundleOutput } from './
|
|
2
|
+
import { B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-62s2GvcO.js';
|
|
3
3
|
|
|
4
4
|
interface CliDeps {
|
|
5
5
|
load(modulePath: string): Promise<unknown>;
|
|
@@ -9,7 +9,14 @@ interface CliDeps {
|
|
|
9
9
|
cwd?: string;
|
|
10
10
|
/** Replaced in tests so pack does not shell out to a bundler. */
|
|
11
11
|
bundle?(request: BundleRequest): Promise<BundleOutput>;
|
|
12
|
+
/** Replaced in tests so pack does not start the staged bundle. */
|
|
13
|
+
launch?(dir: string): Promise<CheckFinding[]>;
|
|
14
|
+
/** Writes a scaffold file or a receipt; replaced in tests so nothing touches disk. */
|
|
15
|
+
writeFile?(path: string, contents: string): Promise<void>;
|
|
16
|
+
/** Replaced in tests beside writeFile. */
|
|
17
|
+
exists?(path: string): boolean;
|
|
12
18
|
}
|
|
13
19
|
declare function runCli(argv: string[], deps: CliDeps): Promise<number>;
|
|
20
|
+
declare function isEntryPoint(moduleUrl: string, argv?: readonly string[]): boolean;
|
|
14
21
|
|
|
15
|
-
export { type CliDeps, runCli };
|
|
22
|
+
export { type CliDeps, isEntryPoint, runCli };
|
package/dist/cli.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
checkConnector,
|
|
4
3
|
connectionSetup,
|
|
5
4
|
connectorManifest,
|
|
5
|
+
esbuildBundle,
|
|
6
6
|
formatFindings,
|
|
7
7
|
packConnector,
|
|
8
8
|
resolveConfig,
|
|
9
|
+
runConformance,
|
|
9
10
|
runPoll,
|
|
11
|
+
scaffoldFiles,
|
|
10
12
|
serveConnector
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZKHXHE3O.js";
|
|
12
14
|
|
|
13
15
|
// src/cli.ts
|
|
14
|
-
import { pathToFileURL } from "url";
|
|
15
|
-
import {
|
|
16
|
-
|
|
16
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
17
|
+
import { existsSync, realpathSync } from "fs";
|
|
18
|
+
import { dirname, join, resolve } from "path";
|
|
19
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
20
|
+
var USAGE = `vorn-connector <command> <module | id> [options]
|
|
17
21
|
|
|
18
22
|
Commands:
|
|
23
|
+
new <id> Scaffold a new connector, ready to build
|
|
19
24
|
manifest <module> Print the connector manifest as JSON
|
|
20
25
|
setup <module> [trigger] Print the Vorn connection settings to paste
|
|
21
26
|
check <module> Verify the connector against Vorn's contract
|
|
@@ -27,8 +32,13 @@ Options:
|
|
|
27
32
|
--since <iso> Lower bound passed to poll
|
|
28
33
|
--limit <n> Maximum items to request
|
|
29
34
|
--live Let check poll for real using the environment
|
|
30
|
-
--
|
|
31
|
-
|
|
35
|
+
--mock Run every action against served HTTP, not the network
|
|
36
|
+
--receipt <file> Where check writes what it verified, as JSON
|
|
37
|
+
--out <dir> Directory new and pack write to
|
|
38
|
+
--name <name> Display name for a new connector
|
|
39
|
+
--repo-conventions Scaffold a package shaped for the connectors repository
|
|
40
|
+
--extension Scaffold an extension \u2014 footers, panes and link handlers`;
|
|
41
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["live", "mock", "repo-conventions", "extension"]);
|
|
32
42
|
function parseArgs(args) {
|
|
33
43
|
const flags = {};
|
|
34
44
|
const positional = [];
|
|
@@ -58,7 +68,7 @@ function pickConnector(loaded, modulePath) {
|
|
|
58
68
|
const connector = candidate;
|
|
59
69
|
if (!connector || typeof connector !== "object" || !Array.isArray(connector.triggers)) {
|
|
60
70
|
throw new Error(
|
|
61
|
-
`${modulePath} does not export a connector built with defineConnector() (default or named "connector")`
|
|
71
|
+
`${modulePath} does not export a connector built with defineConnector() or defineExtension() (default or named "connector")`
|
|
62
72
|
);
|
|
63
73
|
}
|
|
64
74
|
return connector;
|
|
@@ -70,11 +80,37 @@ async function runCli(argv, deps) {
|
|
|
70
80
|
return command ? 0 : 1;
|
|
71
81
|
}
|
|
72
82
|
if (!modulePath) {
|
|
73
|
-
deps.write(`Missing
|
|
83
|
+
deps.write(`Missing <${command === "new" ? "id" : "module"}> argument
|
|
74
84
|
|
|
75
85
|
${USAGE}`);
|
|
76
86
|
return 1;
|
|
77
87
|
}
|
|
88
|
+
if (command === "new") {
|
|
89
|
+
const { flags: flags2 } = parseArgs(rest);
|
|
90
|
+
if (!deps.writeFile) {
|
|
91
|
+
deps.write("This build cannot write files");
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
const files = scaffoldFiles({
|
|
95
|
+
id: modulePath,
|
|
96
|
+
...flags2.name !== void 0 && { name: flags2.name },
|
|
97
|
+
...flags2["repo-conventions"] === "true" && { repoConventions: true },
|
|
98
|
+
...flags2.extension === "true" && { kind: "extension" }
|
|
99
|
+
});
|
|
100
|
+
const root = join(flags2.out ?? deps.cwd ?? ".", modulePath);
|
|
101
|
+
if ((deps.exists ?? existsSync)(root)) {
|
|
102
|
+
deps.write(`${root} already exists; a scaffold never overwrites`);
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
await deps.writeFile(join(root, file.path), file.contents);
|
|
107
|
+
}
|
|
108
|
+
deps.write(`Created ${modulePath} in ${root}`);
|
|
109
|
+
for (const file of files) deps.write(` ${file.path}`);
|
|
110
|
+
deps.write(`
|
|
111
|
+
Next: cd ${root} && yarn install && yarn check`);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
78
114
|
const connector = pickConnector(await deps.load(modulePath), modulePath);
|
|
79
115
|
const { flags, positional } = parseArgs(rest);
|
|
80
116
|
switch (command) {
|
|
@@ -98,14 +134,33 @@ ${USAGE}`);
|
|
|
98
134
|
return 0;
|
|
99
135
|
}
|
|
100
136
|
case "check": {
|
|
101
|
-
const
|
|
137
|
+
const packaged = flags.mock === "true" ? {
|
|
138
|
+
mock: true,
|
|
139
|
+
packageDir: deps.cwd ?? process.cwd(),
|
|
140
|
+
entry: modulePath,
|
|
141
|
+
bundle: deps.bundle ?? esbuildBundle
|
|
142
|
+
} : {};
|
|
143
|
+
const run = await runConformance(connector, {
|
|
144
|
+
...packaged,
|
|
102
145
|
...flags.live === "true" && {
|
|
103
146
|
live: true,
|
|
104
147
|
config: resolveConfig(connector, deps.env ?? process.env)
|
|
105
148
|
}
|
|
106
149
|
});
|
|
150
|
+
const { findings } = run;
|
|
107
151
|
const errors = findings.filter((item) => item.level === "error");
|
|
108
152
|
if (findings.length > 0) deps.write(formatFindings(findings));
|
|
153
|
+
if (flags.receipt !== void 0) {
|
|
154
|
+
if (run.receipt) {
|
|
155
|
+
const write = deps.writeFile ?? ((path, contents) => writeFile(path, contents));
|
|
156
|
+
await write(flags.receipt, `${JSON.stringify(run.receipt, null, 2)}
|
|
157
|
+
`);
|
|
158
|
+
deps.write(`Verified ${run.receipt.checks.join(", ")} \u2014 wrote ${flags.receipt}`);
|
|
159
|
+
} else {
|
|
160
|
+
deps.write(`No receipt written: nothing could be vouched for`);
|
|
161
|
+
if (errors.length === 0) return 1;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
109
164
|
deps.write(
|
|
110
165
|
errors.length > 0 ? `
|
|
111
166
|
${errors.length} error(s), ${findings.length - errors.length} warning(s)` : `
|
|
@@ -118,7 +173,8 @@ ${connector.id} passed with ${findings.length} warning(s)`
|
|
|
118
173
|
entry: modulePath,
|
|
119
174
|
...flags.out !== void 0 && { outDir: flags.out },
|
|
120
175
|
...deps.cwd !== void 0 && { resolveDir: deps.cwd },
|
|
121
|
-
...deps.bundle !== void 0 && { bundle: deps.bundle }
|
|
176
|
+
...deps.bundle !== void 0 && { bundle: deps.bundle },
|
|
177
|
+
...deps.launch !== void 0 && { launch: deps.launch }
|
|
122
178
|
});
|
|
123
179
|
if (result.findings.length > 0) deps.write(formatFindings(result.findings));
|
|
124
180
|
const errors = result.findings.filter((item) => item.level === "error");
|
|
@@ -164,12 +220,25 @@ ${USAGE}`);
|
|
|
164
220
|
return 1;
|
|
165
221
|
}
|
|
166
222
|
}
|
|
167
|
-
|
|
223
|
+
function isEntryPoint(moduleUrl, argv = process.argv) {
|
|
224
|
+
const invoked = argv[1];
|
|
225
|
+
if (invoked === void 0) return false;
|
|
226
|
+
try {
|
|
227
|
+
return realpathSync(fileURLToPath(moduleUrl)) === realpathSync(resolve(invoked));
|
|
228
|
+
} catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
var invokedDirectly = isEntryPoint(import.meta.url);
|
|
168
233
|
if (invokedDirectly) {
|
|
169
234
|
runCli(process.argv.slice(2), {
|
|
170
235
|
load: (modulePath) => modulePath.startsWith(".") || modulePath.startsWith("/") ? import(pathToFileURL(resolve(modulePath)).href) : import(modulePath),
|
|
171
236
|
write: (line) => process.stdout.write(`${line}
|
|
172
|
-
`)
|
|
237
|
+
`),
|
|
238
|
+
writeFile: async (path, contents) => {
|
|
239
|
+
await mkdir(dirname(path), { recursive: true });
|
|
240
|
+
await writeFile(path, contents);
|
|
241
|
+
}
|
|
173
242
|
}).then((code) => {
|
|
174
243
|
process.exitCode = code;
|
|
175
244
|
}).catch((error) => {
|
|
@@ -179,5 +248,6 @@ if (invokedDirectly) {
|
|
|
179
248
|
});
|
|
180
249
|
}
|
|
181
250
|
export {
|
|
251
|
+
isEntryPoint,
|
|
182
252
|
runCli
|
|
183
253
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { E as ExtensionPermission, b as ExtensionHostMethod, c as ConnectorDefinition, d as Connector, e as ExtensionDefinition, f as ConnectorConfig, g as ExtensionHost, T as TriggerDefinition, P as PollContext, h as PollOutcome, i as ConnectorItem, N as NormalizedItem, j as PostReceiveOp, A as ActionRequest, B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-62s2GvcO.js';
|
|
2
|
+
export { k as ActionContext, l as ActionDefinition, m as ActionInputField, n as ActionInputOption, o as ActionInputType, p as ActionOutputField, q as ActivationPredicate, r as AuthRung, s as BrowserSignIn, t as CHECK_OWNERS, u as CheckCode, v as CheckOptions, w as ConformanceRun, x as ConnectionSetup, y as ConnectorAuth, z as ConnectorConfigField, D as ConnectorHarness, F as ConnectorIcon, G as ConnectorKind, H as ConnectorManifest, I as ConnectorVerification, J as DedupeStrategy, K as DefaultWorkflow, L as ExtensionAgent, M as ExtensionContext, O as ExtensionContributions, Q as ExtensionPlatform, R as ExtensionUsage, S as ExtensionUsageWindow, U as FetchContext, V as FooterContribution, W as FooterItem, X as HarnessOptions, Y as LinkContext, Z as LinkHandled, _ as LinkHandlerContribution, $ as MANIFEST_TOOL, a0 as MAX_PACK_BYTES, a1 as MAX_POLL_PAGES, a2 as ManifestContributions, a3 as MockCall, a4 as MockHostAnswers, a5 as MockHostRun, a6 as MockRoute, a7 as MockRouteMissError, a8 as MockRun, a9 as OPTIONS_TOOL, aa as OptionsContext, ab as OptionsLoader, ac as PREFLIGHT_TOOL, ad as PaginationStrategy, ae as PaneContribution, af as PollPage, ag as PreflightResult, ah as ResilientFetchOptions, ai as RetryPolicy, aj as RunActionOptions, ak as RunPollOptions, al as SessionContext, am as StatusSuggestion, an as backoffMs, ao as bundleDependencyFindings, ap as bundledRequireFindings, aq as checkConnector, ar as connectionSetup, as as connectorManifest, at as createConnectorHarness, au as drainPoll, av as esbuildBundle, aw as escapedMockHttp, ax as footerToolName, ay as formatFindings, az as handlerToolName, aA as lifecycleScriptFindings, aB as mockExtensionHost, aC as pollToolName, aD as readNearestPackageJson, aE as resilientFetch, aF as retryAfterMs, aG as runAction, aH as runConformance, aI as runOptions, aJ as runPoll, aK as withMockHttp } from './check-62s2GvcO.js';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
|
|
5
|
+
/** Everything an extension may ask the host for; anything else is not grantable. */
|
|
6
|
+
declare const EXTENSION_PERMISSIONS: ExtensionPermission[];
|
|
7
|
+
/** What each host method costs, read by the bridge that grants it and the check that gates it. */
|
|
8
|
+
declare const HOST_PERMISSIONS: Record<ExtensionHostMethod, ExtensionPermission>;
|
|
5
9
|
/** Environment variable a config field reads from, e.g. `apiToken` → `API_TOKEN`. */
|
|
6
10
|
declare function envNameFor(key: string, explicit?: string): string;
|
|
7
11
|
/**
|
|
@@ -12,6 +16,15 @@ declare function envNameFor(key: string, explicit?: string): string;
|
|
|
12
16
|
* MCP tool once the connector is already installed in someone's app.
|
|
13
17
|
*/
|
|
14
18
|
declare function defineConnector(definition: ConnectorDefinition): Connector;
|
|
19
|
+
/**
|
|
20
|
+
* Validate an extension and fill in its defaults.
|
|
21
|
+
*
|
|
22
|
+
* An extension is a pack like a connector, so it goes through the same
|
|
23
|
+
* manifest, pack, check and catalog; what differs is that it contributes to a
|
|
24
|
+
* session card rather than polling a service. Failing here — at import time —
|
|
25
|
+
* keeps a mistyped permission or an unreachable page from reaching a card.
|
|
26
|
+
*/
|
|
27
|
+
declare function defineExtension(definition: ExtensionDefinition): Connector;
|
|
15
28
|
/**
|
|
16
29
|
* Read the connector's declared config out of the environment. Vorn supplies
|
|
17
30
|
* these through the connection's `env` / `secretEnv` maps, so a missing
|
|
@@ -20,6 +33,64 @@ declare function defineConnector(definition: ConnectorDefinition): Connector;
|
|
|
20
33
|
*/
|
|
21
34
|
declare function resolveConfig(connector: Connector, env?: NodeJS.ProcessEnv): ConnectorConfig;
|
|
22
35
|
|
|
36
|
+
/**
|
|
37
|
+
* How an extension asks the host for what it was granted.
|
|
38
|
+
*
|
|
39
|
+
* The extension runs as its own process, so the bridge is an HTTP endpoint the
|
|
40
|
+
* host serves and names in the environment, with a token that says which
|
|
41
|
+
* extension is calling. The host grants exactly the permissions the manifest
|
|
42
|
+
* declared, which is why a call outside them comes back refused rather than
|
|
43
|
+
* empty — the same answer the check's stub gives, so an extension meets the
|
|
44
|
+
* rule once rather than twice.
|
|
45
|
+
*/
|
|
46
|
+
/** Where the host answers, and the token that says who is asking. */
|
|
47
|
+
declare const HOST_URL_ENV = "VORN_EXTENSION_HOST";
|
|
48
|
+
declare const HOST_TOKEN_ENV = "VORN_EXTENSION_TOKEN";
|
|
49
|
+
/** The host refused a call the extension's manifest never asked for. */
|
|
50
|
+
declare class PermissionDeniedError extends Error {
|
|
51
|
+
constructor(method: string, detail: string);
|
|
52
|
+
}
|
|
53
|
+
interface HostBridgeOptions {
|
|
54
|
+
sessionId: string;
|
|
55
|
+
env?: NodeJS.ProcessEnv;
|
|
56
|
+
/** Replaced in tests so nothing opens a socket. */
|
|
57
|
+
fetchImpl?: typeof fetch;
|
|
58
|
+
}
|
|
59
|
+
/** The host as an extension process reaches it, over the bridge Vorn served it. */
|
|
60
|
+
declare function createExtensionHost(options: HostBridgeOptions): ExtensionHost;
|
|
61
|
+
|
|
62
|
+
/** Where Vorn serves a browser-sign-in connector the window it signed in through. */
|
|
63
|
+
declare const BROWSER_HOST_ENV = "VORN_BROWSER_HOST";
|
|
64
|
+
declare const BROWSER_TOKEN_ENV = "VORN_BROWSER_TOKEN";
|
|
65
|
+
/** The tool call a window request belongs to, so Vorn can tell a step's own requests from another's. */
|
|
66
|
+
declare const SESSION_CALL_META = "vorn/sessionCall";
|
|
67
|
+
declare const SESSION_CALL_HEADER = "x-vorn-session-call";
|
|
68
|
+
/** The signed-in window could not make the call: Vorn is closed, too old, or not the caller. */
|
|
69
|
+
declare class SessionUnavailableError extends Error {
|
|
70
|
+
/** Asking again cannot bring the window back, so the SDK's retries let this through at once. */
|
|
71
|
+
readonly retryable = false;
|
|
72
|
+
constructor(message: string);
|
|
73
|
+
}
|
|
74
|
+
/** Vorn refused the call itself, for instance because it is off the connector's origins. */
|
|
75
|
+
declare class SessionRefusedError extends Error {
|
|
76
|
+
readonly retryable = false;
|
|
77
|
+
constructor(message: string);
|
|
78
|
+
}
|
|
79
|
+
interface SessionFetchOptions {
|
|
80
|
+
env?: NodeJS.ProcessEnv;
|
|
81
|
+
/** Replaced in tests so nothing opens a socket. */
|
|
82
|
+
fetchImpl?: typeof fetch;
|
|
83
|
+
/** The key of the tool call these requests belong to, from its MCP metadata. */
|
|
84
|
+
call?: string;
|
|
85
|
+
}
|
|
86
|
+
/** A fetch whose requests run inside the connection's signed-in Vorn window, so no cookie reaches this process. */
|
|
87
|
+
declare function createSessionFetch(options?: SessionFetchOptions): typeof fetch;
|
|
88
|
+
|
|
89
|
+
/** An origin a connector may act on: `https://host`, or `https://*.host` for every subdomain. */
|
|
90
|
+
declare const ORIGIN_PATTERN: RegExp;
|
|
91
|
+
/** Whether `url` is on one of the declared origins. */
|
|
92
|
+
declare function withinOrigins(origins: readonly string[], url: string): boolean;
|
|
93
|
+
|
|
23
94
|
/**
|
|
24
95
|
* Run a declarative trigger: call the author's `fetch`, then apply the chosen
|
|
25
96
|
* dedupe strategy.
|
|
@@ -46,119 +117,99 @@ declare function normalizeItem(item: ConnectorItem, polledAt: string): Normalize
|
|
|
46
117
|
*/
|
|
47
118
|
declare function normalizeItems(items: ConnectorItem[], polledAt: string): NormalizedItem[];
|
|
48
119
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
interface
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
cursor?: string;
|
|
58
|
-
limit?: number;
|
|
59
|
-
now?: () => string;
|
|
120
|
+
/** The value at a dotted path, or undefined if any step is missing. */
|
|
121
|
+
declare function valueAt(value: unknown, path: string): unknown;
|
|
122
|
+
/** Run a response through the declared ops, left to right. */
|
|
123
|
+
declare function applyPostReceive(value: unknown, ops: PostReceiveOp[] | undefined): unknown;
|
|
124
|
+
|
|
125
|
+
interface RequestScope {
|
|
126
|
+
args: Record<string, unknown>;
|
|
127
|
+
config: ConnectorConfig;
|
|
60
128
|
}
|
|
61
|
-
/** Longest chain of pages `drainPoll` will follow before calling it a bug. */
|
|
62
|
-
declare const MAX_POLL_PAGES = 1000;
|
|
63
129
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
130
|
+
* How a substituted value is written into its surroundings.
|
|
131
|
+
*
|
|
132
|
+
* A value's meaning depends on where it lands: a path segment has to be
|
|
133
|
+
* escaped, a header has characters it may not contain at all. Passing that
|
|
134
|
+
* decision in means the substitution is made safe once, here, instead of by
|
|
135
|
+
* every author who interpolates an argument.
|
|
66
136
|
*/
|
|
67
|
-
|
|
137
|
+
type Substitution = (value: string, source: 'args' | 'config') => string;
|
|
68
138
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
139
|
+
* Resolve `{{args.x}}` and `{{config.y}}` inside a value.
|
|
140
|
+
*
|
|
141
|
+
* A whole-string placeholder keeps the referenced value's own type, so a body
|
|
142
|
+
* can carry a number or an object; a placeholder among other text is rendered
|
|
143
|
+
* into the string. An unset reference resolves to `undefined` on its own and to
|
|
144
|
+
* the empty string when it is part of a larger one, which is what lets an
|
|
145
|
+
* optional argument simply not appear.
|
|
146
|
+
*
|
|
147
|
+
* With a `substitute`, every resolved value passes through it — including a
|
|
148
|
+
* whole-string one, which then arrives as text rather than keeping its type,
|
|
149
|
+
* because a place that needs escaping is a place that holds a string.
|
|
72
150
|
*/
|
|
73
|
-
declare function
|
|
74
|
-
interface
|
|
75
|
-
|
|
76
|
-
|
|
151
|
+
declare function resolveTemplates(value: unknown, scope: RequestScope, substitute?: Substitution): unknown;
|
|
152
|
+
interface ResolvedRequest {
|
|
153
|
+
url: string;
|
|
154
|
+
method: string;
|
|
155
|
+
headers: Record<string, string>;
|
|
156
|
+
body?: string;
|
|
77
157
|
}
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
declare function runAction(connector: Connector, actionType: string, args: Record<string, unknown>, options?: RunActionOptions): Promise<Record<string, unknown>>;
|
|
84
|
-
|
|
85
|
-
/** MCP tool name a trigger is served under. */
|
|
86
|
-
declare function pollToolName(triggerType: string): string;
|
|
87
|
-
/** Tool that reports the connector's manifest and setup hints. */
|
|
88
|
-
declare const MANIFEST_TOOL = "vorn_connector_manifest";
|
|
89
|
-
/**
|
|
90
|
-
* Tool that reports whether the connector can run right now. Present only when
|
|
91
|
-
* the connector declares a `preflight`, so its absence means "nothing to
|
|
92
|
-
* check" rather than "check passed".
|
|
93
|
-
*/
|
|
94
|
-
declare const PREFLIGHT_TOOL = "vorn_connector_preflight";
|
|
95
|
-
interface ConnectionSetup {
|
|
96
|
-
connectorId: string;
|
|
97
|
-
triggerType: string;
|
|
98
|
-
/** Values to paste into Vorn's MCP connection form. */
|
|
99
|
-
filters: {
|
|
100
|
-
pollTool: string;
|
|
101
|
-
itemsPath: 'items';
|
|
102
|
-
idField: 'externalId';
|
|
103
|
-
timestampField: 'updatedAt';
|
|
104
|
-
titleField: 'title';
|
|
105
|
-
urlField: 'url';
|
|
106
|
-
cursorArg: 'cursor';
|
|
107
|
-
cursorPath: 'nextCursor';
|
|
108
|
-
};
|
|
109
|
-
/** Environment variable names the connector reads. */
|
|
110
|
-
env: Array<{
|
|
111
|
-
name: string;
|
|
112
|
-
required: boolean;
|
|
113
|
-
secret: boolean;
|
|
114
|
-
description?: string;
|
|
115
|
-
}>;
|
|
158
|
+
/** Build the exact call a declared request makes, with its templates resolved. */
|
|
159
|
+
declare function resolveRequest(request: ActionRequest, scope: RequestScope): ResolvedRequest;
|
|
160
|
+
interface SendOptions {
|
|
161
|
+
fetchImpl: typeof fetch;
|
|
116
162
|
}
|
|
117
163
|
/**
|
|
118
|
-
*
|
|
164
|
+
* The action's result, as Vorn stores it.
|
|
119
165
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* connector back its own cursor each poll, which is what lets its dedupe
|
|
124
|
-
* strategy — rather than Vorn's timestamp comparison — decide what is new.
|
|
166
|
+
* A step's output is a record, so a response that is a list becomes `items` —
|
|
167
|
+
* the name the rest of this SDK already uses for one — and any other bare
|
|
168
|
+
* value becomes `result`.
|
|
125
169
|
*/
|
|
126
|
-
declare function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
170
|
+
declare function asOutput(value: unknown): Record<string, unknown>;
|
|
171
|
+
/** Longest chain of pages a declared request will follow before calling it a bug. */
|
|
172
|
+
declare const MAX_REQUEST_PAGES = 100;
|
|
173
|
+
/** The URL of the next page, as a paged HTTP API states it in its `Link` header. */
|
|
174
|
+
declare function nextLink(header: string | null): string | undefined;
|
|
175
|
+
/** Run a declared request end to end: resolve, send, follow its pages, reshape. */
|
|
176
|
+
declare function executeRequest(request: ActionRequest, postReceive: PostReceiveOp[] | undefined, scope: RequestScope, options: SendOptions): Promise<Record<string, unknown>>;
|
|
177
|
+
|
|
178
|
+
interface PackOptions {
|
|
179
|
+
/** Module specifier the connector was loaded from, bundled as the pack entry. */
|
|
180
|
+
entry: string;
|
|
181
|
+
/** Directory the `.vorn.tgz` is written to; defaults to the working directory. */
|
|
182
|
+
outDir?: string;
|
|
183
|
+
/** Directory module specifiers resolve from; defaults to the working directory. */
|
|
184
|
+
resolveDir?: string;
|
|
185
|
+
/** SDK specifier the generated stdio entry imports; overridden in tests. */
|
|
186
|
+
sdkModule?: string;
|
|
187
|
+
/** Size ceiling for the written archive; defaults to `MAX_PACK_BYTES`. */
|
|
188
|
+
maxBytes?: number;
|
|
189
|
+
/** Size ceiling for what the archive unpacks to; defaults to `MAX_UNPACKED_BYTES`. */
|
|
190
|
+
maxUnpackedBytes?: number;
|
|
191
|
+
/** Replaced in tests so packing does not shell out to a bundler. */
|
|
192
|
+
bundle?(request: BundleRequest): Promise<BundleOutput>;
|
|
193
|
+
/** Replaced in tests whose subject is the archive rather than the launch; defaults to starting it for real. */
|
|
194
|
+
launch?(dir: string): Promise<CheckFinding[]>;
|
|
195
|
+
}
|
|
196
|
+
interface PackResult {
|
|
197
|
+
findings: CheckFinding[];
|
|
198
|
+
/** Absolute path of the written pack; absent when a gate failed. */
|
|
199
|
+
file?: string;
|
|
200
|
+
bytes?: number;
|
|
154
201
|
}
|
|
155
|
-
/**
|
|
156
|
-
declare function
|
|
202
|
+
/** File name Vorn recognizes as a connector pack. */
|
|
203
|
+
declare function packFileName(connector: Connector): string;
|
|
204
|
+
/** The entry is generated, not the author's bin, so every pack launches alike. */
|
|
205
|
+
declare function packConnector(connector: Connector, options: PackOptions): Promise<PackResult>;
|
|
157
206
|
|
|
158
207
|
interface ConnectorServerOptions {
|
|
159
208
|
/** Resolved connector configuration. Defaults to reading `process.env`. */
|
|
160
209
|
config?: ConnectorConfig;
|
|
161
210
|
now?: () => string;
|
|
211
|
+
/** The host an extension's contributions talk to; defaults to the bridge Vorn served. */
|
|
212
|
+
host?(sessionId: string): ExtensionHost;
|
|
162
213
|
}
|
|
163
214
|
/**
|
|
164
215
|
* Expose a connector as an MCP server.
|
|
@@ -172,28 +223,36 @@ declare function createConnectorServer(connector: Connector, options?: Connector
|
|
|
172
223
|
/** Serve a connector on stdio. This is the one line a connector's bin needs. */
|
|
173
224
|
declare function serveConnector(connector: Connector, options?: ConnectorServerOptions): Promise<void>;
|
|
174
225
|
|
|
175
|
-
interface HarnessOptions {
|
|
176
|
-
config?: ConnectorConfig;
|
|
177
|
-
/** Fixed clock, so `updatedAt` defaults and cursors are deterministic. */
|
|
178
|
-
now?: () => string;
|
|
179
|
-
}
|
|
180
|
-
interface ConnectorHarness {
|
|
181
|
-
poll(triggerType: string, options?: RunPollOptions): Promise<PollPage>;
|
|
182
|
-
drain(triggerType: string, options?: RunPollOptions): Promise<NormalizedItem[]>;
|
|
183
|
-
execute(actionType: string, args?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
184
|
-
manifest(): ConnectorManifest;
|
|
185
|
-
/**
|
|
186
|
-
* Poll repeatedly the way Vorn does — carrying the newest `updatedAt`
|
|
187
|
-
* forward as the watermark — and return only items a real installation
|
|
188
|
-
* would treat as new. Catches the classic connector bug where a poll
|
|
189
|
-
* ignores its lower bound and re-delivers the same backlog forever.
|
|
190
|
-
*/
|
|
191
|
-
pollTwice(triggerType: string, options?: RunPollOptions): Promise<NormalizedItem[]>;
|
|
192
|
-
}
|
|
193
226
|
/**
|
|
194
|
-
*
|
|
195
|
-
*
|
|
227
|
+
* The files a new connector starts as.
|
|
228
|
+
*
|
|
229
|
+
* A connector is mostly boilerplate — a package that builds, an entry that
|
|
230
|
+
* serves, a definition, a test that proves it without a network — and getting
|
|
231
|
+
* that boilerplate right is the slowest part of writing the interesting bit.
|
|
232
|
+
* Generating it means every connector starts from the same shape, which is
|
|
233
|
+
* also the shape `check` and `pack` expect to find.
|
|
234
|
+
*
|
|
235
|
+
* The files are returned rather than written so the decision of what to write
|
|
236
|
+
* stays testable, and the writing stays in the CLI.
|
|
196
237
|
*/
|
|
197
|
-
|
|
238
|
+
interface ScaffoldOptions {
|
|
239
|
+
id: string;
|
|
240
|
+
/** Defaults to the id in title case. */
|
|
241
|
+
name?: string;
|
|
242
|
+
description?: string;
|
|
243
|
+
/** Emit the shape the connectors repository expects of a package inside it. */
|
|
244
|
+
repoConventions?: boolean;
|
|
245
|
+
/** What to start: a connector that polls a service, or an extension that contributes to a card. */
|
|
246
|
+
kind?: 'connector' | 'extension';
|
|
247
|
+
}
|
|
248
|
+
interface ScaffoldFile {
|
|
249
|
+
/** Relative to the directory the connector is created in. */
|
|
250
|
+
path: string;
|
|
251
|
+
contents: string;
|
|
252
|
+
}
|
|
253
|
+
/** `acme-tickets` → `Acme Tickets`, so a generated name reads like a name. */
|
|
254
|
+
declare function titleCase(id: string): string;
|
|
255
|
+
/** Every file a new connector or extension starts with, ready to build, check and pack. */
|
|
256
|
+
declare function scaffoldFiles(options: ScaffoldOptions): ScaffoldFile[];
|
|
198
257
|
|
|
199
|
-
export {
|
|
258
|
+
export { ActionRequest, BROWSER_HOST_ENV, BROWSER_TOKEN_ENV, BundleOutput, BundleRequest, CheckFinding, Connector, ConnectorConfig, ConnectorDefinition, ConnectorItem, type ConnectorServerOptions, EXTENSION_PERMISSIONS, ExtensionDefinition, ExtensionHost, ExtensionHostMethod, ExtensionPermission, HOST_PERMISSIONS, HOST_TOKEN_ENV, HOST_URL_ENV, type HostBridgeOptions, MAX_REQUEST_PAGES, NormalizedItem, ORIGIN_PATTERN, type PackOptions, type PackResult, PermissionDeniedError, PollContext, PollOutcome, PostReceiveOp, type RequestScope, type ResolvedRequest, SESSION_CALL_HEADER, SESSION_CALL_META, type ScaffoldFile, type ScaffoldOptions, type SessionFetchOptions, SessionRefusedError, SessionUnavailableError, type Substitution, TriggerDefinition, applyPostReceive, asOutput, createConnectorServer, createExtensionHost, createSessionFetch, defineConnector, defineExtension, envNameFor, executeRequest, nextLink, normalizeItem, normalizeItems, packConnector, packFileName, pollWithDedupe, resolveConfig, resolveRequest, resolveTemplates, scaffoldFiles, serveConnector, titleCase, valueAt, withinOrigins };
|