veryfront 0.1.68 → 0.1.71
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/esm/deno.js +1 -1
- package/esm/src/agent/factory.d.ts +6 -1
- package/esm/src/agent/factory.d.ts.map +1 -1
- package/esm/src/agent/factory.js +31 -1
- package/esm/src/agent/types.d.ts +2 -0
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/build/binary-plugin-includes.d.ts +5 -0
- package/esm/src/build/binary-plugin-includes.d.ts.map +1 -0
- package/esm/src/build/binary-plugin-includes.js +14 -0
- package/esm/src/html/styles-builder/plugin-loader.d.ts.map +1 -1
- package/esm/src/html/styles-builder/plugin-loader.js +2 -1
- package/esm/src/internal-agents/control-plane-auth.d.ts +1 -0
- package/esm/src/internal-agents/control-plane-auth.d.ts.map +1 -1
- package/esm/src/internal-agents/control-plane-auth.js +9 -1
- package/esm/src/server/handlers/request/channel-invoke.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/channel-invoke.handler.js +2 -1
- package/esm/src/transforms/esm/http-cache-helpers.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache-helpers.js +13 -1
- package/package.json +1 -1
- package/scripts/postinstall-lib.js +79 -0
- package/scripts/postinstall.js +8 -1
- package/src/deno.js +1 -1
- package/src/src/agent/factory.ts +35 -1
- package/src/src/agent/types.ts +2 -0
- package/src/src/build/binary-plugin-includes.ts +17 -0
- package/src/src/html/styles-builder/plugin-loader.ts +2 -1
- package/src/src/internal-agents/control-plane-auth.ts +10 -1
- package/src/src/server/handlers/request/channel-invoke.handler.ts +2 -1
- package/src/src/transforms/esm/http-cache-helpers.ts +18 -1
package/esm/deno.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import type { Agent, AgentConfig } from "./types.js";
|
|
1
|
+
import type { Agent, AgentConfig, AgentMiddleware } from "./types.js";
|
|
2
2
|
export declare function agent(config: AgentConfig): Agent;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the middleware array for an agent, prepending security middleware
|
|
5
|
+
* unless explicitly opted out with `security: false`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveSecurityMiddleware(config: Pick<AgentConfig, "security" | "middleware">): AgentMiddleware[];
|
|
3
8
|
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/agent/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,KAAK,EACL,WAAW,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/agent/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EACX,eAAe,EAKhB,MAAM,YAAY,CAAC;AA+CpB,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CA4MhD;AAcD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC,GACnD,eAAe,EAAE,CAcnB"}
|
package/esm/src/agent/factory.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createExecuteSkillScriptTool, createLoadSkillReferenceTool, createLoadS
|
|
|
9
9
|
import { agentRegistry } from "./composition/index.js";
|
|
10
10
|
import { agentLogger } from "../utils/logger/logger.js";
|
|
11
11
|
import { createError, toError } from "../errors/veryfront-error.js";
|
|
12
|
+
import { COMMON_BLOCKED_PATTERNS, securityMiddleware } from "./middleware/security/validator.js";
|
|
12
13
|
import { withSpan } from "../observability/tracing/otlp-setup.js";
|
|
13
14
|
import { resolveConfiguredAgentModel } from "./runtime/model-resolution.js";
|
|
14
15
|
const STREAMING_HEADERS = {
|
|
@@ -90,6 +91,7 @@ export function agent(config) {
|
|
|
90
91
|
return `${basePrompt}\n\n${buildSkillManifestPrompt(currentSkills)}`;
|
|
91
92
|
}
|
|
92
93
|
: originalSystem;
|
|
94
|
+
const resolvedMiddleware = resolveSecurityMiddleware(config);
|
|
93
95
|
const platform = detectPlatform();
|
|
94
96
|
const compatibility = validatePlatformCompatibility({
|
|
95
97
|
maxSteps: config.maxSteps,
|
|
@@ -110,6 +112,7 @@ export function agent(config) {
|
|
|
110
112
|
...publicConfig,
|
|
111
113
|
tools: mergedToolsConfig,
|
|
112
114
|
system: augmentedSystem,
|
|
115
|
+
middleware: resolvedMiddleware,
|
|
113
116
|
});
|
|
114
117
|
const agentInstance = {
|
|
115
118
|
id,
|
|
@@ -171,7 +174,34 @@ export function agent(config) {
|
|
|
171
174
|
// Register on globalThis so compiled-binary runtime shim can delegate to the
|
|
172
175
|
// real factory. External temp-file modules can't import from the embedded
|
|
173
176
|
// binary FS, so they use globalThis bridges instead.
|
|
174
|
-
dntShim.dntGlobalThis
|
|
177
|
+
if (!("__vfAgentFactory" in dntShim.dntGlobalThis)) {
|
|
178
|
+
Object.defineProperty(dntShim.dntGlobalThis, "__vfAgentFactory", {
|
|
179
|
+
value: agent,
|
|
180
|
+
writable: false,
|
|
181
|
+
enumerable: false,
|
|
182
|
+
configurable: false,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Resolve the middleware array for an agent, prepending security middleware
|
|
187
|
+
* unless explicitly opted out with `security: false`.
|
|
188
|
+
*/
|
|
189
|
+
export function resolveSecurityMiddleware(config) {
|
|
190
|
+
if (config.security === false)
|
|
191
|
+
return config.middleware ?? [];
|
|
192
|
+
return [
|
|
193
|
+
securityMiddleware({
|
|
194
|
+
input: {
|
|
195
|
+
maxLength: 50_000,
|
|
196
|
+
blockedPatterns: COMMON_BLOCKED_PATTERNS.promptInjection,
|
|
197
|
+
},
|
|
198
|
+
output: {
|
|
199
|
+
filterPII: true,
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
202
|
+
...(config.middleware ?? []),
|
|
203
|
+
];
|
|
204
|
+
}
|
|
175
205
|
let agentIdCounter = 0;
|
|
176
206
|
function generateAgentId() {
|
|
177
207
|
return `agent_${Date.now()}_${agentIdCounter++}`;
|
package/esm/src/agent/types.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export interface AgentConfig {
|
|
|
45
45
|
* and registers the skill tools.
|
|
46
46
|
*/
|
|
47
47
|
skills?: true | string[];
|
|
48
|
+
/** Set to false to disable the default security middleware */
|
|
49
|
+
security?: false;
|
|
48
50
|
}
|
|
49
51
|
export type ResolvedAgentConfig = AgentConfig & {
|
|
50
52
|
model: ModelString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/agent/types.ts"],"names":[],"mappings":"AAAA;;4BAE4B;AAC5B,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAG3D,YAAY,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,YAAY,EACZ,OAAO,EACP,WAAW,EACX,aAAa,EACb,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAGjC,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,0EAA0E;IAC1E,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;IAC9B;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/agent/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const BINARY_TAILWIND_PLUGIN_PACKAGES: readonly ["tailwindcss-animate@1.0.7", "@tailwindcss/typography@0.5.19", "@tailwindcss/forms@0.5.11", "tailwind-scrollbar-hide@2.0.0", "daisyui@5.5.14"];
|
|
2
|
+
export declare function getTailwindPluginBundleUrl(packageName: string): string;
|
|
3
|
+
export declare function getBinaryPluginBundleIncludes(): string[];
|
|
4
|
+
export { BINARY_TAILWIND_PLUGIN_PACKAGES };
|
|
5
|
+
//# sourceMappingURL=binary-plugin-includes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-plugin-includes.d.ts","sourceRoot":"","sources":["../../../src/src/build/binary-plugin-includes.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,+BAA+B,0JAM3B,CAAC;AAEX,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,6BAA6B,IAAI,MAAM,EAAE,CAExD;AAED,OAAO,EAAE,+BAA+B,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const BINARY_TAILWIND_PLUGIN_PACKAGES = [
|
|
2
|
+
"tailwindcss-animate@1.0.7",
|
|
3
|
+
"@tailwindcss/typography@0.5.19",
|
|
4
|
+
"@tailwindcss/forms@0.5.11",
|
|
5
|
+
"tailwind-scrollbar-hide@2.0.0",
|
|
6
|
+
"daisyui@5.5.14",
|
|
7
|
+
];
|
|
8
|
+
export function getTailwindPluginBundleUrl(packageName) {
|
|
9
|
+
return `https://esm.sh/${packageName}?bundle&external=tailwindcss&target=denonext`;
|
|
10
|
+
}
|
|
11
|
+
export function getBinaryPluginBundleIncludes() {
|
|
12
|
+
return BINARY_TAILWIND_PLUGIN_PACKAGES.map(getTailwindPluginBundleUrl);
|
|
13
|
+
}
|
|
14
|
+
export { BINARY_TAILWIND_PLUGIN_PACKAGES };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../../../../src/src/html/styles-builder/plugin-loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../../../../src/src/html/styles-builder/plugin-loader.ts"],"names":[],"mappings":"AAwGA;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0D/E;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CAmClB"}
|
|
@@ -12,6 +12,7 @@ import defaultTheme from "tailwindcss/defaultTheme";
|
|
|
12
12
|
import colors from "tailwindcss/colors";
|
|
13
13
|
import { serverLogger } from "../../utils/index.js";
|
|
14
14
|
import { getErrorBySlug, IMPORT_RESOLUTION_ERROR, NETWORK_ERROR, VeryfrontError, } from "../../errors/index.js";
|
|
15
|
+
import { getTailwindPluginBundleUrl } from "../../build/binary-plugin-includes.js";
|
|
15
16
|
const logger = serverLogger.component("tailwind");
|
|
16
17
|
// Provide localStorage shim for plugins that use util-deprecate (which checks localStorage)
|
|
17
18
|
// This prevents "LocalStorage is not supported in this context" errors in Deno.
|
|
@@ -88,7 +89,7 @@ async function importBundledModule(code) {
|
|
|
88
89
|
* dynamic imports from URLs. Fetches bundled code, rewrites imports, loads via temp file.
|
|
89
90
|
*/
|
|
90
91
|
export async function loadModuleFromEsmSh(packageName) {
|
|
91
|
-
const stubUrl =
|
|
92
|
+
const stubUrl = getTailwindPluginBundleUrl(packageName);
|
|
92
93
|
logger.debug("Fetching esm.sh stub", { url: stubUrl });
|
|
93
94
|
const stubResponse = await dntShim.fetch(stubUrl);
|
|
94
95
|
if (!stubResponse.ok) {
|
|
@@ -4,6 +4,7 @@ export declare class ControlPlaneRequestError extends Error {
|
|
|
4
4
|
readonly status: number;
|
|
5
5
|
constructor(status: number, message: string);
|
|
6
6
|
}
|
|
7
|
+
export declare function getControlPlaneVerificationPublicKey(ctx: HandlerContext): string | undefined;
|
|
7
8
|
export declare function verifyControlPlaneRequest(req: dntShim.Request, ctx: HandlerContext, rawBody: string, options?: {
|
|
8
9
|
expectedSubject?: string;
|
|
9
10
|
expectedSurface?: "studio" | "channels" | "a2a" | "mcp";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-plane-auth.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/control-plane-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"control-plane-auth.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/control-plane-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAQxD,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED,wBAAgB,oCAAoC,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAM5F;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,CAAC;CACpD;;;;;;;;;GAsDP"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { verifyControlPlaneJws } from "../channels/control-plane.js";
|
|
2
|
+
import { getHostEnv } from "../platform/compat/process.js";
|
|
2
3
|
import { serverLogger } from "../utils/index.js";
|
|
3
4
|
import { HTTP_INTERNAL_SERVER_ERROR } from "../utils/constants/index.js";
|
|
4
5
|
const CONTROL_PLANE_JWS_HEADER = "x-veryfront-control-plane-jws";
|
|
@@ -12,8 +13,15 @@ export class ControlPlaneRequestError extends Error {
|
|
|
12
13
|
this.name = "ControlPlaneRequestError";
|
|
13
14
|
}
|
|
14
15
|
}
|
|
16
|
+
export function getControlPlaneVerificationPublicKey(ctx) {
|
|
17
|
+
// Project env overlays intentionally hide host secrets from request-scoped reads.
|
|
18
|
+
// Control-plane verification is framework-owned config, so it must fall back to
|
|
19
|
+
// the host environment when the runtime adapter env is overlay-aware.
|
|
20
|
+
return ctx.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY") ??
|
|
21
|
+
getHostEnv("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
|
|
22
|
+
}
|
|
15
23
|
export async function verifyControlPlaneRequest(req, ctx, rawBody, options = {}) {
|
|
16
|
-
const publicKeyPem = ctx
|
|
24
|
+
const publicKeyPem = getControlPlaneVerificationPublicKey(ctx);
|
|
17
25
|
if (!publicKeyPem) {
|
|
18
26
|
throw new ControlPlaneRequestError(HTTP_INTERNAL_SERVER_ERROR, "Control-plane verification is not configured");
|
|
19
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-invoke.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/channel-invoke.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EACL,KAAK,iBAAiB,EAKvB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"channel-invoke.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/channel-invoke.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EACL,KAAK,iBAAiB,EAKvB,MAAM,6BAA6B,CAAC;AAUrC,qBAAa,oBAAqB,SAAQ,WAAW;IAOvC,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,QAAQ,EAAE,eAAe,CAIvB;gBAE2B,IAAI,GAAE,iBAA4C;IAIzE,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAiEhF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseHandler } from "../response/base.js";
|
|
2
2
|
import { ChannelInvokeRequestSchema, defaultChannelInvokeDeps, executeChannelInvoke, verifyDispatchJws, } from "../../../channels/invoke.js";
|
|
3
|
+
import { getControlPlaneVerificationPublicKey } from "../../../internal-agents/control-plane-auth.js";
|
|
3
4
|
import { HTTP_INTERNAL_SERVER_ERROR, PRIORITY_MEDIUM_API, } from "../../../utils/constants/index.js";
|
|
4
5
|
const DISPATCH_JWS_HEADER = "x-veryfront-dispatch-jws";
|
|
5
6
|
const MAX_DISPATCH_SIGNATURE_AGE_SECONDS = 60;
|
|
@@ -22,7 +23,7 @@ export class ChannelInvokeHandler extends BaseHandler {
|
|
|
22
23
|
const builder = this.createResponseBuilder(ctx)
|
|
23
24
|
.withCORS(req, ctx.securityConfig?.cors)
|
|
24
25
|
.withSecurity(ctx.securityConfig ?? undefined, req);
|
|
25
|
-
const publicKeyPem = ctx
|
|
26
|
+
const publicKeyPem = getControlPlaneVerificationPublicKey(ctx);
|
|
26
27
|
if (!publicKeyPem) {
|
|
27
28
|
this.logWarn("Missing CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY for channel invoke endpoint");
|
|
28
29
|
return this.respond(builder.json({ error: "Channel dispatch verification is not configured" }, HTTP_INTERNAL_SERVER_ERROR));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-cache-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAKzE;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC;IACjC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACvB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,eAAe,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAK3D;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEvE;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAqBhD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"http-cache-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAKzE;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC;IACjC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACvB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,eAAe,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAK3D;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEvE;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAqBhD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA2BpD;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,eAAe,EAC1B,YAAY,GAAE,MAA8B,GAC3C,MAAM,CAmBR;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAkBrF"}
|
|
@@ -65,7 +65,19 @@ export function normalizeHttpUrl(raw) {
|
|
|
65
65
|
const url = new URL(raw);
|
|
66
66
|
normalizeEsmShUrl(url);
|
|
67
67
|
url.searchParams.sort();
|
|
68
|
-
|
|
68
|
+
const normalized = url.toString();
|
|
69
|
+
// esm.sh misbehaves when list-valued params such as
|
|
70
|
+
// `external=react,react-dom` are percent-encoded as `%2C`.
|
|
71
|
+
// Preserve literal commas only for the affected param so unrelated
|
|
72
|
+
// query values remain canonically encoded.
|
|
73
|
+
if (url.hostname === "esm.sh") {
|
|
74
|
+
const external = url.searchParams.get("external");
|
|
75
|
+
if (!external)
|
|
76
|
+
return normalized;
|
|
77
|
+
const encodedExternal = encodeURIComponent(external);
|
|
78
|
+
return normalized.replace(`external=${encodedExternal}`, `external=${encodedExternal.replace(/%2C/gi, ",")}`);
|
|
79
|
+
}
|
|
80
|
+
return normalized;
|
|
69
81
|
}
|
|
70
82
|
catch (_) {
|
|
71
83
|
/* expected: URL may be malformed */
|
package/package.json
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createReadStream, existsSync, unlinkSync } from "node:fs";
|
|
3
|
+
import https from "node:https";
|
|
4
|
+
|
|
5
|
+
export function computeFileHash(filePath) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const hash = createHash("sha256");
|
|
8
|
+
const stream = createReadStream(filePath);
|
|
9
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
10
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
11
|
+
stream.on("error", reject);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function downloadText(url, maxRedirects = 5) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
function follow(currentUrl, redirectCount) {
|
|
18
|
+
if (redirectCount > maxRedirects) {
|
|
19
|
+
return reject(new Error("Too many redirects"));
|
|
20
|
+
}
|
|
21
|
+
let settled = false;
|
|
22
|
+
https.get(currentUrl, (response) => {
|
|
23
|
+
const { statusCode = 0, headers } = response;
|
|
24
|
+
if (statusCode >= 301 && statusCode <= 308 && statusCode !== 304) {
|
|
25
|
+
response.resume();
|
|
26
|
+
const location = headers.location;
|
|
27
|
+
if (!location) return reject(new Error("Redirect missing Location"));
|
|
28
|
+
try { return follow(new URL(location, currentUrl).toString(), redirectCount + 1); }
|
|
29
|
+
catch { return reject(new Error(`Invalid redirect URL: ${location}`)); }
|
|
30
|
+
}
|
|
31
|
+
if (statusCode !== 200) {
|
|
32
|
+
response.resume();
|
|
33
|
+
return reject(new Error(`HTTP ${statusCode}`));
|
|
34
|
+
}
|
|
35
|
+
const MAX_CHECKSUM_SIZE = 1024;
|
|
36
|
+
let data = "";
|
|
37
|
+
response.on("data", (chunk) => {
|
|
38
|
+
data += chunk;
|
|
39
|
+
if (!settled && data.length > MAX_CHECKSUM_SIZE) {
|
|
40
|
+
settled = true;
|
|
41
|
+
response.destroy();
|
|
42
|
+
reject(new Error("Checksum file too large"));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
response.on("end", () => { if (!settled) resolve(data); });
|
|
46
|
+
}).on("error", (err) => { if (!settled) reject(err); });
|
|
47
|
+
}
|
|
48
|
+
follow(url, 0);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function verifyChecksum(filePath, checksumUrl, downloadFn = downloadText) {
|
|
53
|
+
let checksumText;
|
|
54
|
+
try {
|
|
55
|
+
checksumText = await downloadFn(checksumUrl);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
if (err.message === "HTTP 404") {
|
|
58
|
+
console.warn("⚠️ No checksum file available — skipping verification");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Failed to fetch checksum: ${err.message}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Checksum file format: "<hash> <filename>" or just "<hash>"
|
|
65
|
+
const expectedHash = checksumText.trim().split(/\s+/)[0].toLowerCase();
|
|
66
|
+
if (!/^[0-9a-f]{64}$/.test(expectedHash)) {
|
|
67
|
+
throw new Error(`Invalid checksum format: ${expectedHash}`);
|
|
68
|
+
}
|
|
69
|
+
const actualHash = await computeFileHash(filePath);
|
|
70
|
+
|
|
71
|
+
if (actualHash !== expectedHash) {
|
|
72
|
+
try { if (existsSync(filePath)) unlinkSync(filePath); } catch {}
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Checksum mismatch!\n Expected: ${expectedHash}\n Actual: ${actualHash}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log("✅ Checksum verified");
|
|
79
|
+
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -11,6 +11,7 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import https from "node:https";
|
|
12
12
|
import os from "node:os";
|
|
13
13
|
import { readFileSync } from "node:fs";
|
|
14
|
+
import { verifyChecksum } from "./postinstall-lib.js";
|
|
14
15
|
|
|
15
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
17
|
const platform = os.platform();
|
|
@@ -85,7 +86,7 @@ function downloadBinary(url, dest, maxRedirects = 5) {
|
|
|
85
86
|
|
|
86
87
|
const file = createWriteStream(dest);
|
|
87
88
|
response.pipe(file);
|
|
88
|
-
file.on('finish', () => { file.close()
|
|
89
|
+
file.on('finish', () => { file.close(() => resolve()); });
|
|
89
90
|
file.on("error", (err) => {
|
|
90
91
|
try { if (existsSync(dest)) unlinkSync(dest); }
|
|
91
92
|
catch (e) { console.warn(" Warning: Failed to clean up partial download:", e.message); }
|
|
@@ -103,6 +104,10 @@ async function install() {
|
|
|
103
104
|
console.log(`⬇️ Downloading binary from ${url}...`);
|
|
104
105
|
await downloadBinary(url, binPath);
|
|
105
106
|
|
|
107
|
+
// Verify binary integrity
|
|
108
|
+
const checksumUrl = `${baseUrl}/${binaryName}.sha256`;
|
|
109
|
+
await verifyChecksum(binPath, checksumUrl);
|
|
110
|
+
|
|
106
111
|
// Make binary executable (Unix systems)
|
|
107
112
|
if (platform !== "win32") {
|
|
108
113
|
chmodSync(binPath, 0o755);
|
|
@@ -114,6 +119,8 @@ async function install() {
|
|
|
114
119
|
console.log(' npx veryfront create my-app');
|
|
115
120
|
|
|
116
121
|
} catch (error) {
|
|
122
|
+
// Clean up unverified binary so the JS fallback is used instead
|
|
123
|
+
try { if (existsSync(binPath)) unlinkSync(binPath); } catch {}
|
|
117
124
|
// Graceful fallback - bundled JS CLI will be used instead
|
|
118
125
|
console.warn("⚠️ Binary download failed:", error.message);
|
|
119
126
|
console.warn(" Falling back to bundled JavaScript CLI (slower startup)");
|
package/src/deno.js
CHANGED
package/src/src/agent/factory.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as dntShim from "../../_dnt.shims.js";
|
|
|
2
2
|
import type {
|
|
3
3
|
Agent,
|
|
4
4
|
AgentConfig,
|
|
5
|
+
AgentMiddleware,
|
|
5
6
|
AgentResponse,
|
|
6
7
|
AgentStreamResult,
|
|
7
8
|
Message,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
import { agentRegistry } from "./composition/index.js";
|
|
25
26
|
import { agentLogger } from "../utils/logger/logger.js";
|
|
26
27
|
import { createError, toError } from "../errors/veryfront-error.js";
|
|
28
|
+
import { COMMON_BLOCKED_PATTERNS, securityMiddleware } from "./middleware/security/validator.js";
|
|
27
29
|
import { withSpan } from "../observability/tracing/otlp-setup.js";
|
|
28
30
|
import { resolveConfiguredAgentModel } from "./runtime/model-resolution.js";
|
|
29
31
|
|
|
@@ -118,6 +120,8 @@ export function agent(config: AgentConfig): Agent {
|
|
|
118
120
|
}
|
|
119
121
|
: originalSystem;
|
|
120
122
|
|
|
123
|
+
const resolvedMiddleware = resolveSecurityMiddleware(config);
|
|
124
|
+
|
|
121
125
|
const platform = detectPlatform();
|
|
122
126
|
const compatibility = validatePlatformCompatibility(
|
|
123
127
|
{
|
|
@@ -148,6 +152,7 @@ export function agent(config: AgentConfig): Agent {
|
|
|
148
152
|
...publicConfig,
|
|
149
153
|
tools: mergedToolsConfig,
|
|
150
154
|
system: augmentedSystem,
|
|
155
|
+
middleware: resolvedMiddleware,
|
|
151
156
|
});
|
|
152
157
|
|
|
153
158
|
const agentInstance: Agent = {
|
|
@@ -258,7 +263,36 @@ export function agent(config: AgentConfig): Agent {
|
|
|
258
263
|
// Register on globalThis so compiled-binary runtime shim can delegate to the
|
|
259
264
|
// real factory. External temp-file modules can't import from the embedded
|
|
260
265
|
// binary FS, so they use globalThis bridges instead.
|
|
261
|
-
(dntShim.dntGlobalThis
|
|
266
|
+
if (!("__vfAgentFactory" in dntShim.dntGlobalThis)) {
|
|
267
|
+
Object.defineProperty(dntShim.dntGlobalThis, "__vfAgentFactory", {
|
|
268
|
+
value: agent,
|
|
269
|
+
writable: false,
|
|
270
|
+
enumerable: false,
|
|
271
|
+
configurable: false,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Resolve the middleware array for an agent, prepending security middleware
|
|
277
|
+
* unless explicitly opted out with `security: false`.
|
|
278
|
+
*/
|
|
279
|
+
export function resolveSecurityMiddleware(
|
|
280
|
+
config: Pick<AgentConfig, "security" | "middleware">,
|
|
281
|
+
): AgentMiddleware[] {
|
|
282
|
+
if (config.security === false) return config.middleware ?? [];
|
|
283
|
+
return [
|
|
284
|
+
securityMiddleware({
|
|
285
|
+
input: {
|
|
286
|
+
maxLength: 50_000,
|
|
287
|
+
blockedPatterns: COMMON_BLOCKED_PATTERNS.promptInjection,
|
|
288
|
+
},
|
|
289
|
+
output: {
|
|
290
|
+
filterPII: true,
|
|
291
|
+
},
|
|
292
|
+
}),
|
|
293
|
+
...(config.middleware ?? []),
|
|
294
|
+
];
|
|
295
|
+
}
|
|
262
296
|
|
|
263
297
|
let agentIdCounter = 0;
|
|
264
298
|
|
package/src/src/agent/types.ts
CHANGED
|
@@ -78,6 +78,8 @@ export interface AgentConfig {
|
|
|
78
78
|
* and registers the skill tools.
|
|
79
79
|
*/
|
|
80
80
|
skills?: true | string[];
|
|
81
|
+
/** Set to false to disable the default security middleware */
|
|
82
|
+
security?: false;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
export type ResolvedAgentConfig = AgentConfig & { model: ModelString };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const BINARY_TAILWIND_PLUGIN_PACKAGES = [
|
|
2
|
+
"tailwindcss-animate@1.0.7",
|
|
3
|
+
"@tailwindcss/typography@0.5.19",
|
|
4
|
+
"@tailwindcss/forms@0.5.11",
|
|
5
|
+
"tailwind-scrollbar-hide@2.0.0",
|
|
6
|
+
"daisyui@5.5.14",
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
export function getTailwindPluginBundleUrl(packageName: string): string {
|
|
10
|
+
return `https://esm.sh/${packageName}?bundle&external=tailwindcss&target=denonext`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getBinaryPluginBundleIncludes(): string[] {
|
|
14
|
+
return BINARY_TAILWIND_PLUGIN_PACKAGES.map(getTailwindPluginBundleUrl);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { BINARY_TAILWIND_PLUGIN_PACKAGES };
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
NETWORK_ERROR,
|
|
21
21
|
VeryfrontError,
|
|
22
22
|
} from "../../errors/index.js";
|
|
23
|
+
import { getTailwindPluginBundleUrl } from "../../build/binary-plugin-includes.js";
|
|
23
24
|
|
|
24
25
|
const logger = serverLogger.component("tailwind");
|
|
25
26
|
|
|
@@ -108,7 +109,7 @@ async function importBundledModule(code: string): Promise<unknown> {
|
|
|
108
109
|
* dynamic imports from URLs. Fetches bundled code, rewrites imports, loads via temp file.
|
|
109
110
|
*/
|
|
110
111
|
export async function loadModuleFromEsmSh(packageName: string): Promise<unknown> {
|
|
111
|
-
const stubUrl =
|
|
112
|
+
const stubUrl = getTailwindPluginBundleUrl(packageName);
|
|
112
113
|
logger.debug("Fetching esm.sh stub", { url: stubUrl });
|
|
113
114
|
|
|
114
115
|
const stubResponse = await dntShim.fetch(stubUrl);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
2
|
import { verifyControlPlaneJws } from "../channels/control-plane.js";
|
|
3
|
+
import { getHostEnv } from "../platform/compat/process.js";
|
|
3
4
|
import type { HandlerContext } from "../types/index.js";
|
|
4
5
|
import { serverLogger } from "../utils/index.js";
|
|
5
6
|
import { HTTP_INTERNAL_SERVER_ERROR } from "../utils/constants/index.js";
|
|
@@ -18,6 +19,14 @@ export class ControlPlaneRequestError extends Error {
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
export function getControlPlaneVerificationPublicKey(ctx: HandlerContext): string | undefined {
|
|
23
|
+
// Project env overlays intentionally hide host secrets from request-scoped reads.
|
|
24
|
+
// Control-plane verification is framework-owned config, so it must fall back to
|
|
25
|
+
// the host environment when the runtime adapter env is overlay-aware.
|
|
26
|
+
return ctx.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY") ??
|
|
27
|
+
getHostEnv("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
export async function verifyControlPlaneRequest(
|
|
22
31
|
req: dntShim.Request,
|
|
23
32
|
ctx: HandlerContext,
|
|
@@ -27,7 +36,7 @@ export async function verifyControlPlaneRequest(
|
|
|
27
36
|
expectedSurface?: "studio" | "channels" | "a2a" | "mcp";
|
|
28
37
|
} = {},
|
|
29
38
|
) {
|
|
30
|
-
const publicKeyPem = ctx
|
|
39
|
+
const publicKeyPem = getControlPlaneVerificationPublicKey(ctx);
|
|
31
40
|
if (!publicKeyPem) {
|
|
32
41
|
throw new ControlPlaneRequestError(
|
|
33
42
|
HTTP_INTERNAL_SERVER_ERROR,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
executeChannelInvoke,
|
|
9
9
|
verifyDispatchJws,
|
|
10
10
|
} from "../../../channels/invoke.js";
|
|
11
|
+
import { getControlPlaneVerificationPublicKey } from "../../../internal-agents/control-plane-auth.js";
|
|
11
12
|
import {
|
|
12
13
|
HTTP_INTERNAL_SERVER_ERROR,
|
|
13
14
|
PRIORITY_MEDIUM_API,
|
|
@@ -37,7 +38,7 @@ export class ChannelInvokeHandler extends BaseHandler {
|
|
|
37
38
|
.withCORS(req, ctx.securityConfig?.cors)
|
|
38
39
|
.withSecurity(ctx.securityConfig ?? undefined, req);
|
|
39
40
|
|
|
40
|
-
const publicKeyPem = ctx
|
|
41
|
+
const publicKeyPem = getControlPlaneVerificationPublicKey(ctx);
|
|
41
42
|
if (!publicKeyPem) {
|
|
42
43
|
this.logWarn("Missing CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY for channel invoke endpoint");
|
|
43
44
|
return this.respond(
|
|
@@ -103,7 +103,24 @@ export function normalizeHttpUrl(raw: string): string {
|
|
|
103
103
|
const url = new URL(raw);
|
|
104
104
|
normalizeEsmShUrl(url);
|
|
105
105
|
url.searchParams.sort();
|
|
106
|
-
|
|
106
|
+
const normalized = url.toString();
|
|
107
|
+
|
|
108
|
+
// esm.sh misbehaves when list-valued params such as
|
|
109
|
+
// `external=react,react-dom` are percent-encoded as `%2C`.
|
|
110
|
+
// Preserve literal commas only for the affected param so unrelated
|
|
111
|
+
// query values remain canonically encoded.
|
|
112
|
+
if (url.hostname === "esm.sh") {
|
|
113
|
+
const external = url.searchParams.get("external");
|
|
114
|
+
if (!external) return normalized;
|
|
115
|
+
|
|
116
|
+
const encodedExternal = encodeURIComponent(external);
|
|
117
|
+
return normalized.replace(
|
|
118
|
+
`external=${encodedExternal}`,
|
|
119
|
+
`external=${encodedExternal.replace(/%2C/gi, ",")}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return normalized;
|
|
107
124
|
} catch (_) {
|
|
108
125
|
/* expected: URL may be malformed */
|
|
109
126
|
return raw;
|