devframe 0.9.8 → 0.9.10
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-CCzf9Hub.d.mts +83 -0
- package/dist/_shared-U8D-xzrp.mjs +115 -0
- package/dist/adapters/build.d.mts +6 -6
- package/dist/adapters/build.mjs +33 -36
- package/dist/adapters/cac.d.mts +12 -1
- package/dist/adapters/cac.mjs +8 -8
- package/dist/adapters/dev.d.mts +17 -17
- package/dist/adapters/dev.mjs +2 -2
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/initiate.d.mts +31 -28
- package/dist/adapters/initiate.mjs +1 -1
- package/dist/adapters/mcp.d.mts +28 -14
- package/dist/adapters/mcp.mjs +76 -40
- package/dist/{agent-tool-name-EgfoFO8C.mjs → agent-tool-name-DGzeuWcO.mjs} +2 -2
- package/dist/cli/main.d.mts +1 -1
- package/dist/cli/main.mjs +41 -17
- package/dist/client/index.d.mts +36 -36
- package/dist/client/index.mjs +90 -52
- package/dist/{client-assets-C7SXgTWY.mjs → client-assets-DNdhagGm.mjs} +2 -2
- package/dist/constants.d.mts +8 -7
- package/dist/constants.mjs +7 -6
- package/dist/{context-omlma_1n.mjs → context-B29Oh0oA.mjs} +166 -93
- package/dist/{context-DftYyXaR.d.mts → context-BJiKJqyW.d.mts} +5 -5
- package/dist/{context-CLF4-8Pp.d.mts → context-CHW4BZOj.d.mts} +203 -134
- package/dist/{context-KUqAfawQ.mjs → context-jXO5vzjH.mjs} +3 -3
- package/dist/{crypto-token-XCqTSMg9.mjs → crypto-token-TVbGGFuj.mjs} +1 -1
- package/dist/{dev-CzkPCJwi.mjs → dev-CRYHx7iG.mjs} +73 -40
- package/dist/{diagnostics-BXWW3VK-.mjs → diagnostics-DZA6KQ_Z.mjs} +32 -19
- package/dist/{events-4daw0uK9.mjs → events-BV4Dj59a.mjs} +2 -2
- package/dist/{services-install-CqqQVls5.mjs → host-agent-CKqSTEX9.mjs} +15 -151
- package/dist/{host-h3-fRbF9yor.mjs → host-h3-BROI6SQ4.mjs} +2 -2
- package/dist/in-page-channel/index.d.mts +14 -14
- package/dist/in-page-channel/index.mjs +63 -54
- package/dist/{index-D3k0BIhe.d.mts → index-CNC390b_.d.mts} +4 -4
- package/dist/{index-BzyopqxV.d.mts → index-pIVt92jP.d.mts} +9 -9
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +2 -2
- package/dist/{instance-registry-BjlMQbFB.mjs → instance-registry-DCq762YJ.mjs} +9 -9
- package/dist/{instance-shell-Tcp5hGoq.d.mts → instance-shell-DZipaP9k.d.mts} +18 -18
- package/dist/{instance-shell-CpVW4zG0.mjs → instance-shell-DvYCwrDy.mjs} +223 -67
- package/dist/internal/index.d.mts +45 -26
- package/dist/internal/index.mjs +10 -10
- package/dist/node/auth.d.mts +2 -2
- package/dist/node/auth.mjs +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 +5 -5
- package/dist/node/index.mjs +2 -2
- package/dist/{nostics-SPGDgHEP.d.mts → nostics-0sKe5HIj.d.mts} +2 -2
- package/dist/{nostics-CzECRXpE.mjs → nostics-D0PvLZsn.mjs} +1 -1
- package/dist/origin-DGDH8BI9.d.mts +45 -0
- package/dist/origin-DZit9g29.mjs +80 -0
- package/dist/recipes/common-rpc-functions.d.mts +5 -5
- package/dist/recipes/common-rpc-functions.mjs +3 -3
- package/dist/recipes/interactive-auth.d.mts +6 -6
- package/dist/recipes/interactive-auth.mjs +6 -6
- package/dist/{remote-assets-DezQmPQU.mjs → remote-assets-DMFzLSoH.mjs} +27 -7
- package/dist/{remote-assets-B13_vRkJ.d.mts → remote-assets-eBvSKZMS.d.mts} +7 -7
- package/dist/{revoke-COLW0cOi.mjs → revoke-cqztiCX4.mjs} +1 -1
- package/dist/rpc/dump.d.mts +19 -12
- package/dist/rpc/dump.mjs +2 -2
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +2 -3
- package/dist/rpc/transports/sse-client.d.mts +1 -1
- package/dist/rpc/transports/sse-client.mjs +30 -14
- package/dist/rpc/transports/sse-server.d.mts +4 -4
- package/dist/rpc/transports/sse-server.mjs +7 -7
- package/dist/rpc/transports/ws-bun.d.mts +5 -5
- package/dist/rpc/transports/ws-bun.mjs +8 -2
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-client.mjs +2 -2
- package/dist/rpc/transports/ws-deno.d.mts +4 -4
- package/dist/rpc/transports/ws-deno.mjs +8 -2
- package/dist/rpc/transports/ws-server.d.mts +2 -1
- package/dist/rpc/transports/ws-server.mjs +232 -1
- package/dist/{rpc-core-DlHd276T.mjs → rpc-core-CvkU23bQ.mjs} +14 -2
- package/dist/{rpc-core-B3W3z9ff.d.mts → rpc-core-DsyDViQy.d.mts} +4 -4
- package/dist/serialization-DFg5sUt6.mjs +116 -0
- package/dist/services-install-Ben4yh52.mjs +154 -0
- package/dist/session-DPfj6zQG.mjs +16 -0
- package/dist/{shared-state--sduc6Xi.mjs → shared-state-CaxB1q0h.mjs} +2 -2
- package/dist/{simple-schema-DQPZrAaZ.mjs → simple-schema-Bi40l-P6.mjs} +2 -2
- package/dist/{sse-client-DwX021ST.d.mts → sse-client-BQ4jS3eO.d.mts} +4 -4
- package/dist/{state-CK9LjrnT.mjs → state-Mwt6--el.mjs} +17 -9
- package/dist/{storage-BXNVhKyR.mjs → storage-B70AXK64.mjs} +2 -2
- package/dist/types/index.d.mts +6 -6
- package/dist/{types-CMdPYhOx.d.mts → types-Dq4i156u.d.mts} +17 -17
- package/dist/utils/agent-tool-name.d.mts +2 -2
- package/dist/utils/agent-tool-name.mjs +2 -2
- package/dist/utils/colors.d.mts +1 -1
- package/dist/utils/crypto-token.d.mts +1 -1
- package/dist/utils/crypto-token.mjs +1 -1
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/nostics.d.mts +1 -1
- package/dist/utils/nostics.mjs +1 -1
- package/dist/utils/open.mjs +1 -1
- package/dist/utils/origin.d.mts +2 -0
- package/dist/utils/origin.mjs +80 -0
- package/dist/utils/remote-assets.d.mts +2 -2
- package/dist/utils/remote-assets.mjs +1 -1
- package/dist/utils/serve-static.d.mts +4 -4
- package/dist/utils/serve-static.mjs +56 -19
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -1
- package/dist/utils/simple-schema.d.mts +5 -5
- package/dist/utils/simple-schema.mjs +2 -2
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/streaming-channel.mjs +2 -2
- package/dist/utils/when.d.mts +5 -5
- package/dist/{validation-YrZH6atx.mjs → validation-CfV1s0SF.mjs} +2 -2
- package/dist/{wire-codec-0K-o5MYW.mjs → wire-codec-BHGt0sSs.mjs} +3 -3
- package/dist/{static-DV_qUSRS.mjs → write-BuLCrn9h.mjs} +153 -137
- package/dist/{ws-client-7_lZi-B9.d.mts → ws-client-Xpxt0oPA.d.mts} +3 -3
- package/dist/{ws-server-VyHlanzy.d.mts → ws-server-D2nv68Hg.d.mts} +13 -37
- package/package.json +3 -6
- package/skills/devframe/SKILL.md +5 -3
- package/dist/_shared-BM3PdYli.mjs +0 -68
- package/dist/_shared-mtXpcJIv.d.mts +0 -41
- package/dist/diagnostics-CD8nlgll.mjs +0 -39
- package/dist/serialization-BGzEwAdr.mjs +0 -77
- package/dist/ws-server-Y_AumUQH.mjs +0 -294
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEVFRAME_OTP_URL_PARAM } from "./constants.mjs";
|
|
2
|
-
import { n as randomToken, r as timingSafeEqual, t as randomDigits } from "./crypto-token-
|
|
2
|
+
import { n as randomToken, r as timingSafeEqual, t as randomDigits } from "./crypto-token-TVbGGFuj.mjs";
|
|
3
3
|
//#region ../../node_modules/.pnpm/ua-parser-modern@0.1.1/node_modules/ua-parser-modern/dist/index.mjs
|
|
4
4
|
const EMPTY = "";
|
|
5
5
|
const UNKNOWN = "?";
|
|
@@ -1169,7 +1169,7 @@ function parseUA(uastringOrExtensions, extensions) {
|
|
|
1169
1169
|
*
|
|
1170
1170
|
* The client used to parse+format this itself, but that pulled
|
|
1171
1171
|
* `ua-parser-modern` into the browser bundle for a label nothing else on
|
|
1172
|
-
* the client needs
|
|
1172
|
+
* the client needs; the client now sends the raw string and parsing
|
|
1173
1173
|
* happens here, at the server ingress, keeping the persisted label format
|
|
1174
1174
|
* identical.
|
|
1175
1175
|
*/
|
|
@@ -1194,18 +1194,25 @@ const TEMP_AUTH_CODE_LENGTH = 6;
|
|
|
1194
1194
|
const TEMP_AUTH_CODE_TTL = 3e5;
|
|
1195
1195
|
/** Failed attempts allowed against a single code before it is rotated. */
|
|
1196
1196
|
const TEMP_AUTH_MAX_ATTEMPTS = 5;
|
|
1197
|
-
let tempAuthCode
|
|
1198
|
-
let tempAuthCodeExpiresAt =
|
|
1197
|
+
let tempAuthCode;
|
|
1198
|
+
let tempAuthCodeExpiresAt = 0;
|
|
1199
1199
|
let tempAuthFailedAttempts = 0;
|
|
1200
1200
|
function generateTempCode() {
|
|
1201
1201
|
return randomDigits(TEMP_AUTH_CODE_LENGTH);
|
|
1202
1202
|
}
|
|
1203
|
+
function ensureTempAuthCode() {
|
|
1204
|
+
if (tempAuthCode === void 0) {
|
|
1205
|
+
tempAuthCode = generateTempCode();
|
|
1206
|
+
tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
|
|
1207
|
+
}
|
|
1208
|
+
return tempAuthCode;
|
|
1209
|
+
}
|
|
1203
1210
|
/**
|
|
1204
1211
|
* The current one-time authentication code. Display this to the user (e.g. in
|
|
1205
1212
|
* the dev-server terminal) so they can type it into the browser to authenticate.
|
|
1206
1213
|
*/
|
|
1207
1214
|
function getTempAuthCode() {
|
|
1208
|
-
return
|
|
1215
|
+
return ensureTempAuthCode();
|
|
1209
1216
|
}
|
|
1210
1217
|
/**
|
|
1211
1218
|
* Rotate the authentication code, resetting its expiry window and failed-attempt
|
|
@@ -1221,16 +1228,16 @@ function refreshTempAuthCode() {
|
|
|
1221
1228
|
}
|
|
1222
1229
|
/**
|
|
1223
1230
|
* Build a "magic link" authentication URL that embeds a one-time code (OTP) in
|
|
1224
|
-
* the URL **fragment**. Opening it authenticates the client without typing
|
|
1231
|
+
* the URL **fragment**. Opening it authenticates the client without typing;
|
|
1225
1232
|
* print it on startup (devframe stays headless, so the host prints its own
|
|
1226
1233
|
* banner). Defaults to the current code; the link is subject to the same TTL.
|
|
1227
1234
|
*
|
|
1228
1235
|
* The code rides the fragment (`#devframe_otp=…`), not the query string, so it
|
|
1229
1236
|
* is never sent to the server, written to an access log, or leaked in a
|
|
1230
|
-
* `Referer` header
|
|
1237
|
+
* `Referer` header; the browser client reads it locally (see
|
|
1231
1238
|
* `consumeOtpFromUrl`). Any existing fragment parameters are preserved.
|
|
1232
1239
|
*/
|
|
1233
|
-
function buildOtpAuthUrl(baseUrl, code =
|
|
1240
|
+
function buildOtpAuthUrl(baseUrl, code = getTempAuthCode()) {
|
|
1234
1241
|
const url = new URL(baseUrl);
|
|
1235
1242
|
const fragment = new URLSearchParams(url.hash.replace(/^#/, ""));
|
|
1236
1243
|
fragment.set(DEVFRAME_OTP_URL_PARAM, code);
|
|
@@ -1264,11 +1271,12 @@ function verifyAuthToken(token, session, storage) {
|
|
|
1264
1271
|
* attacker cannot keep guessing against the same code.
|
|
1265
1272
|
*/
|
|
1266
1273
|
function exchangeTempAuthCode(code, session, info, storage) {
|
|
1274
|
+
const currentTempAuthCode = ensureTempAuthCode();
|
|
1267
1275
|
if (Date.now() > tempAuthCodeExpiresAt) {
|
|
1268
1276
|
refreshTempAuthCode();
|
|
1269
1277
|
return null;
|
|
1270
1278
|
}
|
|
1271
|
-
if (!timingSafeEqual(code,
|
|
1279
|
+
if (!timingSafeEqual(code, currentTempAuthCode)) {
|
|
1272
1280
|
tempAuthFailedAttempts += 1;
|
|
1273
1281
|
if (tempAuthFailedAttempts >= TEMP_AUTH_MAX_ATTEMPTS) refreshTempAuthCode();
|
|
1274
1282
|
return null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as diagnostics } from "./diagnostics-
|
|
1
|
+
import { t as diagnostics } from "./diagnostics-DZA6KQ_Z.mjs";
|
|
2
|
+
import { dirname } from "pathe";
|
|
2
3
|
import { createSharedState } from "devframe/utils/shared-state";
|
|
3
4
|
import process from "node:process";
|
|
4
|
-
import { dirname } from "pathe";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
//#region ../../node_modules/.pnpm/perfect-debounce@2.1.0/node_modules/perfect-debounce/dist/index.mjs
|
|
7
7
|
const DEBOUNCE_DEFAULTS = { trailing: true };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { g as RpcFunctionAgentOptions } from "../types-
|
|
2
|
-
import {
|
|
3
|
-
import { $ as
|
|
4
|
-
import { a as RemoteAssetsStore, i as RemoteAssetsProviderCustom, n as RemoteAssetsErrorMessage, o as StaticAssetsSource, r as RemoteAssetsProvider, t as RemoteAssets } from "../remote-assets-
|
|
5
|
-
import { i as DevframeDefineDiagnosticsOptions } from "../nostics-
|
|
6
|
-
export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, AgentToolProvider, AgentToolProviderHandle, ConnectionMeta, ConnectionMetaSse, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeCapabilities, DevframeCliOptions, DevframeConnectionConfigsRegistry, type DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDockDefaults, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, type DevframeRpcConnection, type DevframeRpcConnectionRequest, DevframeRpcOptions, DevframeRpcServerFunctions, DevframeRpcSharedStates, type DevframeRpcTransportKind, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeServiceDefinition, DevframeServiceDescriptor, DevframeServiceId, DevframeServiceInput, DevframeServiceMeta, DevframeServiceOf, DevframeServiceScopeOf, DevframeServicesHost, DevframeServicesRegistry, DevframeServicesScopeRegistry, DevframeServicesState, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSnapshotRpcEntry, DevframeSnapshotRpcInputs, DevframeSseOptions, DevframeStorageScope, DevframeViewHost, DevframeWsOptions, EventEmitter, EventUnsubscribe, EventsMap, McpRouteOptions, RemoteAssets, RemoteAssetsErrorMessage, RemoteAssetsProvider, RemoteAssetsProviderCustom, RemoteAssetsStore, RpcBroadcastOptions, type RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedRpcFn, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, StaticAssetsSource };
|
|
1
|
+
import { g as RpcFunctionAgentOptions } from "../types-Dq4i156u.mjs";
|
|
2
|
+
import { c as DevframeNodeRpcSessionMeta, d as DevframeRpcTransportKind, l as DevframeRpcConnection, u as DevframeRpcConnectionRequest } from "../ws-server-D2nv68Hg.mjs";
|
|
3
|
+
import { $ as DevframeServiceOf, At as AgentHandle, B as DevframeSetupInfo, Bt as DevframeAgentHostEvents, Ct as DevframeDiagnosticsHost, F as DevframeDefinition, Ft as AgentTool, G as McpAuthorization, H as DevframeSnapshotRpcInputs, Ht as EventUnsubscribe, I as DevframeDeploymentKind, It as AgentToolInput, J as DevframeServiceDefinition, K as McpRouteOptions, L as DevframeDockDefaults, Lt as AgentToolProvider, Mt as AgentResource, Nt as AgentResourceContent, P as DevframeCliOptions, Pt as AgentResourceInput, Q as DevframeServiceMeta, R as DevframeDuplicationStrategy, Rt as AgentToolProviderHandle, St as DevframeStorageScope, U as DevframeSseOptions, Ut as EventsMap, V as DevframeSnapshotRpcEntry, Vt as EventEmitter, W as DevframeWsOptions, X as DevframeServiceId, Y as DevframeServiceDescriptor, Z as DevframeServiceInput, _t as DevframeViewHost, a as DevframeConnectionConfigsRegistry, at as DevframeScopedNodeContext, bt as DevframeRpcSharedStates, c as RpcBroadcastOptions, ct as DevframeSettings, d as RpcSharedStateHost, dt as ScopedBroadcastOptions, et as DevframeServiceScopeOf, f as RpcStreamingChannel, ft as ScopedClientFunctions, gt as SettingsForNamespace, ht as ScopedSharedStates, i as DevframeCapabilities, it as DevframeServicesState, jt as AgentManifest, l as RpcFunctionsHost, lt as DevframeSettingsRegistry, m as RpcStreamingHost, mt as ScopedServerFunctions, n as ConnectionMetaSse, nt as DevframeServicesRegistry, o as DevframeNodeContext, ot as DevframeScopedNodeRpc, p as RpcStreamingChannelOptions, pt as ScopedRpcFn, q as McpSetting, r as ConnectionMetaWebsocket, rt as DevframeServicesScopeRegistry, s as DevframeNodeRpcSession, st as DevframeScopedStreamingHost, t as ConnectionMeta, tt as DevframeServicesHost, u as RpcSharedStateGetOptions, ut as DevframeSettingsStore, vt as DevframeRpcClientFunctions, wt as DevframeDiagnosticsLogger, xt as DevframeHost, yt as DevframeRpcServerFunctions, z as DevframeRpcOptions, zt as DevframeAgentHost } from "../context-CHW4BZOj.mjs";
|
|
4
|
+
import { a as RemoteAssetsStore, i as RemoteAssetsProviderCustom, n as RemoteAssetsErrorMessage, o as StaticAssetsSource, r as RemoteAssetsProvider, t as RemoteAssets } from "../remote-assets-eBvSKZMS.mjs";
|
|
5
|
+
import { i as DevframeDefineDiagnosticsOptions } from "../nostics-0sKe5HIj.mjs";
|
|
6
|
+
export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, AgentToolProvider, AgentToolProviderHandle, ConnectionMeta, ConnectionMetaSse, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeCapabilities, DevframeCliOptions, DevframeConnectionConfigsRegistry, type DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDockDefaults, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, type DevframeRpcConnection, type DevframeRpcConnectionRequest, DevframeRpcOptions, DevframeRpcServerFunctions, DevframeRpcSharedStates, type DevframeRpcTransportKind, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeServiceDefinition, DevframeServiceDescriptor, DevframeServiceId, DevframeServiceInput, DevframeServiceMeta, DevframeServiceOf, DevframeServiceScopeOf, DevframeServicesHost, DevframeServicesRegistry, DevframeServicesScopeRegistry, DevframeServicesState, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSnapshotRpcEntry, DevframeSnapshotRpcInputs, DevframeSseOptions, DevframeStorageScope, DevframeViewHost, DevframeWsOptions, EventEmitter, EventUnsubscribe, EventsMap, McpAuthorization, McpRouteOptions, McpSetting, RemoteAssets, RemoteAssetsErrorMessage, RemoteAssetsProvider, RemoteAssetsProviderCustom, RemoteAssetsStore, RpcBroadcastOptions, type RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedRpcFn, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, StaticAssetsSource };
|
|
@@ -22,12 +22,12 @@ type RpcFunctionType = 'static' | 'action' | 'event' | 'query';
|
|
|
22
22
|
/**
|
|
23
23
|
* Agent exposure settings for an RPC function. When this field is set,
|
|
24
24
|
* the function is surfaced to agents (e.g. via the devframe MCP adapter)
|
|
25
|
-
* as a callable tool. Functions without an `agent` field are not exposed
|
|
25
|
+
* as a callable tool. Functions without an `agent` field are not exposed;
|
|
26
26
|
* default-deny.
|
|
27
27
|
*/
|
|
28
28
|
interface RpcFunctionAgentOptions {
|
|
29
29
|
/**
|
|
30
|
-
* Human-readable description shown to the agent. Required
|
|
30
|
+
* Human-readable description shown to the agent. Required, since agents
|
|
31
31
|
* rely on this to decide when to invoke the tool. Keep it to ~1–3
|
|
32
32
|
* sentences explaining what the tool does and when to use it.
|
|
33
33
|
*/
|
|
@@ -40,9 +40,9 @@ interface RpcFunctionAgentOptions {
|
|
|
40
40
|
/**
|
|
41
41
|
* Safety classification. Drives MCP annotations (`readOnlyHint`,
|
|
42
42
|
* `destructiveHint`) downstream.
|
|
43
|
-
* - `'read'
|
|
44
|
-
* - `'action'
|
|
45
|
-
* - `'destructive'
|
|
43
|
+
* - `'read'`: no side effects; safe to call freely.
|
|
44
|
+
* - `'action'`: mutates state but not destructive.
|
|
45
|
+
* - `'destructive'`: may perform destructive updates.
|
|
46
46
|
*
|
|
47
47
|
* When omitted it is inferred from the function `type`:
|
|
48
48
|
* - `'static'` / `'query'` → `'read'`
|
|
@@ -158,17 +158,17 @@ interface RpcFunctionDefinitionBase {
|
|
|
158
158
|
/** Function type (static, action, event, or query) */
|
|
159
159
|
type?: RpcFunctionType;
|
|
160
160
|
/**
|
|
161
|
-
* Declares whether this function's args/return are JSON-serializable
|
|
162
|
-
*
|
|
161
|
+
* Declares whether this function's args/return are JSON-serializable,
|
|
162
|
+
* i.e. no `Map`, `Set`, `Date`, `BigInt`, class instances, circular
|
|
163
163
|
* references, `undefined` leaves, `Symbol`, or `Function` values.
|
|
164
164
|
*
|
|
165
|
-
* - `true
|
|
165
|
+
* - `true`: args and return are encoded with strict `JSON.stringify`
|
|
166
166
|
* on the wire and on disk. Misshapen values throw `DF0019` at the
|
|
167
167
|
* sender, surfacing the bug *during the offending call* rather than
|
|
168
168
|
* silently coercing to `{}` later. Required for `agent` exposure.
|
|
169
|
-
* - `false` (default)
|
|
169
|
+
* - `false` (default): payloads use `structured-clone-es`, which
|
|
170
170
|
* round-trips Maps/Sets/cycles. Functions in this mode cannot be
|
|
171
|
-
* exposed via the `agent` field
|
|
171
|
+
* exposed via the `agent` field; registration throws `DF0018`.
|
|
172
172
|
*/
|
|
173
173
|
jsonSerializable?: boolean;
|
|
174
174
|
}
|
|
@@ -221,9 +221,9 @@ type RpcFunctionDefinition<NAME extends string, TYPE extends RpcFunctionType = '
|
|
|
221
221
|
* Declares whether this function's args/return are JSON-serializable
|
|
222
222
|
* (no Map/Set/Date/BigInt/cycles/class instances/undefined/Symbol/Function).
|
|
223
223
|
*
|
|
224
|
-
* - `true
|
|
224
|
+
* - `true`: wire and dump use strict `JSON.stringify`; misshapen
|
|
225
225
|
* values throw `DF0019` at the call site. Required for `agent`.
|
|
226
|
-
* - `false` (default)
|
|
226
|
+
* - `false` (default): `structured-clone-es` round-trips fancy
|
|
227
227
|
* types. Cannot be `agent`-exposed (registration throws `DF0018`).
|
|
228
228
|
*/
|
|
229
229
|
jsonSerializable?: boolean;
|
|
@@ -244,7 +244,7 @@ type RpcFunctionDefinition<NAME extends string, TYPE extends RpcFunctionType = '
|
|
|
244
244
|
* handler once with no arguments and stores the result as both a
|
|
245
245
|
* no-args record and the fallback so any call variant resolves
|
|
246
246
|
* to the same snapshot. Only valid on `query` (or untyped)
|
|
247
|
-
* functions
|
|
247
|
+
* functions; `static` already has equivalent default behavior.
|
|
248
248
|
*/
|
|
249
249
|
snapshot?: boolean;
|
|
250
250
|
/** Per-context setup-result cache, populated by `getRpcResolvedSetupResult`. @internal */
|
|
@@ -266,9 +266,9 @@ type RpcFunctionDefinition<NAME extends string, TYPE extends RpcFunctionType = '
|
|
|
266
266
|
* Declares whether this function's args/return are JSON-serializable
|
|
267
267
|
* (no Map/Set/Date/BigInt/cycles/class instances/undefined/Symbol/Function).
|
|
268
268
|
*
|
|
269
|
-
* - `true
|
|
269
|
+
* - `true`: wire and dump use strict `JSON.stringify`; misshapen
|
|
270
270
|
* values throw `DF0019` at the call site. Required for `agent`.
|
|
271
|
-
* - `false` (default)
|
|
271
|
+
* - `false` (default): `structured-clone-es` round-trips fancy
|
|
272
272
|
* types. Cannot be `agent`-exposed (registration throws `DF0018`).
|
|
273
273
|
*/
|
|
274
274
|
jsonSerializable?: boolean;
|
|
@@ -281,7 +281,7 @@ type RpcFunctionDefinition<NAME extends string, TYPE extends RpcFunctionType = '
|
|
|
281
281
|
setup?: (context: CONTEXT) => Thenable<RpcFunctionSetupResult<InferArgsType<AS>, Thenable<InferReturnType<RS>>>>;
|
|
282
282
|
/**
|
|
283
283
|
* Function implementation (required if setup doesn't provide one).
|
|
284
|
-
* The declared `returns` schema describes the *resolved* value
|
|
284
|
+
* The declared `returns` schema describes the *resolved* value:
|
|
285
285
|
* async handlers return a promise of it (the runtime always awaits).
|
|
286
286
|
*/
|
|
287
287
|
handler?: (...args: InferArgsType<AS>) => Thenable<InferReturnType<RS>>;
|
|
@@ -293,7 +293,7 @@ type RpcFunctionDefinition<NAME extends string, TYPE extends RpcFunctionType = '
|
|
|
293
293
|
* handler once with no arguments and stores the result as both a
|
|
294
294
|
* no-args record and the fallback so any call variant resolves
|
|
295
295
|
* to the same snapshot. Only valid on `query` (or untyped)
|
|
296
|
-
* functions
|
|
296
|
+
* functions; `static` already has equivalent default behavior.
|
|
297
297
|
*/
|
|
298
298
|
snapshot?: boolean;
|
|
299
299
|
/** Per-context setup-result cache, populated by `getRpcResolvedSetupResult`. @internal */
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Derive the wire-safe agent tool name for an internal tool id.
|
|
4
4
|
*
|
|
5
|
-
* Devframe tool ids are colon-namespaced
|
|
5
|
+
* Devframe tool ids are colon-namespaced: `devframe:<area>:<fn>` for
|
|
6
6
|
* built-ins, `devframes:plugin:<slug>:<fn>` for plugin RPCs, and hub
|
|
7
7
|
* command ids for command-derived tools. MCP clients constrain tool names
|
|
8
8
|
* to `^[a-zA-Z0-9_-]{1,128}$`, so the agent/MCP boundary derives the wire
|
|
9
9
|
* name automatically: every run of characters outside `[a-zA-Z0-9_-]`
|
|
10
10
|
* becomes a single `_`, truncated to 128 characters. Internal ids never
|
|
11
|
-
* change
|
|
11
|
+
* change; resolution back to the id happens at the boundary.
|
|
12
12
|
*
|
|
13
13
|
* ```
|
|
14
14
|
* devframe:state:read → devframe_state_read
|
|
@@ -7,13 +7,13 @@ const MAX_TOOL_NAME_LENGTH = 128;
|
|
|
7
7
|
/**
|
|
8
8
|
* Derive the wire-safe agent tool name for an internal tool id.
|
|
9
9
|
*
|
|
10
|
-
* Devframe tool ids are colon-namespaced
|
|
10
|
+
* Devframe tool ids are colon-namespaced: `devframe:<area>:<fn>` for
|
|
11
11
|
* built-ins, `devframes:plugin:<slug>:<fn>` for plugin RPCs, and hub
|
|
12
12
|
* command ids for command-derived tools. MCP clients constrain tool names
|
|
13
13
|
* to `^[a-zA-Z0-9_-]{1,128}$`, so the agent/MCP boundary derives the wire
|
|
14
14
|
* name automatically: every run of characters outside `[a-zA-Z0-9_-]`
|
|
15
15
|
* becomes a single `_`, truncated to 128 characters. Internal ids never
|
|
16
|
-
* change
|
|
16
|
+
* change; resolution back to the id happens at the boundary.
|
|
17
17
|
*
|
|
18
18
|
* ```
|
|
19
19
|
* devframe:state:read → devframe_state_read
|
package/dist/utils/colors.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/utils/crypto-token.d.ts
|
|
2
2
|
/**
|
|
3
3
|
* Generate a high-entropy, URL-safe (hex) random token suitable for use as a
|
|
4
|
-
* bearer credential
|
|
4
|
+
* bearer credential, e.g. the persistent client auth token or an ephemeral
|
|
5
5
|
* remote-dock token. Defaults to 16 bytes (128 bits) of entropy.
|
|
6
6
|
*/
|
|
7
7
|
declare function randomToken(byteLength?: number): string;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const HEX = "0123456789abcdef";
|
|
3
3
|
/**
|
|
4
4
|
* Generate a high-entropy, URL-safe (hex) random token suitable for use as a
|
|
5
|
-
* bearer credential
|
|
5
|
+
* bearer credential, e.g. the persistent client auth token or an ephemeral
|
|
6
6
|
* remote-dock token. Defaults to 16 bytes (128 bits) of entropy.
|
|
7
7
|
*/
|
|
8
8
|
function randomToken(byteLength = 16) {
|
package/dist/utils/events.d.mts
CHANGED
package/dist/utils/nostics.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as Diagnostic, c as DiagnosticHandle, d as Diagnostics, f as ansiFormatter, g as formatDiagnostic, h as defineProdDiagnostics, i as DevframeDefineDiagnosticsOptions, l as DiagnosticInit, m as defineDiagnostics, n as ConsoleMethod, o as DiagnosticCallParams, p as createConsoleReporter, r as ConsoleReporterOptions, s as DiagnosticDefinition, t as AnyDiagnosticReporter, u as DiagnosticReporter } from "../nostics-
|
|
1
|
+
import { a as Diagnostic, c as DiagnosticHandle, d as Diagnostics, f as ansiFormatter, g as formatDiagnostic, h as defineProdDiagnostics, i as DevframeDefineDiagnosticsOptions, l as DiagnosticInit, m as defineDiagnostics, n as ConsoleMethod, o as DiagnosticCallParams, p as createConsoleReporter, r as ConsoleReporterOptions, s as DiagnosticDefinition, t as AnyDiagnosticReporter, u as DiagnosticReporter } from "../nostics-0sKe5HIj.mjs";
|
|
2
2
|
export { type AnyDiagnosticReporter, type ConsoleMethod, type ConsoleReporterOptions, DevframeDefineDiagnosticsOptions, type Diagnostic, type DiagnosticCallParams, type DiagnosticDefinition, type DiagnosticHandle, type DiagnosticInit, type DiagnosticReporter, type Diagnostics, ansiFormatter, createConsoleReporter, defineDiagnostics, defineProdDiagnostics, formatDiagnostic };
|
package/dist/utils/nostics.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as defineProdDiagnostics, i as defineDiagnostics, n as ansiFormatter, o as formatDiagnostic, r as createConsoleReporter, t as Diagnostic } from "../nostics-
|
|
1
|
+
import { a as defineProdDiagnostics, i as defineDiagnostics, n as ansiFormatter, o as formatDiagnostic, r as createConsoleReporter, t as Diagnostic } from "../nostics-D0PvLZsn.mjs";
|
|
2
2
|
export { Diagnostic, ansiFormatter, createConsoleReporter, defineDiagnostics, defineProdDiagnostics, formatDiagnostic };
|
package/dist/utils/open.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
//#region src/utils/open.ts
|
|
5
5
|
/**
|
|
6
6
|
* Launches `command` detached from the current process and resolves once
|
|
7
|
-
* the OS has accepted the spawn (not once the launched app exits)
|
|
7
|
+
* the OS has accepted the spawn (not once the launched app exits), the
|
|
8
8
|
* same "fire and forget" behavior `open`'s default (`wait: false`) gave us.
|
|
9
9
|
*/
|
|
10
10
|
function spawnDetached(command, args) {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//#region src/utils/origin.ts
|
|
2
|
+
/**
|
|
3
|
+
* Origin and hostname predicates shared by the RPC transports (the WS upgrade,
|
|
4
|
+
* SSE, and MCP origin gates) and the instance shell's authentication-link
|
|
5
|
+
* origin validation. Kept dependency-free and runtime-agnostic so any consumer
|
|
6
|
+
* can pull in a single check without dragging in a transport's `crossws`
|
|
7
|
+
* import.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
|
|
11
|
+
* subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
|
|
12
|
+
* `127.0.0.0/8` loopback block.
|
|
13
|
+
*
|
|
14
|
+
* The IPv4 case is matched **structurally**: the whole hostname must be a
|
|
15
|
+
* canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
|
|
16
|
+
* `startsWith('127.')` prefix check would also accept an attacker-controlled
|
|
17
|
+
* DNS name that merely *begins* with `127.` (`127.attacker.example`,
|
|
18
|
+
* `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
|
|
19
|
+
* the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
|
|
20
|
+
* cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
|
|
21
|
+
* genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
|
|
22
|
+
* those DNS names.
|
|
23
|
+
*/
|
|
24
|
+
function isLoopbackHostname(hostname) {
|
|
25
|
+
const h = hostname.replace(/^\[|\]$/g, "");
|
|
26
|
+
if (h === "localhost" || h.endsWith(".localhost") || h === "::1") return true;
|
|
27
|
+
return isLoopbackIPv4(h);
|
|
28
|
+
}
|
|
29
|
+
/** A canonical dotted-decimal IPv4 literal in `127.0.0.0/8`. */
|
|
30
|
+
function isLoopbackIPv4(hostname) {
|
|
31
|
+
const octets = hostname.split(".");
|
|
32
|
+
if (octets.length !== 4 || !octets.every(isDecimalOctet)) return false;
|
|
33
|
+
return Number(octets[0]) === 127;
|
|
34
|
+
}
|
|
35
|
+
/** A single canonical IPv4 octet: 1–3 digits, no leading zero, value 0–255. */
|
|
36
|
+
function isDecimalOctet(part) {
|
|
37
|
+
if (!/^\d{1,3}$/.test(part) || part.length > 1 && part[0] === "0") return false;
|
|
38
|
+
return Number(part) <= 255;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Default origin policy for a localhost dev tool: allow requests with no
|
|
42
|
+
* `Origin` header (native, non-browser clients), allow any loopback origin
|
|
43
|
+
* (so cross-port localhost dev setups keep working), and allow explicitly
|
|
44
|
+
* configured origins. Everything else, such as a real remote page in the dev's
|
|
45
|
+
* browser, is rejected.
|
|
46
|
+
*/
|
|
47
|
+
function isAllowedOrigin(origin, allowedOrigins) {
|
|
48
|
+
if (!origin) return true;
|
|
49
|
+
if (allowedOrigins.includes(origin)) return true;
|
|
50
|
+
try {
|
|
51
|
+
return isLoopbackHostname(new URL(origin).hostname);
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Decide whether a request-derived origin candidate may back a devframe's
|
|
58
|
+
* advertised public origin, the destination of the OTP magic link. Stricter
|
|
59
|
+
* than {@link isAllowedOrigin}: it rejects credentials, a path, a query, a
|
|
60
|
+
* fragment, a malformed port, and non-HTTP(S) schemes, and adopts a candidate
|
|
61
|
+
* only when its hostname is loopback or its canonical origin exactly matches
|
|
62
|
+
* an `allowedOrigins` entry (a caller with no static list passes none, so only
|
|
63
|
+
* loopback qualifies). Returns the canonical origin to adopt, or `undefined`
|
|
64
|
+
* to reject. Forwarded headers are never consulted.
|
|
65
|
+
*/
|
|
66
|
+
function validateOriginCandidate(candidate, allowedOrigins) {
|
|
67
|
+
let url;
|
|
68
|
+
try {
|
|
69
|
+
url = new URL(candidate);
|
|
70
|
+
} catch {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
74
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/" && url.pathname !== "") return void 0;
|
|
75
|
+
const canonical = url.origin;
|
|
76
|
+
if (canonical === "null") return void 0;
|
|
77
|
+
if (isLoopbackHostname(url.hostname) || allowedOrigins?.includes(canonical)) return canonical;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { isAllowedOrigin, isLoopbackHostname, validateOriginCandidate };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-assets-
|
|
1
|
+
import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-assets-eBvSKZMS.mjs";
|
|
2
2
|
//#region src/utils/remote-assets.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Normalize a {@link StaticAssetsSource} into something servable: a local
|
|
@@ -7,7 +7,7 @@ import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-asset
|
|
|
7
7
|
* {@link RemoteAssetsStore} back-proxy. Remote caches live under
|
|
8
8
|
* `<projectStorageDir>/.remote-assets/<package>@<version>/`.
|
|
9
9
|
*
|
|
10
|
-
* A remote source's `package`/`version` are validated first (`DF0065`)
|
|
10
|
+
* A remote source's `package`/`version` are validated first (`DF0065`); both
|
|
11
11
|
* are interpolated into CDN URLs and the cache path.
|
|
12
12
|
*
|
|
13
13
|
* `defaultResolveFrom` (typically the declaring devframe's `importMetaUrl`)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as resolveStaticAssetsSource } from "../remote-assets-
|
|
1
|
+
import { t as resolveStaticAssetsSource } from "../remote-assets-DMFzLSoH.mjs";
|
|
2
2
|
export { resolveStaticAssetsSource };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RemoteAssetsStore } from "../remote-assets-
|
|
1
|
+
import { a as RemoteAssetsStore } from "../remote-assets-eBvSKZMS.mjs";
|
|
2
2
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
3
3
|
import { EventHandler, H3 } from "h3";
|
|
4
4
|
//#region src/utils/serve-static.d.ts
|
|
@@ -14,12 +14,12 @@ interface ServeStaticOptions {
|
|
|
14
14
|
single?: boolean;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* h3 event handler that serves files from `source` with SPA fallback
|
|
17
|
+
* h3 event handler that serves files from `source` with SPA fallback: a
|
|
18
18
|
* local directory, or a {@link RemoteAssetsStore} whose files stream through
|
|
19
19
|
* the CDN back-proxy into the local cache.
|
|
20
20
|
*
|
|
21
21
|
* Drop-in replacement for `fromNodeMiddleware(sirv(dir, { dev: true, single: true }))`
|
|
22
|
-
* when the surrounding server is an h3 app
|
|
22
|
+
* when the surrounding server is an h3 app: no `Cache-Control` beyond
|
|
23
23
|
* `no-store`, `Content-Type` resolved via `mrmime`, and a miss with no
|
|
24
24
|
* file extension falls back to `<dir>/index.html` so client-side routing
|
|
25
25
|
* works.
|
|
@@ -37,7 +37,7 @@ declare function mountStaticHandler(app: H3, base: string, source: ServableAsset
|
|
|
37
37
|
* Connect/Express-style Node middleware variant of {@link serveStaticHandler}.
|
|
38
38
|
*
|
|
39
39
|
* Use when mounting onto `viteServer.middlewares.use(base, …)` or any other
|
|
40
|
-
* Connect stack
|
|
40
|
+
* Connect stack; avoids forcing the host package to depend on h3 just to
|
|
41
41
|
* adapt an event handler back into Node middleware.
|
|
42
42
|
*/
|
|
43
43
|
declare function serveStaticNodeMiddleware(source: ServableAssets, options?: ServeStaticOptions): (req: IncomingMessage, res: ServerResponse, next?: (err?: Error) => void) => void;
|
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import { t as DEVFRAME_EVENTS } from "../events-
|
|
1
|
+
import { t as DEVFRAME_EVENTS } from "../events-BV4Dj59a.mjs";
|
|
2
|
+
import { realpath, stat } from "node:fs/promises";
|
|
2
3
|
import { extname, join, normalize, resolve, sep } from "pathe";
|
|
3
4
|
import { createReadStream } from "node:fs";
|
|
4
|
-
import { stat } from "node:fs/promises";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { lookup } from "mrmime";
|
|
7
7
|
import { H3, defineHandler } from "h3";
|
|
8
8
|
//#region src/utils/serve-static.ts
|
|
9
9
|
const HTML_EXTENSIONS = [".html", ".htm"];
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The canonical (symlink-resolved) served root, falling back to the lexical
|
|
12
|
+
* path when the directory doesn't exist yet (an empty deployment then serves
|
|
13
|
+
* nothing rather than throwing).
|
|
14
|
+
*/
|
|
15
|
+
async function canonicalRoot(absDir) {
|
|
16
|
+
return realpath(absDir).then(normalize, () => absDir);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Stat a candidate file, confirming its canonical target stays inside the
|
|
20
|
+
* canonical served root; a symlink inside the root can only resolve to a
|
|
21
|
+
* file still within it; one escaping the root reads as a miss, not a leak.
|
|
22
|
+
*/
|
|
23
|
+
async function statFile(abs, realRoot) {
|
|
11
24
|
try {
|
|
12
25
|
const s = await stat(abs);
|
|
13
|
-
|
|
26
|
+
const real = normalize(await realpath(abs));
|
|
27
|
+
if (!s.isFile() || real !== realRoot && !real.startsWith(realRoot + sep)) return null;
|
|
14
28
|
return {
|
|
15
29
|
abs,
|
|
16
30
|
size: s.size,
|
|
@@ -20,7 +34,7 @@ async function statFile(abs) {
|
|
|
20
34
|
return null;
|
|
21
35
|
}
|
|
22
36
|
}
|
|
23
|
-
|
|
37
|
+
function cleanUrlPath(urlPath) {
|
|
24
38
|
let cleaned;
|
|
25
39
|
try {
|
|
26
40
|
cleaned = decodeURIComponent(urlPath || "/");
|
|
@@ -30,23 +44,44 @@ async function resolveTarget(absDir, urlPath, indexNames, single) {
|
|
|
30
44
|
cleaned = cleaned.replace(/[?#].*$/, "");
|
|
31
45
|
if (cleaned.endsWith("/")) cleaned = cleaned.slice(0, -1);
|
|
32
46
|
if (cleaned.startsWith("/")) cleaned = cleaned.slice(1);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (direct) return direct;
|
|
47
|
+
return cleaned;
|
|
48
|
+
}
|
|
49
|
+
async function resolveDirectoryIndex(abs, realRoot, indexNames) {
|
|
37
50
|
try {
|
|
38
51
|
if ((await stat(abs)).isDirectory()) for (const name of indexNames) {
|
|
39
|
-
const candidate = await statFile(join(abs, name));
|
|
52
|
+
const candidate = await statFile(join(abs, name), realRoot);
|
|
40
53
|
if (candidate) return candidate;
|
|
41
54
|
}
|
|
42
55
|
} catch {}
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Mirror sirv's `extensions: ['html', 'htm']` default: an extension-less
|
|
60
|
+
* request tries `${path}.html` / `${path}.htm` so pretty-URL deployments
|
|
61
|
+
* resolve to the right page before the SPA fallback.
|
|
62
|
+
*/
|
|
63
|
+
async function resolveHtmlExtension(abs, cleaned, realRoot) {
|
|
64
|
+
if (extname(cleaned)) return null;
|
|
65
|
+
for (const ext of HTML_EXTENSIONS) {
|
|
66
|
+
const candidate = await statFile(abs + ext, realRoot);
|
|
45
67
|
if (candidate) return candidate;
|
|
46
68
|
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
async function resolveTarget(absDir, realRoot, urlPath, indexNames, single) {
|
|
72
|
+
const cleaned = cleanUrlPath(urlPath);
|
|
73
|
+
if (cleaned === null) return null;
|
|
74
|
+
const abs = normalize(join(absDir, cleaned));
|
|
75
|
+
if (abs !== absDir && !abs.startsWith(absDir + sep)) return null;
|
|
76
|
+
const direct = await statFile(abs, realRoot);
|
|
77
|
+
if (direct) return direct;
|
|
78
|
+
const indexed = await resolveDirectoryIndex(abs, realRoot, indexNames);
|
|
79
|
+
if (indexed) return indexed;
|
|
80
|
+
const htmlExt = await resolveHtmlExtension(abs, cleaned, realRoot);
|
|
81
|
+
if (htmlExt) return htmlExt;
|
|
47
82
|
const fallbackIndex = indexNames[0];
|
|
48
83
|
if (single && fallbackIndex && !/\.[a-z0-9]+$/i.test(cleaned)) {
|
|
49
|
-
const indexFile = await statFile(join(absDir, fallbackIndex));
|
|
84
|
+
const indexFile = await statFile(join(absDir, fallbackIndex), realRoot);
|
|
50
85
|
if (indexFile) return indexFile;
|
|
51
86
|
}
|
|
52
87
|
return null;
|
|
@@ -77,7 +112,7 @@ function normalizeOptions(options) {
|
|
|
77
112
|
/**
|
|
78
113
|
* Drive one request through a {@link RemoteAssetsStore}: the store's
|
|
79
114
|
* `Response` on a hit, a 404 on a miss, or a 502 (styled error page for HTML
|
|
80
|
-
* navigations) on provider failure
|
|
115
|
+
* navigations) on provider failure, shared between the h3 and connect flavors.
|
|
81
116
|
*/
|
|
82
117
|
async function remoteResponse(store, urlPath, accept) {
|
|
83
118
|
try {
|
|
@@ -109,12 +144,12 @@ function serveRemoteAssetsHandler(store) {
|
|
|
109
144
|
});
|
|
110
145
|
}
|
|
111
146
|
/**
|
|
112
|
-
* h3 event handler that serves files from `source` with SPA fallback
|
|
147
|
+
* h3 event handler that serves files from `source` with SPA fallback: a
|
|
113
148
|
* local directory, or a {@link RemoteAssetsStore} whose files stream through
|
|
114
149
|
* the CDN back-proxy into the local cache.
|
|
115
150
|
*
|
|
116
151
|
* Drop-in replacement for `fromNodeMiddleware(sirv(dir, { dev: true, single: true }))`
|
|
117
|
-
* when the surrounding server is an h3 app
|
|
152
|
+
* when the surrounding server is an h3 app: no `Cache-Control` beyond
|
|
118
153
|
* `no-store`, `Content-Type` resolved via `mrmime`, and a miss with no
|
|
119
154
|
* file extension falls back to `<dir>/index.html` so client-side routing
|
|
120
155
|
* works.
|
|
@@ -123,6 +158,7 @@ function serveStaticHandler(source, options) {
|
|
|
123
158
|
if (typeof source !== "string") return serveRemoteAssetsHandler(source);
|
|
124
159
|
const absDir = resolve(source);
|
|
125
160
|
const opts = normalizeOptions(options);
|
|
161
|
+
const realRoot = canonicalRoot(absDir);
|
|
126
162
|
return defineHandler(async (event) => {
|
|
127
163
|
const method = event.req.method;
|
|
128
164
|
if (method !== "GET" && method !== "HEAD") {
|
|
@@ -130,7 +166,7 @@ function serveStaticHandler(source, options) {
|
|
|
130
166
|
event.res.headers.set("Allow", "GET, HEAD");
|
|
131
167
|
return "";
|
|
132
168
|
}
|
|
133
|
-
const file = await resolveTarget(absDir, event.url.pathname, opts.indexNames, opts.single);
|
|
169
|
+
const file = await resolveTarget(absDir, await realRoot, event.url.pathname, opts.indexNames, opts.single);
|
|
134
170
|
if (!file) {
|
|
135
171
|
event.res.status = 404;
|
|
136
172
|
return "";
|
|
@@ -156,12 +192,13 @@ function mountStaticHandler(app, base, source, options) {
|
|
|
156
192
|
* Connect/Express-style Node middleware variant of {@link serveStaticHandler}.
|
|
157
193
|
*
|
|
158
194
|
* Use when mounting onto `viteServer.middlewares.use(base, …)` or any other
|
|
159
|
-
* Connect stack
|
|
195
|
+
* Connect stack; avoids forcing the host package to depend on h3 just to
|
|
160
196
|
* adapt an event handler back into Node middleware.
|
|
161
197
|
*/
|
|
162
198
|
function serveStaticNodeMiddleware(source, options) {
|
|
163
199
|
const absDir = typeof source === "string" ? resolve(source) : void 0;
|
|
164
200
|
const opts = normalizeOptions(options);
|
|
201
|
+
const realRoot = absDir === void 0 ? void 0 : canonicalRoot(absDir);
|
|
165
202
|
return (req, res, next) => {
|
|
166
203
|
(async () => {
|
|
167
204
|
const method = req.method;
|
|
@@ -192,7 +229,7 @@ function serveStaticNodeMiddleware(source, options) {
|
|
|
192
229
|
Readable.fromWeb(response.body).pipe(res);
|
|
193
230
|
return;
|
|
194
231
|
}
|
|
195
|
-
const file = await resolveTarget(absDir, url, opts.indexNames, opts.single);
|
|
232
|
+
const file = await resolveTarget(absDir, await realRoot, url, opts.indexNames, opts.single);
|
|
196
233
|
if (!file) {
|
|
197
234
|
if (next) {
|
|
198
235
|
next();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as SharedStateEvents, D as ImmutableObject, E as ImmutableMap, M as SharedStatePatch, N as createSharedState, O as ImmutableSet, T as ImmutableArray, j as SharedStateOptions, k as SharedState, w as Immutable } from "../context-
|
|
1
|
+
import { A as SharedStateEvents, D as ImmutableObject, E as ImmutableMap, M as SharedStatePatch, N as createSharedState, O as ImmutableSet, T as ImmutableArray, j as SharedStateOptions, k as SharedState, w as Immutable } from "../context-CHW4BZOj.mjs";
|
|
2
2
|
export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, SharedStatePatch, createSharedState };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createSharedState } from "../shared-state
|
|
1
|
+
import { t as createSharedState } from "../shared-state-CaxB1q0h.mjs";
|
|
2
2
|
export { createSharedState };
|