@aexhq/sdk 0.13.6
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 +201 -0
- package/README.md +160 -0
- package/dist/_contracts/connection-ticket.d.ts +21 -0
- package/dist/_contracts/connection-ticket.js +49 -0
- package/dist/_contracts/event-envelope.d.ts +276 -0
- package/dist/_contracts/event-envelope.js +324 -0
- package/dist/_contracts/event-stream-client.d.ts +47 -0
- package/dist/_contracts/event-stream-client.js +141 -0
- package/dist/_contracts/http.d.ts +35 -0
- package/dist/_contracts/http.js +114 -0
- package/dist/_contracts/index.d.ts +28 -0
- package/dist/_contracts/index.js +29 -0
- package/dist/_contracts/managed-key.d.ts +74 -0
- package/dist/_contracts/managed-key.js +110 -0
- package/dist/_contracts/operations.d.ts +237 -0
- package/dist/_contracts/operations.js +632 -0
- package/dist/_contracts/provider-support.d.ts +220 -0
- package/dist/_contracts/provider-support.js +90 -0
- package/dist/_contracts/proxy-protocol.d.ts +257 -0
- package/dist/_contracts/proxy-protocol.js +234 -0
- package/dist/_contracts/proxy-validation.d.ts +19 -0
- package/dist/_contracts/proxy-validation.js +51 -0
- package/dist/_contracts/run-artifacts.d.ts +47 -0
- package/dist/_contracts/run-artifacts.js +101 -0
- package/dist/_contracts/run-config.d.ts +304 -0
- package/dist/_contracts/run-config.js +659 -0
- package/dist/_contracts/run-cost.d.ts +125 -0
- package/dist/_contracts/run-cost.js +616 -0
- package/dist/_contracts/run-custody.d.ts +226 -0
- package/dist/_contracts/run-custody.js +465 -0
- package/dist/_contracts/run-record.d.ts +127 -0
- package/dist/_contracts/run-record.js +177 -0
- package/dist/_contracts/run-retention.d.ts +213 -0
- package/dist/_contracts/run-retention.js +484 -0
- package/dist/_contracts/run-unit.d.ts +194 -0
- package/dist/_contracts/run-unit.js +215 -0
- package/dist/_contracts/runner-event.d.ts +114 -0
- package/dist/_contracts/runner-event.js +187 -0
- package/dist/_contracts/runtime-manifest.d.ts +106 -0
- package/dist/_contracts/runtime-manifest.js +98 -0
- package/dist/_contracts/runtime-security-profile.d.ts +27 -0
- package/dist/_contracts/runtime-security-profile.js +82 -0
- package/dist/_contracts/runtime-sizes.d.ts +144 -0
- package/dist/_contracts/runtime-sizes.js +136 -0
- package/dist/_contracts/runtime-types.d.ts +212 -0
- package/dist/_contracts/runtime-types.js +2 -0
- package/dist/_contracts/sdk-errors.d.ts +34 -0
- package/dist/_contracts/sdk-errors.js +52 -0
- package/dist/_contracts/sdk-secrets.d.ts +31 -0
- package/dist/_contracts/sdk-secrets.js +220 -0
- package/dist/_contracts/side-effect-audit.d.ts +129 -0
- package/dist/_contracts/side-effect-audit.js +494 -0
- package/dist/_contracts/sse.d.ts +74 -0
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +26 -0
- package/dist/_contracts/stable.js +44 -0
- package/dist/_contracts/status.d.ts +19 -0
- package/dist/_contracts/status.js +61 -0
- package/dist/_contracts/submission.d.ts +383 -0
- package/dist/_contracts/submission.js +1380 -0
- package/dist/agents-md.d.ts +46 -0
- package/dist/agents-md.js +83 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +66 -0
- package/dist/asset-upload.js +168 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.d.ts +33 -0
- package/dist/bundle.js +89 -0
- package/dist/bundle.js.map +1 -0
- package/dist/cli.mjs +4140 -0
- package/dist/cli.mjs.sha256 +1 -0
- package/dist/client.d.ts +460 -0
- package/dist/client.js +857 -0
- package/dist/client.js.map +1 -0
- package/dist/fetch-archive.d.ts +16 -0
- package/dist/fetch-archive.js +170 -0
- package/dist/fetch-archive.js.map +1 -0
- package/dist/file.d.ts +57 -0
- package/dist/file.js +153 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +84 -0
- package/dist/mcp-server.js +114 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/node-fs.d.ts +12 -0
- package/dist/node-fs.js +44 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +117 -0
- package/dist/skill.js +169 -0
- package/dist/skill.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/cleanup.md +38 -0
- package/docs/credentials.md +153 -0
- package/docs/events.md +76 -0
- package/docs/mcp.md +47 -0
- package/docs/outputs.md +157 -0
- package/docs/product-boundaries.md +57 -0
- package/docs/provider-runtime-capabilities.md +103 -0
- package/docs/quickstart.md +110 -0
- package/docs/release.md +99 -0
- package/docs/run-config.md +53 -0
- package/docs/run-record.md +39 -0
- package/docs/skills.md +139 -0
- package/docs/testing.md +29 -0
- package/package.json +47 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side consumer of the event coordinator's WebSocket stream.
|
|
3
|
+
*
|
|
4
|
+
* One mechanism for catch-up + resume + live: subscribe = read-from-cursor +
|
|
5
|
+
* tail. The consumer opens a WS to the coordinator with a connection ticket,
|
|
6
|
+
* replays from its cursor, and yields {@link AexEvent}s as they arrive.
|
|
7
|
+
* On a transport drop it reconnects with backoff and resumes from the last
|
|
8
|
+
* sequence it saw — `from = lastSeq + 1` — so delivery is exactly-once across
|
|
9
|
+
* reconnects (no gap, no duplicate). It stops on a terminal event, on abort,
|
|
10
|
+
* or when the caller breaks the iterator.
|
|
11
|
+
*
|
|
12
|
+
* Filtering and projection are the client's concern (the wire carries the
|
|
13
|
+
* whole run): compose {@link filterStream} with the envelope guards, and
|
|
14
|
+
* {@link mapStream} with {@link toAGUI}, on top of this stream.
|
|
15
|
+
*
|
|
16
|
+
* The WebSocket is injectable so the SDK/CLI use the Node/global `WebSocket`
|
|
17
|
+
* (Node 22+ ships it; no dependency) and tests drive a fake.
|
|
18
|
+
*/
|
|
19
|
+
const isTerminalType = (t) => t === "RUN_FINISHED" || t === "RUN_ERROR";
|
|
20
|
+
export async function* streamCoordinatorEvents(opts) {
|
|
21
|
+
const makeWs = opts.webSocketFactory ?? ((url) => new WebSocket(url));
|
|
22
|
+
const reconnectDelayMs = opts.reconnectDelayMs ?? 500;
|
|
23
|
+
const maxReconnects = opts.maxReconnects ?? Number.POSITIVE_INFINITY;
|
|
24
|
+
let cursor = (opts.from ?? 0) - 1;
|
|
25
|
+
let attempts = 0;
|
|
26
|
+
let done = false;
|
|
27
|
+
while (!done && !opts.signal?.aborted) {
|
|
28
|
+
const ticket = await opts.fetchTicket();
|
|
29
|
+
const url = `${opts.wsUrl}?ticket=${encodeURIComponent(ticket)}&from=${cursor + 1}`;
|
|
30
|
+
const ws = makeWs(url);
|
|
31
|
+
const queue = [];
|
|
32
|
+
let closed = false;
|
|
33
|
+
let disconnectReason = "";
|
|
34
|
+
let resolveNext = null;
|
|
35
|
+
const wake = () => {
|
|
36
|
+
if (resolveNext) {
|
|
37
|
+
const r = resolveNext;
|
|
38
|
+
resolveNext = null;
|
|
39
|
+
r();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
ws.addEventListener("message", (ev) => {
|
|
43
|
+
const data = typeof ev.data === "string" ? ev.data : "";
|
|
44
|
+
if (!data)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
const evt = JSON.parse(data);
|
|
48
|
+
if (typeof evt.sequence === "number" && evt.sequence > cursor) {
|
|
49
|
+
queue.push(evt);
|
|
50
|
+
wake();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// ignore a non-JSON frame
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
ws.addEventListener("close", (ev) => {
|
|
58
|
+
closed = true;
|
|
59
|
+
const code = ev?.code;
|
|
60
|
+
disconnectReason = `close${typeof code === "number" ? ` code=${code}` : ""}`;
|
|
61
|
+
wake();
|
|
62
|
+
});
|
|
63
|
+
ws.addEventListener("error", () => {
|
|
64
|
+
closed = true;
|
|
65
|
+
disconnectReason = "error";
|
|
66
|
+
wake();
|
|
67
|
+
});
|
|
68
|
+
const onAbort = () => {
|
|
69
|
+
closeQuietly(ws);
|
|
70
|
+
closed = true;
|
|
71
|
+
wake();
|
|
72
|
+
};
|
|
73
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
74
|
+
try {
|
|
75
|
+
while (true) {
|
|
76
|
+
while (queue.length > 0) {
|
|
77
|
+
const evt = queue.shift();
|
|
78
|
+
cursor = evt.sequence;
|
|
79
|
+
yield evt;
|
|
80
|
+
if (isTerminalType(evt.type))
|
|
81
|
+
done = true;
|
|
82
|
+
}
|
|
83
|
+
if (done || opts.signal?.aborted) {
|
|
84
|
+
closeQuietly(ws);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
if (closed)
|
|
88
|
+
break; // transport ended → fall through to reconnect
|
|
89
|
+
await new Promise((resolve) => {
|
|
90
|
+
resolveNext = resolve;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
96
|
+
}
|
|
97
|
+
if (done || opts.signal?.aborted)
|
|
98
|
+
return;
|
|
99
|
+
attempts += 1;
|
|
100
|
+
// Don't let the stream die silently — a give-up before the terminal event
|
|
101
|
+
// is exactly the case a caller needs to see (it looks like a clean end
|
|
102
|
+
// otherwise). Reconnects are rare, so the warn volume is bounded.
|
|
103
|
+
if (attempts > maxReconnects) {
|
|
104
|
+
console.warn(`[aex] event stream gave up after ${maxReconnects} reconnect attempt(s) (last: ${disconnectReason || "unknown"}); ended before a terminal event at seq ${cursor + 1}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
console.warn(`[aex] event stream disconnected (${disconnectReason || "unknown"}); reconnecting attempt ${attempts} from seq ${cursor + 1}`);
|
|
108
|
+
await sleep(reconnectDelayMs, opts.signal);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Async-iterable filter — keep only events matching the predicate. */
|
|
112
|
+
export async function* filterStream(stream, predicate) {
|
|
113
|
+
for await (const event of stream) {
|
|
114
|
+
if (predicate(event))
|
|
115
|
+
yield event;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Async-iterable map — project each event (e.g. with `toAGUI`). */
|
|
119
|
+
export async function* mapStream(stream, project) {
|
|
120
|
+
for await (const event of stream) {
|
|
121
|
+
yield project(event);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function closeQuietly(ws) {
|
|
125
|
+
try {
|
|
126
|
+
ws.close();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// already closed
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function sleep(ms, signal) {
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
const timer = setTimeout(resolve, ms);
|
|
135
|
+
signal?.addEventListener("abort", () => {
|
|
136
|
+
clearTimeout(timer);
|
|
137
|
+
resolve();
|
|
138
|
+
}, { once: true });
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=event-stream-client.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
2
|
+
/**
|
|
3
|
+
* Sink for local debug traces. Receives one preformatted line per HTTP
|
|
4
|
+
* round-trip (method, path, status, elapsed). NEVER carries the auth
|
|
5
|
+
* header, request/response bodies, or query string — purely a local
|
|
6
|
+
* diagnostic; nothing is uploaded. The SDK wires this to `console.error`
|
|
7
|
+
* when `debug` is set; the CLI wires it to stderr under `--debug`.
|
|
8
|
+
*/
|
|
9
|
+
export type DebugSink = (line: string) => void;
|
|
10
|
+
export interface HttpClientOptions {
|
|
11
|
+
/**
|
|
12
|
+
* API plane root. Optional — defaults to `AEX_DEFAULT_BASE_URL`
|
|
13
|
+
* (`https://api.aex.dev`). Self-hosted deployments override with their
|
|
14
|
+
* own URL; no env var consults this value.
|
|
15
|
+
*/
|
|
16
|
+
readonly baseUrl?: string;
|
|
17
|
+
readonly apiToken: string;
|
|
18
|
+
readonly fetch?: FetchLike;
|
|
19
|
+
/** When set, every request emits a redacted one-line trace here. */
|
|
20
|
+
readonly debug?: DebugSink;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Thin transport used by every BFF-bound operation. The SDK class and
|
|
24
|
+
* the CLI subcommands BOTH build an `HttpClient` and pass it to the
|
|
25
|
+
* operations module — so they cannot drift in how they auth, encode
|
|
26
|
+
* query parameters, or decode error responses.
|
|
27
|
+
*/
|
|
28
|
+
export declare class HttpClient {
|
|
29
|
+
#private;
|
|
30
|
+
constructor(options: HttpClientOptions);
|
|
31
|
+
request<T>(path: string, init?: RequestInit, query?: Record<string, string>): Promise<T>;
|
|
32
|
+
download(path: string, init?: RequestInit, query?: Record<string, string>): Promise<{
|
|
33
|
+
readonly response: Response;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AexApiError } from "./sdk-errors.js";
|
|
2
|
+
import { AEX_DEFAULT_BASE_URL } from "./stable.js";
|
|
3
|
+
/**
|
|
4
|
+
* Thin transport used by every BFF-bound operation. The SDK class and
|
|
5
|
+
* the CLI subcommands BOTH build an `HttpClient` and pass it to the
|
|
6
|
+
* operations module — so they cannot drift in how they auth, encode
|
|
7
|
+
* query parameters, or decode error responses.
|
|
8
|
+
*/
|
|
9
|
+
export class HttpClient {
|
|
10
|
+
#baseUrl;
|
|
11
|
+
#apiToken;
|
|
12
|
+
#fetch;
|
|
13
|
+
#debug;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
if (!options.apiToken) {
|
|
16
|
+
throw new Error("HttpClient: apiToken is required");
|
|
17
|
+
}
|
|
18
|
+
const raw = options.baseUrl ?? AEX_DEFAULT_BASE_URL;
|
|
19
|
+
const normalized = raw.endsWith("/") ? raw : `${raw}/`;
|
|
20
|
+
this.#baseUrl = new URL(normalized);
|
|
21
|
+
this.#apiToken = options.apiToken;
|
|
22
|
+
this.#fetch = options.fetch ?? fetch;
|
|
23
|
+
this.#debug = options.debug;
|
|
24
|
+
}
|
|
25
|
+
/** Emit a redacted round-trip trace (no auth header, body, or query). */
|
|
26
|
+
#trace(method, url, status, startedMs) {
|
|
27
|
+
this.#debug?.(`[aex] ${(method ?? "GET").toUpperCase()} ${url.pathname} -> ${status} ${Date.now() - startedMs}ms`);
|
|
28
|
+
}
|
|
29
|
+
async request(path, init = {}, query = {}) {
|
|
30
|
+
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
31
|
+
for (const [key, value] of Object.entries(query)) {
|
|
32
|
+
url.searchParams.set(key, value);
|
|
33
|
+
}
|
|
34
|
+
const headers = {
|
|
35
|
+
accept: "application/json",
|
|
36
|
+
authorization: `Bearer ${this.#apiToken}`,
|
|
37
|
+
...normalizeHeaders(init.headers)
|
|
38
|
+
};
|
|
39
|
+
if (init.body !== undefined && init.body !== null && !headers["content-type"]) {
|
|
40
|
+
// Default to JSON only for string-shaped bodies. FormData / Blob /
|
|
41
|
+
// ArrayBuffer / streams set their own content-type (and FormData
|
|
42
|
+
// specifically needs fetch to compute the multipart boundary), so
|
|
43
|
+
// we leave content-type untouched for non-string bodies.
|
|
44
|
+
if (typeof init.body === "string") {
|
|
45
|
+
headers["content-type"] = "application/json";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const startedMs = Date.now();
|
|
49
|
+
const response = await this.#fetch(url, { ...init, headers });
|
|
50
|
+
this.#trace(init.method, url, response.status, startedMs);
|
|
51
|
+
const body = await readJson(response);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new AexApiError(response.status, extractErrorMessage(body), body);
|
|
54
|
+
}
|
|
55
|
+
return body;
|
|
56
|
+
}
|
|
57
|
+
async download(path, init = {}, query = {}) {
|
|
58
|
+
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
59
|
+
for (const [key, value] of Object.entries(query)) {
|
|
60
|
+
url.searchParams.set(key, value);
|
|
61
|
+
}
|
|
62
|
+
const headers = {
|
|
63
|
+
authorization: `Bearer ${this.#apiToken}`,
|
|
64
|
+
...normalizeHeaders(init.headers)
|
|
65
|
+
};
|
|
66
|
+
const startedMs = Date.now();
|
|
67
|
+
const response = await this.#fetch(url, { ...init, headers });
|
|
68
|
+
this.#trace(init.method, url, response.status, startedMs);
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
const body = await readJson(response);
|
|
71
|
+
throw new AexApiError(response.status, extractErrorMessage(body), body);
|
|
72
|
+
}
|
|
73
|
+
return { response };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function normalizeHeaders(headers) {
|
|
77
|
+
if (!headers)
|
|
78
|
+
return {};
|
|
79
|
+
if (headers instanceof Headers)
|
|
80
|
+
return Object.fromEntries(headers.entries());
|
|
81
|
+
if (Array.isArray(headers))
|
|
82
|
+
return Object.fromEntries(headers);
|
|
83
|
+
return headers;
|
|
84
|
+
}
|
|
85
|
+
async function readJson(response) {
|
|
86
|
+
const text = await response.text();
|
|
87
|
+
if (text.length === 0)
|
|
88
|
+
return {};
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(text);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return { raw: text };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function extractErrorMessage(body) {
|
|
97
|
+
if (body && typeof body === "object") {
|
|
98
|
+
const obj = body;
|
|
99
|
+
if (typeof obj.error === "string")
|
|
100
|
+
return obj.error;
|
|
101
|
+
if (obj.error && typeof obj.error === "object" && "message" in obj.error) {
|
|
102
|
+
const message = obj.error.message;
|
|
103
|
+
if (typeof message === "string")
|
|
104
|
+
return message;
|
|
105
|
+
}
|
|
106
|
+
// aex Worker error envelope: `{ ok:false, code, message }`. Surface
|
|
107
|
+
// the server's message so structured rejections (e.g. runtime support)
|
|
108
|
+
// aren't flattened to the generic fallback below.
|
|
109
|
+
if (typeof obj.message === "string")
|
|
110
|
+
return obj.message;
|
|
111
|
+
}
|
|
112
|
+
return "aex API request failed";
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export * from "./proxy-protocol.js";
|
|
2
|
+
export * from "./provider-support.js";
|
|
3
|
+
export * from "./status.js";
|
|
4
|
+
export * from "./submission.js";
|
|
5
|
+
export * from "./runtime-sizes.js";
|
|
6
|
+
export * from "./runner-event.js";
|
|
7
|
+
export * from "./event-envelope.js";
|
|
8
|
+
export * from "./connection-ticket.js";
|
|
9
|
+
export * from "./event-stream-client.js";
|
|
10
|
+
export * from "./run-unit.js";
|
|
11
|
+
export * from "./runtime-manifest.js";
|
|
12
|
+
export * from "./runtime-security-profile.js";
|
|
13
|
+
export * from "./run-record.js";
|
|
14
|
+
export * from "./run-cost.js";
|
|
15
|
+
export * from "./run-custody.js";
|
|
16
|
+
export * from "./run-retention.js";
|
|
17
|
+
export * from "./side-effect-audit.js";
|
|
18
|
+
export * from "./managed-key.js";
|
|
19
|
+
export * from "./stable.js";
|
|
20
|
+
export * from "./sdk-secrets.js";
|
|
21
|
+
export * from "./sdk-errors.js";
|
|
22
|
+
export * from "./run-config.js";
|
|
23
|
+
export * from "./runtime-types.js";
|
|
24
|
+
export * from "./http.js";
|
|
25
|
+
export * from "./run-artifacts.js";
|
|
26
|
+
export * as operations from "./operations.js";
|
|
27
|
+
export * from "./proxy-validation.js";
|
|
28
|
+
export * from "./sse.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from "./proxy-protocol.js";
|
|
2
|
+
export * from "./provider-support.js";
|
|
3
|
+
export * from "./status.js";
|
|
4
|
+
export * from "./submission.js";
|
|
5
|
+
export * from "./runtime-sizes.js";
|
|
6
|
+
export * from "./runner-event.js";
|
|
7
|
+
export * from "./event-envelope.js";
|
|
8
|
+
export * from "./connection-ticket.js";
|
|
9
|
+
export * from "./event-stream-client.js";
|
|
10
|
+
export * from "./run-unit.js";
|
|
11
|
+
export * from "./runtime-manifest.js";
|
|
12
|
+
export * from "./runtime-security-profile.js";
|
|
13
|
+
export * from "./run-record.js";
|
|
14
|
+
export * from "./run-cost.js";
|
|
15
|
+
export * from "./run-custody.js";
|
|
16
|
+
export * from "./run-retention.js";
|
|
17
|
+
export * from "./side-effect-audit.js";
|
|
18
|
+
export * from "./managed-key.js";
|
|
19
|
+
export * from "./stable.js";
|
|
20
|
+
export * from "./sdk-secrets.js";
|
|
21
|
+
export * from "./sdk-errors.js";
|
|
22
|
+
export * from "./run-config.js";
|
|
23
|
+
export * from "./runtime-types.js";
|
|
24
|
+
export * from "./http.js";
|
|
25
|
+
export * from "./run-artifacts.js";
|
|
26
|
+
export * as operations from "./operations.js";
|
|
27
|
+
export * from "./proxy-validation.js";
|
|
28
|
+
export * from "./sse.js";
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { RunProvider, RuntimeKind } from "./submission.js";
|
|
2
|
+
export declare const CREDENTIAL_MODES: readonly ["byok", "managed"];
|
|
3
|
+
export type CredentialMode = (typeof CREDENTIAL_MODES)[number];
|
|
4
|
+
export declare const DEFAULT_CREDENTIAL_MODE: CredentialMode;
|
|
5
|
+
export declare const MANAGED_KEY_POLICY_SCHEMA_VERSION = 1;
|
|
6
|
+
export declare const MANAGED_KEY_LAUNCH_STAGES: readonly ["blocked", "pilot", "ga"];
|
|
7
|
+
export type ManagedKeyLaunchStage = (typeof MANAGED_KEY_LAUNCH_STAGES)[number];
|
|
8
|
+
export declare const MANAGED_KEY_FEATURE_DECISIONS: readonly ["disabled", "allowed"];
|
|
9
|
+
export type ManagedKeyFeatureDecision = (typeof MANAGED_KEY_FEATURE_DECISIONS)[number];
|
|
10
|
+
export interface ManagedKeyFeaturePolicyV1 {
|
|
11
|
+
readonly files: ManagedKeyFeatureDecision;
|
|
12
|
+
readonly packages: ManagedKeyFeatureDecision;
|
|
13
|
+
readonly builtins: ManagedKeyFeatureDecision;
|
|
14
|
+
readonly mcpServers: ManagedKeyFeatureDecision;
|
|
15
|
+
readonly proxyEndpoints: ManagedKeyFeatureDecision;
|
|
16
|
+
readonly openNetworking: ManagedKeyFeatureDecision;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Public managed-key policy contract. Concrete policy values, account
|
|
20
|
+
* selection, financial calculation, and deployment wiring live outside this
|
|
21
|
+
* public module.
|
|
22
|
+
*/
|
|
23
|
+
export interface ManagedKeyPolicyV1 {
|
|
24
|
+
readonly schemaVersion: typeof MANAGED_KEY_POLICY_SCHEMA_VERSION;
|
|
25
|
+
readonly credentialMode: "managed";
|
|
26
|
+
readonly launchStage: ManagedKeyLaunchStage;
|
|
27
|
+
readonly serviceAvailable: boolean;
|
|
28
|
+
readonly billingRequired: true;
|
|
29
|
+
readonly providers: readonly RunProvider[];
|
|
30
|
+
readonly runtimes: readonly RuntimeKind[];
|
|
31
|
+
readonly models?: readonly string[];
|
|
32
|
+
readonly features: ManagedKeyFeaturePolicyV1;
|
|
33
|
+
}
|
|
34
|
+
export declare const BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1: ManagedKeyFeaturePolicyV1;
|
|
35
|
+
export declare const BLOCKED_MANAGED_KEY_POLICY_V1: ManagedKeyPolicyV1;
|
|
36
|
+
export declare class ManagedKeyUnavailableError extends Error {
|
|
37
|
+
readonly code = "managed_key_unavailable";
|
|
38
|
+
constructor(message?: string);
|
|
39
|
+
}
|
|
40
|
+
export declare function parseCredentialMode(input: unknown): CredentialMode;
|
|
41
|
+
export declare function credentialModeOrDefault(input: CredentialMode | undefined): CredentialMode;
|
|
42
|
+
export declare function isCredentialMode(input: unknown): input is CredentialMode;
|
|
43
|
+
export declare function isManagedKeyGenerallyAvailable(policy: ManagedKeyPolicyV1): boolean;
|
|
44
|
+
export declare function isManagedKeyAdmissionAllowed(policy: ManagedKeyPolicyV1): boolean;
|
|
45
|
+
export declare function assertManagedKeyModeAvailable(policy?: ManagedKeyPolicyV1): void;
|
|
46
|
+
export declare function assertManagedKeyAdmissionAllowed(policy?: ManagedKeyPolicyV1): void;
|
|
47
|
+
export interface ManagedCredentialResolutionInput {
|
|
48
|
+
readonly workspaceId: string;
|
|
49
|
+
readonly runId: string;
|
|
50
|
+
readonly provider: RunProvider;
|
|
51
|
+
readonly runtime: RuntimeKind;
|
|
52
|
+
readonly model: string;
|
|
53
|
+
readonly policy: ManagedKeyPolicyV1;
|
|
54
|
+
}
|
|
55
|
+
export interface ManagedCredentialLease {
|
|
56
|
+
readonly credentialMode: "managed";
|
|
57
|
+
readonly provider: RunProvider;
|
|
58
|
+
readonly runtime: RuntimeKind;
|
|
59
|
+
readonly custodyClass: "managed-provider-credential";
|
|
60
|
+
}
|
|
61
|
+
export type ManagedCredentialResolution = {
|
|
62
|
+
readonly ok: true;
|
|
63
|
+
readonly lease: ManagedCredentialLease;
|
|
64
|
+
} | {
|
|
65
|
+
readonly ok: false;
|
|
66
|
+
readonly code: "managed_key_unavailable" | "provider_not_allowed" | "runtime_not_allowed" | "model_not_allowed";
|
|
67
|
+
readonly message: string;
|
|
68
|
+
};
|
|
69
|
+
export interface ManagedCredentialResolver {
|
|
70
|
+
resolveManagedCredential(input: ManagedCredentialResolutionInput): Promise<ManagedCredentialResolution>;
|
|
71
|
+
}
|
|
72
|
+
export declare class FakeManagedCredentialResolver implements ManagedCredentialResolver {
|
|
73
|
+
resolveManagedCredential(input: ManagedCredentialResolutionInput): Promise<ManagedCredentialResolution>;
|
|
74
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export const CREDENTIAL_MODES = ["byok", "managed"];
|
|
2
|
+
export const DEFAULT_CREDENTIAL_MODE = "byok";
|
|
3
|
+
export const MANAGED_KEY_POLICY_SCHEMA_VERSION = 1;
|
|
4
|
+
export const MANAGED_KEY_LAUNCH_STAGES = ["blocked", "pilot", "ga"];
|
|
5
|
+
export const MANAGED_KEY_FEATURE_DECISIONS = ["disabled", "allowed"];
|
|
6
|
+
export const BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1 = Object.freeze({
|
|
7
|
+
files: "disabled",
|
|
8
|
+
packages: "disabled",
|
|
9
|
+
builtins: "disabled",
|
|
10
|
+
mcpServers: "disabled",
|
|
11
|
+
proxyEndpoints: "disabled",
|
|
12
|
+
openNetworking: "disabled"
|
|
13
|
+
});
|
|
14
|
+
export const BLOCKED_MANAGED_KEY_POLICY_V1 = Object.freeze({
|
|
15
|
+
schemaVersion: MANAGED_KEY_POLICY_SCHEMA_VERSION,
|
|
16
|
+
credentialMode: "managed",
|
|
17
|
+
launchStage: "blocked",
|
|
18
|
+
serviceAvailable: false,
|
|
19
|
+
billingRequired: true,
|
|
20
|
+
providers: Object.freeze([]),
|
|
21
|
+
runtimes: Object.freeze([]),
|
|
22
|
+
features: BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1
|
|
23
|
+
});
|
|
24
|
+
export class ManagedKeyUnavailableError extends Error {
|
|
25
|
+
code = "managed_key_unavailable";
|
|
26
|
+
constructor(message = "credentialMode: \"managed\" is not available") {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = "ManagedKeyUnavailableError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function parseCredentialMode(input) {
|
|
32
|
+
if (input === undefined) {
|
|
33
|
+
return DEFAULT_CREDENTIAL_MODE;
|
|
34
|
+
}
|
|
35
|
+
if (!isCredentialMode(input)) {
|
|
36
|
+
throw new Error(`credentialMode must be one of: ${CREDENTIAL_MODES.join(", ")} (got ${JSON.stringify(input)})`);
|
|
37
|
+
}
|
|
38
|
+
return input;
|
|
39
|
+
}
|
|
40
|
+
export function credentialModeOrDefault(input) {
|
|
41
|
+
return input ?? DEFAULT_CREDENTIAL_MODE;
|
|
42
|
+
}
|
|
43
|
+
export function isCredentialMode(input) {
|
|
44
|
+
return typeof input === "string" && CREDENTIAL_MODES.includes(input);
|
|
45
|
+
}
|
|
46
|
+
export function isManagedKeyGenerallyAvailable(policy) {
|
|
47
|
+
return policy.launchStage === "ga" && policy.serviceAvailable;
|
|
48
|
+
}
|
|
49
|
+
export function isManagedKeyAdmissionAllowed(policy) {
|
|
50
|
+
return policy.launchStage !== "blocked" && policy.serviceAvailable;
|
|
51
|
+
}
|
|
52
|
+
export function assertManagedKeyModeAvailable(policy = BLOCKED_MANAGED_KEY_POLICY_V1) {
|
|
53
|
+
if (!isManagedKeyGenerallyAvailable(policy)) {
|
|
54
|
+
throw new ManagedKeyUnavailableError();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function assertManagedKeyAdmissionAllowed(policy = BLOCKED_MANAGED_KEY_POLICY_V1) {
|
|
58
|
+
if (!isManagedKeyAdmissionAllowed(policy)) {
|
|
59
|
+
throw new ManagedKeyUnavailableError();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export class FakeManagedCredentialResolver {
|
|
63
|
+
async resolveManagedCredential(input) {
|
|
64
|
+
const denial = resolvePolicyDenial(input);
|
|
65
|
+
if (denial) {
|
|
66
|
+
return denial;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
ok: true,
|
|
70
|
+
lease: Object.freeze({
|
|
71
|
+
credentialMode: "managed",
|
|
72
|
+
provider: input.provider,
|
|
73
|
+
runtime: input.runtime,
|
|
74
|
+
custodyClass: "managed-provider-credential"
|
|
75
|
+
})
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function resolvePolicyDenial(input) {
|
|
80
|
+
if (!isManagedKeyGenerallyAvailable(input.policy)) {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
code: "managed_key_unavailable",
|
|
84
|
+
message: "managed-key mode is not generally available for this public policy"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (!input.policy.providers.includes(input.provider)) {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
code: "provider_not_allowed",
|
|
91
|
+
message: `provider ${input.provider} is not allowed by managed-key policy`
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (!input.policy.runtimes.includes(input.runtime)) {
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
code: "runtime_not_allowed",
|
|
98
|
+
message: `runtime ${input.runtime} is not allowed by managed-key policy`
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (input.policy.models && !input.policy.models.includes(input.model)) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
code: "model_not_allowed",
|
|
105
|
+
message: "model is not allowed by managed-key policy"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=managed-key.js.map
|