veryfront 0.1.67 → 0.1.70

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.
Files changed (29) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/agent/factory.d.ts +6 -1
  3. package/esm/src/agent/factory.d.ts.map +1 -1
  4. package/esm/src/agent/factory.js +31 -1
  5. package/esm/src/agent/types.d.ts +2 -0
  6. package/esm/src/agent/types.d.ts.map +1 -1
  7. package/esm/src/build/binary-plugin-includes.d.ts +5 -0
  8. package/esm/src/build/binary-plugin-includes.d.ts.map +1 -0
  9. package/esm/src/build/binary-plugin-includes.js +14 -0
  10. package/esm/src/html/styles-builder/plugin-loader.d.ts.map +1 -1
  11. package/esm/src/html/styles-builder/plugin-loader.js +2 -1
  12. package/esm/src/internal-agents/control-plane-auth.d.ts +1 -0
  13. package/esm/src/internal-agents/control-plane-auth.d.ts.map +1 -1
  14. package/esm/src/internal-agents/control-plane-auth.js +9 -1
  15. package/esm/src/security/http/base-handler.d.ts.map +1 -1
  16. package/esm/src/security/http/base-handler.js +5 -4
  17. package/esm/src/server/handlers/request/channel-invoke.handler.d.ts.map +1 -1
  18. package/esm/src/server/handlers/request/channel-invoke.handler.js +2 -1
  19. package/package.json +1 -1
  20. package/scripts/postinstall-lib.js +79 -0
  21. package/scripts/postinstall.js +8 -1
  22. package/src/deno.js +1 -1
  23. package/src/src/agent/factory.ts +35 -1
  24. package/src/src/agent/types.ts +2 -0
  25. package/src/src/build/binary-plugin-includes.ts +17 -0
  26. package/src/src/html/styles-builder/plugin-loader.ts +2 -1
  27. package/src/src/internal-agents/control-plane-auth.ts +10 -1
  28. package/src/src/security/http/base-handler.ts +5 -4
  29. package/src/src/server/handlers/request/channel-invoke.handler.ts +2 -1
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.67",
3
+ "version": "0.1.70",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -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,EAKZ,MAAM,YAAY,CAAC;AA8CpB,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAyMhD"}
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"}
@@ -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.__vfAgentFactory = agent;
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++}`;
@@ -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":"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"}
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":"AAuGA;;;;;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"}
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 = `https://esm.sh/${packageName}?bundle&external=tailwindcss&target=denonext`;
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;AAE/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,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
+ {"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.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
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":"base-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/security/http/base-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,eAAe,EACf,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,qBAAqB,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,eAAe,CAAC;IAChF,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,aAAa,CAAC;IAC3F,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3F,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5C,QAAQ,EAAE,MAAM,aAAa,CAAC;CAC/B;AAED,8BAAsB,WAAY,YAAW,OAAO;IAClD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEnC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAMxC;IAEF,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAElF,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAY1E,OAAO,CAAC,cAAc;IAmBtB,SAAS,CAAC,qBAAqB,CAC7B,GAAG,EAAE,cAAc,EACnB,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,eAAe;IAWlB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,GAAG,IAAI;IAKhG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI;IAIhG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI;IAIhG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAKjD,SAAS,CAAC,QAAQ,IAAI,aAAa;IAInC,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;IAIhG,SAAS,CAAC,gBAAgB,CAAC,CAAC,EAC1B,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAO,GACvC,OAAO,CAAC,CAAC,CAAC;CAuDd"}
1
+ {"version":3,"file":"base-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/security/http/base-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,eAAe,EACf,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,qBAAqB,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,eAAe,CAAC;IAChF,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,aAAa,CAAC;IAC3F,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3F,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5C,QAAQ,EAAE,MAAM,aAAa,CAAC;CAC/B;AAED,8BAAsB,WAAY,YAAW,OAAO;IAClD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEnC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAMxC;IAEF,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAElF,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAY1E,OAAO,CAAC,cAAc;IAmBtB,SAAS,CAAC,qBAAqB,CAC7B,GAAG,EAAE,cAAc,EACnB,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,eAAe;IAWlB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,GAAG,IAAI;IAKhG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI;IAIhG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI;IAIhG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAKjD,SAAS,CAAC,QAAQ,IAAI,aAAa;IAInC,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;IAIhG,SAAS,CAAC,gBAAgB,CAAC,CAAC,EAC1B,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAO,GACvC,OAAO,CAAC,CAAC,CAAC;CAwDd"}
@@ -66,6 +66,7 @@ export class BaseHandler {
66
66
  return { response, continue: false, metadata };
67
67
  }
68
68
  withProxyContext(ctx, fn, options = {}) {
69
+ const effectiveToken = ctx.proxyToken || ctx.adapter.env.get("VERYFRONT_API_TOKEN") || "";
69
70
  const fsWrapper = ctx.adapter.fs;
70
71
  if (typeof fsWrapper.setRequestBranch === "function") {
71
72
  try {
@@ -76,7 +77,7 @@ export class BaseHandler {
76
77
  }
77
78
  }
78
79
  const requireToken = options.requireToken ?? false;
79
- if (!ctx.projectSlug || (requireToken && !ctx.proxyToken))
80
+ if (!ctx.projectSlug || (requireToken && !effectiveToken))
80
81
  return fn();
81
82
  if (fsWrapper.isMultiProjectMode?.()) {
82
83
  const isProduction = (ctx.resolvedEnvironment ?? ctx.requestContext?.mode) === "production";
@@ -87,10 +88,10 @@ export class BaseHandler {
87
88
  releaseId: ctx.releaseId,
88
89
  branch,
89
90
  }, ctx);
90
- return fsWrapper.runWithContext(ctx.projectSlug, ctx.proxyToken ?? "", fn, ctx.projectId, { productionMode: isProduction, releaseId: ctx.releaseId, branch });
91
+ return fsWrapper.runWithContext(ctx.projectSlug, effectiveToken, fn, ctx.projectId, { productionMode: isProduction, releaseId: ctx.releaseId, branch });
91
92
  }
92
- if (typeof fsWrapper.setRequestToken === "function" && ctx.proxyToken) {
93
- fsWrapper.setRequestToken(ctx.proxyToken);
93
+ if (typeof fsWrapper.setRequestToken === "function" && effectiveToken) {
94
+ fsWrapper.setRequestToken(effectiveToken);
94
95
  }
95
96
  return runWithCacheBatching(fn);
96
97
  }
@@ -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;AASrC,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
+ {"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.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.67",
3
+ "version": "0.1.70",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -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
+ }
@@ -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(); resolve(); });
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
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.67",
3
+ "version": "0.1.70",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -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 as Record<string, unknown>).__vfAgentFactory = agent;
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
 
@@ -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 = `https://esm.sh/${packageName}?bundle&external=tailwindcss&target=denonext`;
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.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
39
+ const publicKeyPem = getControlPlaneVerificationPublicKey(ctx);
31
40
  if (!publicKeyPem) {
32
41
  throw new ControlPlaneRequestError(
33
42
  HTTP_INTERNAL_SERVER_ERROR,
@@ -108,6 +108,7 @@ export abstract class BaseHandler implements Handler {
108
108
  fn: () => Promise<T>,
109
109
  options: { requireToken?: boolean } = {},
110
110
  ): Promise<T> {
111
+ const effectiveToken = ctx.proxyToken || ctx.adapter.env.get("VERYFRONT_API_TOKEN") || "";
111
112
  const fsWrapper = ctx.adapter.fs as {
112
113
  setRequestToken?: (t: string) => void;
113
114
  setRequestBranch?: (b: string | null) => void;
@@ -130,7 +131,7 @@ export abstract class BaseHandler implements Handler {
130
131
  }
131
132
 
132
133
  const requireToken = options.requireToken ?? false;
133
- if (!ctx.projectSlug || (requireToken && !ctx.proxyToken)) return fn();
134
+ if (!ctx.projectSlug || (requireToken && !effectiveToken)) return fn();
134
135
 
135
136
  if (fsWrapper.isMultiProjectMode?.()) {
136
137
  const isProduction = (ctx.resolvedEnvironment ?? ctx.requestContext?.mode) === "production";
@@ -149,15 +150,15 @@ export abstract class BaseHandler implements Handler {
149
150
 
150
151
  return fsWrapper.runWithContext!(
151
152
  ctx.projectSlug,
152
- ctx.proxyToken ?? "",
153
+ effectiveToken,
153
154
  fn,
154
155
  ctx.projectId,
155
156
  { productionMode: isProduction, releaseId: ctx.releaseId, branch },
156
157
  );
157
158
  }
158
159
 
159
- if (typeof fsWrapper.setRequestToken === "function" && ctx.proxyToken) {
160
- fsWrapper.setRequestToken(ctx.proxyToken);
160
+ if (typeof fsWrapper.setRequestToken === "function" && effectiveToken) {
161
+ fsWrapper.setRequestToken(effectiveToken);
161
162
  }
162
163
 
163
164
  return runWithCacheBatching(fn);
@@ -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.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
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(