devframe 0.9.20 → 0.10.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/dist/_shared-B2PZsp-J.mjs +191 -0
- package/dist/{_shared-BIUet_Jh.d.mts → _shared-Dy1UBMUN.d.mts} +13 -14
- package/dist/adapters/build.d.mts +3 -4
- package/dist/adapters/build.mjs +4 -5
- package/dist/adapters/cac.d.mts +3 -4
- package/dist/adapters/cac.mjs +3 -3
- package/dist/adapters/dev.d.mts +8 -8
- package/dist/adapters/dev.mjs +2 -2
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/initiate.d.mts +8 -8
- package/dist/adapters/initiate.mjs +1 -1
- package/dist/adapters/mcp.d.mts +4 -142
- package/dist/adapters/mcp.mjs +1 -597
- package/dist/agentic-D4QQQUjE.d.mts +30 -0
- package/dist/cli/main.mjs +12 -260
- package/dist/client/index.d.mts +6 -6
- package/dist/client/index.mjs +3 -4
- package/dist/constants.d.mts +2 -1
- package/dist/constants.mjs +2 -1
- package/dist/{context-BA5FPz7K.d.mts → context-B4BKPuaa.d.mts} +1 -1
- package/dist/{context-BLXXjoBW.mjs → context-C141q8H4.mjs} +5 -5
- package/dist/{context-jXO5vzjH.mjs → context-CHpyLX8W.mjs} +1 -1
- package/dist/{context-BLHBDQcZ.d.mts → context-CTAxz9ec.d.mts} +108 -47
- package/dist/{dev-BdKKOH8S.mjs → dev-DM1mIlgi.mjs} +16 -24
- package/dist/{diagnostics-DZA6KQ_Z.mjs → diagnostics-Cx4_VjlG.mjs} +11 -3
- package/dist/dist-Bw3EbMj4.mjs +305 -0
- package/dist/dist-CO98PBnQ.mjs +265 -0
- package/dist/{host-agent-C3MBpNCd.mjs → host-agent-ZSKgzMVu.mjs} +2 -7
- package/dist/import-runtime-module-BzlEQ9PI.mjs +24 -0
- package/dist/in-page-channel/index.d.mts +2 -7
- package/dist/in-page-channel/index.mjs +1 -4
- package/dist/index-Bia1vKjL.d.mts +218 -0
- package/dist/{index-r6NstVmM.d.mts → index-CcPSKbxb.d.mts} +2 -2
- package/dist/index-CeEtxDmK.d.mts +78 -0
- package/dist/{index-CiA6C705.d.mts → index-DuEm0sDH.d.mts} +1 -1
- package/dist/index.d.mts +4 -11
- package/dist/index.mjs +1 -10
- package/dist/{instance-registry-DCq762YJ.mjs → instance-registry-DtvYxc0Y.mjs} +1 -1
- package/dist/{instance-shell-C6Vg97lg.d.mts → instance-shell-DOZSxst6.d.mts} +31 -5
- package/dist/{instance-shell-yfrM3_vK.mjs → instance-shell-wC2sfEU_.mjs} +7 -7
- package/dist/interactive-auth-BCa_iamv.mjs +384 -0
- package/dist/internal/index.d.mts +66 -22
- package/dist/internal/index.mjs +143 -8
- package/dist/mrmime-40h5OOIp.mjs +448 -0
- package/dist/node/auth.d.mts +2 -2
- package/dist/node/hub-internals.d.mts +2 -2
- package/dist/node/hub-internals.mjs +2 -2
- package/dist/node/index.d.mts +2 -4
- package/dist/node/index.mjs +2 -2
- package/dist/{nostics-0sKe5HIj.d.mts → nostics-DWvukRwa.d.mts} +11 -2
- package/dist/{origin-D_eBKEzr.mjs → origin-DZit9g29.mjs} +1 -21
- package/dist/recipes/interactive-auth.d.mts +2 -2
- package/dist/recipes/interactive-auth.mjs +1 -231
- package/dist/{remote-assets-D0StJVLp.mjs → remote-assets-B9MeWmW6.mjs} +2 -2
- package/dist/rpc/client.d.mts +1 -1
- package/dist/rpc/client.mjs +1 -1
- package/dist/rpc/dump.d.mts +2 -1
- package/dist/rpc/index.d.mts +3 -2
- package/dist/rpc/server.d.mts +1 -1
- package/dist/rpc/server.mjs +1 -1
- package/dist/rpc/transports/sse-client.d.mts +1 -1
- package/dist/rpc/transports/sse-server.d.mts +3 -3
- package/dist/rpc/transports/sse-server.mjs +1 -1
- package/dist/rpc/transports/ws-bun.d.mts +2 -2
- package/dist/rpc/transports/ws-bun.mjs +1 -1
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-deno.d.mts +2 -2
- package/dist/rpc/transports/ws-deno.mjs +1 -1
- package/dist/rpc/transports/ws-server.d.mts +1 -1
- package/dist/rpc/transports/ws-server.mjs +1 -1
- package/dist/{rpc-core-CvkU23bQ.mjs → rpc-core-BXyMjbKG.mjs} +1 -1
- package/dist/{rpc-core-BlL-Ip8n.d.mts → rpc-core-rLrwFEcw.d.mts} +4 -4
- package/dist/{services-install-Ben4yh52.mjs → services-install-D5YUwFXW.mjs} +17 -1
- package/dist/{sse-client-BcbYwXdD.d.mts → sse-client-DNdscfu_.d.mts} +2 -2
- package/dist/{storage-B70AXK64.mjs → storage-CHD1IkqU.mjs} +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/{types-D2vGd7-2.d.mts → types-BmDbfHCx.d.mts} +2 -3
- package/dist/utils/debounce.d.mts +50 -0
- package/dist/utils/debounce.mjs +88 -0
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/launch-editor.d.mts +8 -0
- package/dist/utils/launch-editor.mjs +36 -1
- package/dist/utils/nostics.d.mts +2 -2
- package/dist/utils/remote-assets.mjs +1 -1
- package/dist/utils/serve-static.mjs +1 -1
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/simple-schema.d.mts +3 -2
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/url.d.mts +31 -0
- package/dist/utils/url.mjs +58 -0
- package/dist/{ws-client-CNpP6Ium.d.mts → ws-client-6Mrz6eC4.d.mts} +2 -2
- package/dist/{ws-server-BB8jhxeT.d.mts → ws-server-y2R76aSW.d.mts} +2 -2
- package/package.json +10 -11
- package/dist/_shared-U8D-xzrp.mjs +0 -115
- package/dist/agent-tool-name-DGzeuWcO.mjs +0 -31
- package/dist/client-assets-DNdhagGm.mjs +0 -16
- package/dist/nostics-DD6gsDZA.mjs +0 -108
- package/dist/recipes/common-rpc-functions.d.mts +0 -70
- package/dist/recipes/common-rpc-functions.mjs +0 -115
- package/dist/simple-schema-Bi40l-P6.mjs +0 -154
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { s as colors } from "./nostics-D0PvLZsn.mjs";
|
|
2
|
+
import { n as defineRpcFunction } from "./define-BLWPsH6y.mjs";
|
|
3
|
+
import { isAnonymousRpcMethod } from "./constants.mjs";
|
|
4
|
+
import { a as getTempAuthCodeInfo, n as describeUA, o as refreshTempAuthCode, r as exchangeTempAuthCode, s as verifyAuthToken, t as buildOtpAuthUrl } from "./state-W4wI6X5X.mjs";
|
|
5
|
+
import { t as getInternalContext } from "./context-CHpyLX8W.mjs";
|
|
6
|
+
//#region src/utils/simple-schema.ts
|
|
7
|
+
function ok(value) {
|
|
8
|
+
return { value };
|
|
9
|
+
}
|
|
10
|
+
function fail(message, path) {
|
|
11
|
+
return { issues: [path ? {
|
|
12
|
+
message,
|
|
13
|
+
path
|
|
14
|
+
} : { message }] };
|
|
15
|
+
}
|
|
16
|
+
function make(type, validate, extra) {
|
|
17
|
+
return {
|
|
18
|
+
type,
|
|
19
|
+
...extra,
|
|
20
|
+
"~standard": {
|
|
21
|
+
version: 1,
|
|
22
|
+
vendor: "devframe",
|
|
23
|
+
validate
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Run a Standard Schema synchronously, rejecting async validators. */
|
|
28
|
+
function runSync(schema, value) {
|
|
29
|
+
const result = schema["~standard"].validate(value);
|
|
30
|
+
if (result instanceof Promise) throw new TypeError("[devframe/utils/simple-schema] async validators are not supported inside object()/optional()/nullable()");
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/** Any string. */
|
|
34
|
+
function string() {
|
|
35
|
+
return make("string", (v) => typeof v === "string" ? ok(v) : fail("Expected a string"));
|
|
36
|
+
}
|
|
37
|
+
/** A finite number (rejects `NaN`). */
|
|
38
|
+
function number() {
|
|
39
|
+
return make("number", (v) => typeof v === "number" && !Number.isNaN(v) ? ok(v) : fail("Expected a number"));
|
|
40
|
+
}
|
|
41
|
+
/** A boolean. */
|
|
42
|
+
function boolean() {
|
|
43
|
+
return make("boolean", (v) => typeof v === "boolean" ? ok(v) : fail("Expected a boolean"));
|
|
44
|
+
}
|
|
45
|
+
/** `undefined`, mirroring valibot's `void`. */
|
|
46
|
+
function voidType() {
|
|
47
|
+
return make("void", (v) => v === void 0 ? ok(void 0) : fail("Expected undefined"));
|
|
48
|
+
}
|
|
49
|
+
/** `null`. */
|
|
50
|
+
function nullType() {
|
|
51
|
+
return make("null", (v) => v === null ? ok(null) : fail("Expected null"));
|
|
52
|
+
}
|
|
53
|
+
/** One of a fixed set of literal values. */
|
|
54
|
+
function picklist(values) {
|
|
55
|
+
const set = new Set(values);
|
|
56
|
+
return make("picklist", (v) => set.has(v) ? ok(v) : fail(`Expected one of: ${values.join(", ")}`), { values });
|
|
57
|
+
}
|
|
58
|
+
/** A single literal value (string / number / boolean). */
|
|
59
|
+
function literal(value) {
|
|
60
|
+
return make("literal", (v) => v === value ? ok(v) : fail(`Expected ${JSON.stringify(value)}`), { value });
|
|
61
|
+
}
|
|
62
|
+
/** A value matching any one of the given schemas. */
|
|
63
|
+
function union(options) {
|
|
64
|
+
return make("union", (v) => {
|
|
65
|
+
const issues = [];
|
|
66
|
+
for (const option of options) {
|
|
67
|
+
const result = runSync(option, v);
|
|
68
|
+
if (!result.issues) return ok(v);
|
|
69
|
+
issues.push(...result.issues);
|
|
70
|
+
}
|
|
71
|
+
return { issues };
|
|
72
|
+
}, { options });
|
|
73
|
+
}
|
|
74
|
+
/** A record with string keys whose values each satisfy the value schema. */
|
|
75
|
+
function record(_key, value) {
|
|
76
|
+
return make("record", (v) => {
|
|
77
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) return fail("Expected an object");
|
|
78
|
+
const obj = v;
|
|
79
|
+
const issues = [];
|
|
80
|
+
for (const key of Object.keys(obj)) {
|
|
81
|
+
const result = runSync(value, obj[key]);
|
|
82
|
+
if (result.issues) for (const issue of result.issues) issues.push({
|
|
83
|
+
message: issue.message,
|
|
84
|
+
path: [key, ...issue.path ?? []]
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return issues.length ? { issues } : ok(v);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** An array whose every element satisfies the item schema. */
|
|
91
|
+
function array(item) {
|
|
92
|
+
return make("array", (v) => {
|
|
93
|
+
if (!Array.isArray(v)) return fail("Expected an array");
|
|
94
|
+
const issues = [];
|
|
95
|
+
for (let i = 0; i < v.length; i++) {
|
|
96
|
+
const result = runSync(item, v[i]);
|
|
97
|
+
if (result.issues) for (const issue of result.issues) issues.push({
|
|
98
|
+
message: issue.message,
|
|
99
|
+
path: [i, ...issue.path ?? []]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return issues.length ? { issues } : ok(v);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** An object whose known keys each satisfy their schema (extra keys are kept). */
|
|
106
|
+
function object(shape) {
|
|
107
|
+
const entries = Object.entries(shape);
|
|
108
|
+
return make("object", (v) => {
|
|
109
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) return fail("Expected an object");
|
|
110
|
+
const obj = v;
|
|
111
|
+
const issues = [];
|
|
112
|
+
for (const [key, schema] of entries) {
|
|
113
|
+
const result = runSync(schema, obj[key]);
|
|
114
|
+
if (result.issues) for (const issue of result.issues) issues.push({
|
|
115
|
+
message: issue.message,
|
|
116
|
+
path: [key, ...issue.path ?? []]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return issues.length ? { issues } : ok(v);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** Allow `undefined` in addition to the inner schema. */
|
|
123
|
+
function optional(inner) {
|
|
124
|
+
return make("optional", (v) => v === void 0 ? ok(void 0) : runSync(inner, v), { wrapped: inner });
|
|
125
|
+
}
|
|
126
|
+
/** Allow `null` in addition to the inner schema. */
|
|
127
|
+
function nullable(inner) {
|
|
128
|
+
return make("nullable", (v) => v === null ? ok(null) : runSync(inner, v), { wrapped: inner });
|
|
129
|
+
}
|
|
130
|
+
/** Attach a human-readable description (used for CLI option help). */
|
|
131
|
+
function describe(schema, description) {
|
|
132
|
+
return {
|
|
133
|
+
...schema,
|
|
134
|
+
description
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Grouped access to every builder: `s.string()`, `s.object({ ... })`,
|
|
139
|
+
* `s.void()`, etc. Handy for a valibot-like `import { s } from
|
|
140
|
+
* 'devframe/utils/simple-schema'` call site.
|
|
141
|
+
*/
|
|
142
|
+
const s = {
|
|
143
|
+
string,
|
|
144
|
+
number,
|
|
145
|
+
boolean,
|
|
146
|
+
void: voidType,
|
|
147
|
+
null: nullType,
|
|
148
|
+
literal,
|
|
149
|
+
picklist,
|
|
150
|
+
union,
|
|
151
|
+
record,
|
|
152
|
+
array,
|
|
153
|
+
object,
|
|
154
|
+
optional,
|
|
155
|
+
nullable,
|
|
156
|
+
describe
|
|
157
|
+
};
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/recipes/interactive-auth.ts
|
|
160
|
+
/**
|
|
161
|
+
* Build a {@link AuthBannerFunction} that renders the auth code + magic-link
|
|
162
|
+
* URL as a small bordered box, its two rows label-aligned. `createInteractiveAuth`
|
|
163
|
+
* falls back to `createAuthBanner()` when no `banner` is given; call this
|
|
164
|
+
* yourself to rebrand the box (`title` / `colors`) and pass the result as
|
|
165
|
+
* `options.banner`.
|
|
166
|
+
*/
|
|
167
|
+
function createAuthBanner(options = {}) {
|
|
168
|
+
const title = options.title ?? "Devframe";
|
|
169
|
+
const palette = {
|
|
170
|
+
border: colors.dim,
|
|
171
|
+
title: (x) => colors.gray(colors.bold(x)),
|
|
172
|
+
label: colors.dim,
|
|
173
|
+
code: (f) => colors.green(colors.bold(f)),
|
|
174
|
+
url: colors.cyan,
|
|
175
|
+
...options.colors
|
|
176
|
+
};
|
|
177
|
+
return (info) => {
|
|
178
|
+
const rows = [
|
|
179
|
+
[
|
|
180
|
+
"auth code",
|
|
181
|
+
info.code,
|
|
182
|
+
palette.code
|
|
183
|
+
],
|
|
184
|
+
[
|
|
185
|
+
"or open",
|
|
186
|
+
info.url,
|
|
187
|
+
palette.url
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
"expires at",
|
|
191
|
+
new Date(info.expireAt).toLocaleTimeString(),
|
|
192
|
+
palette.label
|
|
193
|
+
]
|
|
194
|
+
];
|
|
195
|
+
if (info.requester) {
|
|
196
|
+
rows.push([
|
|
197
|
+
"ua",
|
|
198
|
+
info.requester.ua,
|
|
199
|
+
palette.label
|
|
200
|
+
]);
|
|
201
|
+
rows.push([
|
|
202
|
+
"origin",
|
|
203
|
+
info.requester.origin,
|
|
204
|
+
palette.label
|
|
205
|
+
]);
|
|
206
|
+
}
|
|
207
|
+
const labelWidth = Math.max(...rows.map(([label]) => label.length));
|
|
208
|
+
const contentWidth = Math.max(...rows.map(([, value]) => labelWidth + 2 + value.length));
|
|
209
|
+
const titleBarLength = title.length + 2;
|
|
210
|
+
const lineWidth = Math.max(contentWidth, titleBarLength - 2);
|
|
211
|
+
const top = [
|
|
212
|
+
palette.border(`╭`),
|
|
213
|
+
palette.title(title),
|
|
214
|
+
palette.border(`${"─".repeat(Math.max(lineWidth + 2 - titleBarLength, 0))}╮`)
|
|
215
|
+
].join(" ");
|
|
216
|
+
const bottom = `╰${"─".repeat(lineWidth + 2)}╯`;
|
|
217
|
+
const body = rows.map(([label, value, color]) => {
|
|
218
|
+
const plain = `${label.padEnd(labelWidth)} ${value}`;
|
|
219
|
+
const pad = " ".repeat(lineWidth - plain.length);
|
|
220
|
+
return `${palette.border("│")} ${palette.label(label.padEnd(labelWidth))} ${color(value)}${pad} ${palette.border("│")}`;
|
|
221
|
+
});
|
|
222
|
+
console.log(`\n${palette.border(top)}\n${body.join("\n")}\n${palette.border(bottom)}\n`);
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Package the interactive OTP auth protocol devframe's primitives
|
|
227
|
+
* (`exchangeTempAuthCode`, `verifyAuthToken`, `revokeAuthToken`,
|
|
228
|
+
* `getTempAuthCode`, `buildOtpAuthUrl`) implement into a ready-made
|
|
229
|
+
* {@link DevframeAuthHandler}: the handshake RPC functions, the resolver
|
|
230
|
+
* gate, the connect-time trust hook, and the startup banner.
|
|
231
|
+
*
|
|
232
|
+
* The auth storage stays internal to this handler; callers never reach into
|
|
233
|
+
* `devframe/node/hub-internals` themselves.
|
|
234
|
+
*
|
|
235
|
+
* ```ts
|
|
236
|
+
* import { createInteractiveAuth } from 'devframe/recipes/interactive-auth'
|
|
237
|
+
*
|
|
238
|
+
* const auth = createInteractiveAuth(ctx)
|
|
239
|
+
* auth.rpcFunctions.forEach(fn => ctx.rpc.register(fn))
|
|
240
|
+
* auth.printBanner()
|
|
241
|
+
*
|
|
242
|
+
* // wire `auth.authorize` / `auth.onConnect` into your transport, or pass
|
|
243
|
+
* // the whole handler to `initDevframe` / `initHub` via their `auth` option.
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
function createInteractiveAuth(context, options = {}) {
|
|
247
|
+
const internal = getInternalContext(context);
|
|
248
|
+
const storage = internal.storage.auth;
|
|
249
|
+
const staticTokens = new Set(options.clientAuthTokens ?? []);
|
|
250
|
+
function isStaticToken(token) {
|
|
251
|
+
return !!token && staticTokens.has(token);
|
|
252
|
+
}
|
|
253
|
+
function resolveServerUrl() {
|
|
254
|
+
return options.serverUrl?.() ?? context.host.resolveOrigin();
|
|
255
|
+
}
|
|
256
|
+
const banner = options.banner ?? createAuthBanner();
|
|
257
|
+
let bannerPrintedForCode;
|
|
258
|
+
function printBanner(info) {
|
|
259
|
+
const { code, expireAt } = getTempAuthCodeInfo();
|
|
260
|
+
if (code === bannerPrintedForCode) return;
|
|
261
|
+
bannerPrintedForCode = code;
|
|
262
|
+
const url = buildOtpAuthUrl(resolveServerUrl(), code);
|
|
263
|
+
banner({
|
|
264
|
+
code,
|
|
265
|
+
url,
|
|
266
|
+
expireAt,
|
|
267
|
+
...info?.requester ? { requester: info.requester } : {}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
const anonymousAuth = defineRpcFunction({
|
|
271
|
+
name: "anonymous:devframe:auth",
|
|
272
|
+
type: "action",
|
|
273
|
+
jsonSerializable: true,
|
|
274
|
+
args: [s.object({
|
|
275
|
+
authToken: s.string(),
|
|
276
|
+
ua: s.string(),
|
|
277
|
+
origin: s.string()
|
|
278
|
+
})],
|
|
279
|
+
returns: s.object({ isTrusted: s.boolean() }),
|
|
280
|
+
handler(params) {
|
|
281
|
+
const session = context.rpc.getCurrentRpcSession();
|
|
282
|
+
if (!session) return { isTrusted: false };
|
|
283
|
+
if (session.meta.isTrusted) return { isTrusted: true };
|
|
284
|
+
if (isStaticToken(params.authToken)) {
|
|
285
|
+
session.meta.clientAuthToken = params.authToken;
|
|
286
|
+
session.meta.isTrusted = true;
|
|
287
|
+
return { isTrusted: true };
|
|
288
|
+
}
|
|
289
|
+
return { isTrusted: verifyAuthToken(params.authToken, session, storage) };
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const anonymousAuthExchange = defineRpcFunction({
|
|
293
|
+
name: "anonymous:devframe:auth:exchange",
|
|
294
|
+
type: "action",
|
|
295
|
+
jsonSerializable: true,
|
|
296
|
+
args: [s.object({
|
|
297
|
+
code: s.string(),
|
|
298
|
+
ua: s.string(),
|
|
299
|
+
origin: s.string()
|
|
300
|
+
})],
|
|
301
|
+
returns: s.object({ authToken: s.nullable(s.string()) }),
|
|
302
|
+
handler(params) {
|
|
303
|
+
const session = context.rpc.getCurrentRpcSession();
|
|
304
|
+
if (!session) return { authToken: null };
|
|
305
|
+
const authToken = exchangeTempAuthCode(params.code, session, params, storage);
|
|
306
|
+
if (authToken) options.onTrusted?.({
|
|
307
|
+
session,
|
|
308
|
+
authToken
|
|
309
|
+
});
|
|
310
|
+
return { authToken };
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
const anonymousAuthRequestCode = defineRpcFunction({
|
|
314
|
+
name: "anonymous:devframe:auth:request-code",
|
|
315
|
+
type: "action",
|
|
316
|
+
jsonSerializable: true,
|
|
317
|
+
args: [s.object({
|
|
318
|
+
ua: s.string(),
|
|
319
|
+
origin: s.string(),
|
|
320
|
+
reissue: s.optional(s.boolean())
|
|
321
|
+
})],
|
|
322
|
+
returns: s.void(),
|
|
323
|
+
handler(params) {
|
|
324
|
+
if (params.reissue) refreshTempAuthCode();
|
|
325
|
+
printBanner({ requester: {
|
|
326
|
+
ua: describeUA(params.ua),
|
|
327
|
+
origin: params.origin
|
|
328
|
+
} });
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
const revoke = defineRpcFunction({
|
|
332
|
+
name: "devframe:auth:revoke",
|
|
333
|
+
type: "action",
|
|
334
|
+
jsonSerializable: true,
|
|
335
|
+
args: [],
|
|
336
|
+
returns: s.void(),
|
|
337
|
+
async handler() {
|
|
338
|
+
const token = context.rpc.getCurrentRpcSession()?.meta.clientAuthToken;
|
|
339
|
+
if (token) await internal.revokeAuthToken(token);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
function authorize(methodName, session) {
|
|
343
|
+
if (isAnonymousRpcMethod(methodName)) return true;
|
|
344
|
+
return !!session.meta.isTrusted;
|
|
345
|
+
}
|
|
346
|
+
function onConnect(connection, session) {
|
|
347
|
+
let token;
|
|
348
|
+
let requestOrigin;
|
|
349
|
+
try {
|
|
350
|
+
token = new URL(connection.request?.url ?? "", "http://localhost").searchParams.get("devframe_auth_token") ?? void 0;
|
|
351
|
+
} catch {}
|
|
352
|
+
try {
|
|
353
|
+
requestOrigin = connection.request?.headers?.get?.("origin") ?? void 0;
|
|
354
|
+
} catch {}
|
|
355
|
+
if (!token) return;
|
|
356
|
+
if (isStaticToken(token)) {
|
|
357
|
+
session.meta.clientAuthToken = token;
|
|
358
|
+
session.meta.isTrusted = true;
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (verifyAuthToken(token, session, storage)) return;
|
|
362
|
+
if (internal.isRemoteTokenTrusted(token, requestOrigin)) {
|
|
363
|
+
session.meta.clientAuthToken = token;
|
|
364
|
+
session.meta.isTrusted = true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function buildOpenUrl(url) {
|
|
368
|
+
return buildOtpAuthUrl(url);
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
rpcFunctions: [
|
|
372
|
+
anonymousAuth,
|
|
373
|
+
anonymousAuthExchange,
|
|
374
|
+
anonymousAuthRequestCode,
|
|
375
|
+
revoke
|
|
376
|
+
],
|
|
377
|
+
authorize,
|
|
378
|
+
onConnect,
|
|
379
|
+
printBanner,
|
|
380
|
+
buildOpenUrl
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
//#endregion
|
|
384
|
+
export { createInteractiveAuth as n, createAuthBanner as t };
|
|
@@ -1,21 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
5
|
-
import { a as
|
|
6
|
-
import { n as
|
|
7
|
-
|
|
1
|
+
import { t as StandardSchemaV1 } from "../index-CeEtxDmK.mjs";
|
|
2
|
+
import { g as RpcFunctionDefinitionAny } from "../types-BmDbfHCx.mjs";
|
|
3
|
+
import { Bt as AgentTool, Et as DevframeHost, Ft as AgentHandle, Gt as DevframeAgentHostEvents, Ht as AgentToolProvider, It as AgentManifest, Kt as EventEmitter, Lt as AgentResource, Rt as AgentResourceContent, Ut as AgentToolProviderHandle, Vt as AgentToolInput, Wt as DevframeAgentHost$1, o as DevframeNodeContext, zt as AgentResourceInput } from "../context-CTAxz9ec.mjs";
|
|
4
|
+
import { a as RemoteAssetsStore } from "../remote-assets-eBvSKZMS.mjs";
|
|
5
|
+
import { a as InstanceShellInit, c as StartedServer, d as samePath, f as DevframeInstanceRecord, g as registerDevframeInstance, h as probeDevframeOrigin, i as InstanceShellApi, l as createInstanceShell, m as listLiveDevframeInstances, n as InstanceRegisterConfig, o as InstanceShellInternals, p as DevframeInstanceRegistration, r as InstanceShell, s as InstanceWsTier, t as CreateInstanceShellOptions, u as resolveInstanceRegister } from "../instance-shell-DOZSxst6.mjs";
|
|
6
|
+
import { i as importAgenticMcp, n as MountMcpHttpOptions, r as MountedMcpHttp, t as AgenticMcpModule } from "../agentic-D4QQQUjE.mjs";
|
|
7
|
+
import { a as resolveBasePath, i as normalizeBasePath, n as ResolvedMcpConfig, r as loadAutoMcpAdapter, s as resolveMcpConfig } from "../_shared-Dy1UBMUN.mjs";
|
|
8
|
+
import { n as CreateContextRpcServerOptions, r as createContextRpcServer, t as ContextRpcServer } from "../rpc-core-rLrwFEcw.mjs";
|
|
9
|
+
//#region src/agent/stringify.d.ts
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
* UI. Prefers the top-level {@link DevframeDefinition.clientAssets} and falls
|
|
11
|
-
* back to the deprecated `cli.distDir`, so both the new and legacy shapes
|
|
12
|
-
* resolve. Returns `undefined` when neither is set (bridge mode, where the SPA is
|
|
13
|
-
* hosted elsewhere).
|
|
11
|
+
* JSON-coercing serializer for MCP text payloads.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* MCP carries tool results and resource reads as plain text over a
|
|
14
|
+
* JSON-RPC transport, so we cannot use the `s:`-prefixed structured-clone
|
|
15
|
+
* format the WS RPC transport falls back to for non-JSON values. Instead,
|
|
16
|
+
* we coerce common non-JSON types into JSON-friendly forms so the LLM
|
|
17
|
+
* client sees something useful instead of `[object Object]`.
|
|
18
|
+
*
|
|
19
|
+
* Coercions:
|
|
20
|
+
* - `BigInt` → `"123n"`
|
|
21
|
+
* - `Date` → ISO string (via the native `toJSON`)
|
|
22
|
+
* - `Map` → `{ __type: 'Map', entries: [[k, v], …] }`
|
|
23
|
+
* - `Set` → `{ __type: 'Set', entries: [v, …] }`
|
|
24
|
+
* - `Error` → `{ name, message, stack, cause? }` (cause recurses)
|
|
25
|
+
* - `Function` → `"[Function: name]"`
|
|
26
|
+
* - `Symbol` → `value.toString()`
|
|
27
|
+
* - cycles → `"[Circular]"`
|
|
17
28
|
*/
|
|
18
|
-
export declare function
|
|
29
|
+
export declare function stringifyForMcp(value: unknown): string;
|
|
30
|
+
/**
|
|
31
|
+
* Format a thrown value for an MCP `isError` text payload.
|
|
32
|
+
*
|
|
33
|
+
* A nostics `Diagnostic` (every coded devframe error) becomes structured
|
|
34
|
+
* JSON (`{ error: { code, message, fix?, docs? } }`), so an agent receives
|
|
35
|
+
* the actionable next step (`fix`) and the docs URL instead of a bare
|
|
36
|
+
* message string. Other errors surface `Error.name`/`message`, plus one
|
|
37
|
+
* level of `cause.message` so context isn't dropped silently.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatMcpError(error: unknown): string;
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/agent/to-json-schema.d.ts
|
|
42
|
+
/**
|
|
43
|
+
* JSON Schema for an RPC return value on the agent/MCP surface.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
export declare function returnToJsonSchema(schema: StandardSchemaV1 | undefined): unknown;
|
|
47
|
+
/**
|
|
48
|
+
* JSON Schema for an RPC function's positional args on the agent/MCP
|
|
49
|
+
* surface. Each positional arg is advertised under `arg0` / `arg1` / …,
|
|
50
|
+
* matching how the agent bridge coerces the incoming object payload back
|
|
51
|
+
* into positional arguments.
|
|
52
|
+
*
|
|
53
|
+
* Returns `{ type: 'object', properties: {} }` when there are no args.
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export declare function argsToJsonSchema(args: readonly StandardSchemaV1[] | undefined): unknown;
|
|
19
57
|
//#endregion
|
|
20
58
|
//#region src/node/diagnostics.d.ts
|
|
21
59
|
/**
|
|
@@ -147,7 +185,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
|
|
|
147
185
|
readonly why: (p: {
|
|
148
186
|
reason: string;
|
|
149
187
|
}) => string;
|
|
150
|
-
readonly fix: "Install it next to devframe (e.g. `npm install @
|
|
188
|
+
readonly fix: "Install it next to devframe (e.g. `npm install @devframes/agentic`) and run `devframe connect` again.";
|
|
151
189
|
};
|
|
152
190
|
readonly DF0047: {
|
|
153
191
|
readonly why: (p: {
|
|
@@ -177,7 +215,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
|
|
|
177
215
|
readonly why: (p: {
|
|
178
216
|
port: number;
|
|
179
217
|
}) => string;
|
|
180
|
-
readonly fix: "Restart the instance with the --mcp flag
|
|
218
|
+
readonly fix: "Restart the instance with the --mcp flag to expose its tools, then list instances again.";
|
|
181
219
|
};
|
|
182
220
|
readonly DF0052: {
|
|
183
221
|
readonly why: (p: {
|
|
@@ -324,6 +362,16 @@ export declare const diagnostics: import("nostics").Diagnostics<{
|
|
|
324
362
|
}) => string;
|
|
325
363
|
readonly fix: "On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` with `attachBunWsTransport` / `attachDenoWsTransport` (see the hub-deno example), or connect over the SSE endpoint instead.";
|
|
326
364
|
};
|
|
365
|
+
readonly DF0078: {
|
|
366
|
+
readonly why: "This devframe exposes agent tools, but the MCP endpoint stays off: the optional peer \"@devframes/agentic\" is not installed.";
|
|
367
|
+
readonly fix: "Install `@devframes/agentic` next to devframe to serve the MCP endpoint, or set `mcp: false` to opt out silently.";
|
|
368
|
+
};
|
|
369
|
+
readonly DF0079: {
|
|
370
|
+
readonly why: (p: {
|
|
371
|
+
reason: string;
|
|
372
|
+
}) => string;
|
|
373
|
+
readonly fix: "Install `@devframes/agentic` next to devframe (the MCP adapter and the MCP SDK live there), or remove the explicit `mcp` setting.";
|
|
374
|
+
};
|
|
327
375
|
}, readonly [(d: import("nostics").Diagnostic, { method }?: {
|
|
328
376
|
method?: "log" | "warn" | "error";
|
|
329
377
|
}) => void]>;
|
|
@@ -453,9 +501,5 @@ export declare function peekRpcWireFrame(raw: string): {
|
|
|
453
501
|
//#region src/tool-input.d.ts
|
|
454
502
|
/** Convert tool input for a command, whose arguments must be declared. */
|
|
455
503
|
export declare function toolInputToCommandArgs(input: unknown, argumentCount?: number): unknown[];
|
|
456
|
-
/** @deprecated Use {@link toolInputToRpcArgs} or {@link toolInputToCommandArgs}. */
|
|
457
|
-
type AgentArgsFallback = 'wrap' | 'drop';
|
|
458
|
-
/** @deprecated Use {@link toolInputToRpcArgs} or {@link toolInputToCommandArgs}. */
|
|
459
|
-
export declare function coerceAgentPositionalArgs(input: unknown, schemas: readonly unknown[] | undefined, fallback?: AgentArgsFallback): unknown[];
|
|
460
504
|
//#endregion
|
|
461
|
-
export { type
|
|
505
|
+
export { type AgenticMcpModule, type ContextRpcServer, type CreateContextRpcServerOptions, type CreateInstanceShellOptions, type DevframeInstanceRecord, type DevframeInstanceRegistration, type InstanceRegisterConfig, type InstanceShell, type InstanceShellApi, type InstanceShellInit, type InstanceShellInternals, type InstanceWsTier, type MountMcpHttpOptions, type MountedMcpHttp, type ResolvedMcpConfig, type RpcWireCodec, type StartedServer, createContextRpcServer, createInstanceShell, importAgenticMcp, listLiveDevframeInstances, loadAutoMcpAdapter, normalizeBasePath, probeDevframeOrigin, registerDevframeInstance, resolveBasePath, resolveInstanceRegister, resolveMcpConfig, samePath };
|
package/dist/internal/index.mjs
CHANGED
|
@@ -1,10 +1,145 @@
|
|
|
1
|
-
import { t as
|
|
1
|
+
import { t as Diagnostic } from "../nostics-D0PvLZsn.mjs";
|
|
2
2
|
import { n as peekRpcWireFrame, t as createRpcWireCodec } from "../wire-codec-B1W3zH3L.mjs";
|
|
3
|
-
import { t as diagnostics } from "../diagnostics-
|
|
4
|
-
import { n as
|
|
5
|
-
import { a as resolveMcpConfig, n as normalizeBasePath, r as resolveBasePath, s as
|
|
3
|
+
import { t as diagnostics } from "../diagnostics-Cx4_VjlG.mjs";
|
|
4
|
+
import { n as toolInputToCommandArgs, t as DevframeAgentHost } from "../host-agent-ZSKgzMVu.mjs";
|
|
5
|
+
import { a as resolveMcpConfig, n as normalizeBasePath, r as resolveBasePath, s as importAgenticMcp, t as loadAutoMcpAdapter } from "../_shared-B2PZsp-J.mjs";
|
|
6
|
+
import { t as importRuntimeModule } from "../import-runtime-module-BzlEQ9PI.mjs";
|
|
6
7
|
import { t as createH3DevframeHost } from "../host-h3-BROI6SQ4.mjs";
|
|
7
|
-
import { i as registerDevframeInstance, n as listLiveDevframeInstances } from "../instance-registry-
|
|
8
|
-
import { i as normalizeHttpServerUrl, n as resolveInstanceRegister, r as samePath, t as createInstanceShell } from "../instance-shell-
|
|
9
|
-
import { t as createContextRpcServer } from "../rpc-core-
|
|
10
|
-
|
|
8
|
+
import { i as registerDevframeInstance, n as listLiveDevframeInstances, r as probeDevframeOrigin } from "../instance-registry-DtvYxc0Y.mjs";
|
|
9
|
+
import { i as normalizeHttpServerUrl, n as resolveInstanceRegister, r as samePath, t as createInstanceShell } from "../instance-shell-wC2sfEU_.mjs";
|
|
10
|
+
import { t as createContextRpcServer } from "../rpc-core-BXyMjbKG.mjs";
|
|
11
|
+
//#region src/agent/stringify.ts
|
|
12
|
+
/**
|
|
13
|
+
* JSON-coercing serializer for MCP text payloads.
|
|
14
|
+
*
|
|
15
|
+
* MCP carries tool results and resource reads as plain text over a
|
|
16
|
+
* JSON-RPC transport, so we cannot use the `s:`-prefixed structured-clone
|
|
17
|
+
* format the WS RPC transport falls back to for non-JSON values. Instead,
|
|
18
|
+
* we coerce common non-JSON types into JSON-friendly forms so the LLM
|
|
19
|
+
* client sees something useful instead of `[object Object]`.
|
|
20
|
+
*
|
|
21
|
+
* Coercions:
|
|
22
|
+
* - `BigInt` → `"123n"`
|
|
23
|
+
* - `Date` → ISO string (via the native `toJSON`)
|
|
24
|
+
* - `Map` → `{ __type: 'Map', entries: [[k, v], …] }`
|
|
25
|
+
* - `Set` → `{ __type: 'Set', entries: [v, …] }`
|
|
26
|
+
* - `Error` → `{ name, message, stack, cause? }` (cause recurses)
|
|
27
|
+
* - `Function` → `"[Function: name]"`
|
|
28
|
+
* - `Symbol` → `value.toString()`
|
|
29
|
+
* - cycles → `"[Circular]"`
|
|
30
|
+
*/
|
|
31
|
+
function stringifyForMcp(value) {
|
|
32
|
+
if (value === void 0) return "undefined";
|
|
33
|
+
if (typeof value === "string") return value;
|
|
34
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
35
|
+
return JSON.stringify(value, (_key, val) => {
|
|
36
|
+
if (typeof val === "bigint") return `${val}n`;
|
|
37
|
+
if (val instanceof Error) {
|
|
38
|
+
const out = {
|
|
39
|
+
name: val.name,
|
|
40
|
+
message: val.message,
|
|
41
|
+
stack: val.stack
|
|
42
|
+
};
|
|
43
|
+
if (val.cause !== void 0) out.cause = val.cause;
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
if (val instanceof Map) return {
|
|
47
|
+
__type: "Map",
|
|
48
|
+
entries: [...val.entries()]
|
|
49
|
+
};
|
|
50
|
+
if (val instanceof Set) return {
|
|
51
|
+
__type: "Set",
|
|
52
|
+
entries: [...val]
|
|
53
|
+
};
|
|
54
|
+
if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
|
|
55
|
+
if (typeof val === "symbol") return val.toString();
|
|
56
|
+
if (val !== null && typeof val === "object") {
|
|
57
|
+
if (seen.has(val)) return "[Circular]";
|
|
58
|
+
seen.add(val);
|
|
59
|
+
}
|
|
60
|
+
return val;
|
|
61
|
+
}, 2);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Format a thrown value for an MCP `isError` text payload.
|
|
65
|
+
*
|
|
66
|
+
* A nostics `Diagnostic` (every coded devframe error) becomes structured
|
|
67
|
+
* JSON (`{ error: { code, message, fix?, docs? } }`), so an agent receives
|
|
68
|
+
* the actionable next step (`fix`) and the docs URL instead of a bare
|
|
69
|
+
* message string. Other errors surface `Error.name`/`message`, plus one
|
|
70
|
+
* level of `cause.message` so context isn't dropped silently.
|
|
71
|
+
*/
|
|
72
|
+
function formatMcpError(error) {
|
|
73
|
+
if (error instanceof Diagnostic) return JSON.stringify({ error: {
|
|
74
|
+
code: error.code,
|
|
75
|
+
message: error.message,
|
|
76
|
+
...error.fix ? { fix: error.fix } : {},
|
|
77
|
+
...error.docs ? { docs: error.docs } : {}
|
|
78
|
+
} }, null, 2);
|
|
79
|
+
if (!(error instanceof Error)) return String(error);
|
|
80
|
+
const cause = error.cause;
|
|
81
|
+
const causeText = cause instanceof Error ? ` (cause: ${cause.message})` : cause !== void 0 ? ` (cause: ${String(cause)})` : "";
|
|
82
|
+
return `${error.name}: ${error.message}${causeText}`;
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/agent/to-json-schema.ts
|
|
86
|
+
const FALLBACK_OBJECT_SCHEMA = Object.freeze({
|
|
87
|
+
type: "object",
|
|
88
|
+
additionalProperties: true
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Convert a Standard Schema to JSON Schema for the agent/MCP surface.
|
|
92
|
+
*
|
|
93
|
+
* Devframe stays validator-neutral, so conversion uses the schema's own
|
|
94
|
+
* [Standard JSON Schema](https://standardschema.dev/) converter
|
|
95
|
+
* (`~standard.jsonSchema`) when the validator provides one; zod 4 does,
|
|
96
|
+
* for example. Validators without a native converter (e.g. valibot) degrade
|
|
97
|
+
* to a permissive object schema rather than pulling in a converter library.
|
|
98
|
+
*/
|
|
99
|
+
function safeToJsonSchema(schema) {
|
|
100
|
+
const standard = schema["~standard"];
|
|
101
|
+
if (standard.jsonSchema) try {
|
|
102
|
+
return standard.jsonSchema.input({ target: "draft-2020-12" });
|
|
103
|
+
} catch {
|
|
104
|
+
return FALLBACK_OBJECT_SCHEMA;
|
|
105
|
+
}
|
|
106
|
+
return FALLBACK_OBJECT_SCHEMA;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* JSON Schema for an RPC return value on the agent/MCP surface.
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
function returnToJsonSchema(schema) {
|
|
113
|
+
if (!schema) return void 0;
|
|
114
|
+
return safeToJsonSchema(schema);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* JSON Schema for an RPC function's positional args on the agent/MCP
|
|
118
|
+
* surface. Each positional arg is advertised under `arg0` / `arg1` / …,
|
|
119
|
+
* matching how the agent bridge coerces the incoming object payload back
|
|
120
|
+
* into positional arguments.
|
|
121
|
+
*
|
|
122
|
+
* Returns `{ type: 'object', properties: {} }` when there are no args.
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
function argsToJsonSchema(args) {
|
|
126
|
+
if (!args || args.length === 0) return {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {}
|
|
129
|
+
};
|
|
130
|
+
const properties = {};
|
|
131
|
+
const required = [];
|
|
132
|
+
for (let i = 0; i < args.length; i++) {
|
|
133
|
+
const key = `arg${i}`;
|
|
134
|
+
properties[key] = safeToJsonSchema(args[i]);
|
|
135
|
+
required.push(key);
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
type: "object",
|
|
139
|
+
properties,
|
|
140
|
+
required,
|
|
141
|
+
additionalProperties: false
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { DevframeAgentHost, argsToJsonSchema, createContextRpcServer, createH3DevframeHost, createInstanceShell, createRpcWireCodec, diagnostics, formatMcpError, importAgenticMcp, importRuntimeModule, listLiveDevframeInstances, loadAutoMcpAdapter, normalizeBasePath, normalizeHttpServerUrl, peekRpcWireFrame, probeDevframeOrigin, registerDevframeInstance, resolveBasePath, resolveInstanceRegister, resolveMcpConfig, returnToJsonSchema, samePath, stringifyForMcp, toolInputToCommandArgs };
|