veryfront 0.1.131 → 0.1.132

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 (35) hide show
  1. package/esm/_dnt.polyfills.d.ts +11 -0
  2. package/esm/_dnt.polyfills.d.ts.map +1 -1
  3. package/esm/_dnt.polyfills.js +14 -0
  4. package/esm/deno.js +1 -1
  5. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  6. package/esm/src/agent/runtime/index.js +17 -2
  7. package/esm/src/agent/runtime/tool-helpers.d.ts +2 -1
  8. package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
  9. package/esm/src/agent/runtime/tool-helpers.js +6 -3
  10. package/esm/src/html/html-injection.d.ts.map +1 -1
  11. package/esm/src/html/html-injection.js +6 -5
  12. package/esm/src/html/nonce-injection.d.ts +2 -0
  13. package/esm/src/html/nonce-injection.d.ts.map +1 -0
  14. package/esm/src/html/nonce-injection.js +104 -0
  15. package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
  16. package/esm/src/internal-agents/run-stream.js +26 -4
  17. package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
  18. package/esm/src/rendering/orchestrator/html.js +3 -89
  19. package/esm/src/rendering/script-page-handling.js +1 -0
  20. package/esm/src/server/handlers/request/static.handler.d.ts.map +1 -1
  21. package/esm/src/server/handlers/request/static.handler.js +18 -10
  22. package/esm/src/utils/version-constant.d.ts +1 -1
  23. package/esm/src/utils/version-constant.js +1 -1
  24. package/package.json +1 -1
  25. package/src/_dnt.polyfills.ts +27 -0
  26. package/src/deno.js +1 -1
  27. package/src/src/agent/runtime/index.ts +22 -0
  28. package/src/src/agent/runtime/tool-helpers.ts +15 -3
  29. package/src/src/html/html-injection.ts +9 -5
  30. package/src/src/html/nonce-injection.ts +129 -0
  31. package/src/src/internal-agents/run-stream.ts +35 -4
  32. package/src/src/rendering/orchestrator/html.ts +3 -105
  33. package/src/src/rendering/script-page-handling.ts +1 -0
  34. package/src/src/server/handlers/request/static.handler.ts +22 -10
  35. package/src/src/utils/version-constant.ts +1 -1
@@ -159,6 +159,17 @@ declare global {
159
159
  }
160
160
  }
161
161
  export {};
162
+ declare global {
163
+ interface Object {
164
+ /**
165
+ * Determines whether an object has a property with the specified name.
166
+ * @param o An object.
167
+ * @param v A property name.
168
+ */
169
+ hasOwn(o: object, v: PropertyKey): boolean;
170
+ }
171
+ }
172
+ export {};
162
173
  declare global {
163
174
  interface PromiseConstructor {
164
175
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"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"}
@@ -270,6 +270,20 @@ if (!Uint8Array.prototype.findLast) {
270
270
  return findLast(this, callbackfn, that);
271
271
  };
272
272
  }
273
+ // https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
274
+ if (!Object.hasOwn) {
275
+ Object.defineProperty(Object, "hasOwn", {
276
+ value: function (object, property) {
277
+ if (object == null) {
278
+ throw new TypeError("Cannot convert undefined or null to object");
279
+ }
280
+ return Object.prototype.hasOwnProperty.call(Object(object), property);
281
+ },
282
+ configurable: true,
283
+ enumerable: false,
284
+ writable: true,
285
+ });
286
+ }
273
287
  // https://github.com/tc39/proposal-promise-with-resolvers/blob/3a78801e073e99217dbeb2c43ba7212f3bdc8b83/polyfills.js#L1C1-L9C2
274
288
  if (Promise.withResolvers === undefined) {
275
289
  Promise.withResolvers = () => {
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.131",
3
+ "version": "0.1.132",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
@@ -117,6 +117,17 @@ function isLocalModel(model) {
117
117
  m.provider === "local" ||
118
118
  (typeof m.modelId === "string" && m.modelId.startsWith("local/"));
119
119
  }
120
+ function getRuntimeAllowedRemoteTools(config) {
121
+ const configWithRuntimeFilters = config;
122
+ if (!Object.hasOwn(configWithRuntimeFilters, "__vfAllowedRemoteTools")) {
123
+ return undefined;
124
+ }
125
+ const raw = configWithRuntimeFilters.__vfAllowedRemoteTools;
126
+ if (!Array.isArray(raw)) {
127
+ return [];
128
+ }
129
+ return raw.every((toolName) => typeof toolName === "string") ? raw : [];
130
+ }
120
131
  export class AgentRuntime {
121
132
  id;
122
133
  config;
@@ -281,11 +292,13 @@ export class AgentRuntime {
281
292
  }
282
293
  // Request-scoped skill policy (not class-level mutable state)
283
294
  let activeSkillPolicy;
295
+ const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
284
296
  for (let step = 0; step < maxSteps; step++) {
285
297
  this.status = "thinking";
286
298
  addSpanEvent(loopSpan, "step_start", { step });
287
299
  let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
288
300
  includeSkillTools: Boolean(this.config.skills),
301
+ allowedRemoteToolNames,
289
302
  });
290
303
  // Layer 1: Filter tools based on active skill policy (planning-time)
291
304
  if (activeSkillPolicy) {
@@ -387,7 +400,7 @@ export class AgentRuntime {
387
400
  agentId: this.id,
388
401
  toolCallId: tc.toolCallId,
389
402
  projectId: cacheCtx?.projectId,
390
- });
403
+ }, allowedRemoteToolNames);
391
404
  toolCall.status = "completed";
392
405
  toolCall.result = result;
393
406
  toolCall.executionTime = Date.now() - startTime;
@@ -473,11 +486,13 @@ export class AgentRuntime {
473
486
  // Request-scoped skill policy (not class-level mutable state)
474
487
  let activeSkillPolicy;
475
488
  let finalFinishReason;
489
+ const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
476
490
  for (let step = 0; step < maxSteps; step++) {
477
491
  throwIfAborted(abortSignal);
478
492
  sendSSE(controller, encoder, { type: "step-start" });
479
493
  let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
480
494
  includeSkillTools: Boolean(this.config.skills),
495
+ allowedRemoteToolNames,
481
496
  });
482
497
  // Layer 1: Filter tools based on active skill policy (planning-time)
483
498
  if (activeSkillPolicy) {
@@ -566,7 +581,7 @@ export class AgentRuntime {
566
581
  agentId: this.id,
567
582
  toolCallId: tc.id,
568
583
  ...toolContext,
569
- });
584
+ }, allowedRemoteToolNames);
570
585
  throwIfAborted(abortSignal);
571
586
  toolCall.status = "completed";
572
587
  toolCall.result = result;
@@ -28,7 +28,7 @@ export declare function isDynamicTool(name: string): boolean;
28
28
  */
29
29
  export type ToolConfigEntry = Tool<any, any> | boolean;
30
30
  export declare function resolveConfiguredTool(toolsConfig: true | Record<string, ToolConfigEntry> | undefined, toolName: string): Tool | null;
31
- export declare function executeConfiguredTool(toolName: string, input: Record<string, unknown>, toolsConfig: true | Record<string, ToolConfigEntry> | undefined, context?: ToolExecutionContext): Promise<unknown>;
31
+ export declare function executeConfiguredTool(toolName: string, input: Record<string, unknown>, toolsConfig: true | Record<string, ToolConfigEntry> | undefined, context?: ToolExecutionContext, allowedRemoteToolNames?: string[]): Promise<unknown>;
32
32
  /**
33
33
  * Get available tools based on agent configuration.
34
34
  * When tools === true, loads all tools from registry.
@@ -40,5 +40,6 @@ export declare function executeConfiguredTool(toolName: string, input: Record<st
40
40
  export declare function getAvailableTools(toolsConfig: true | Record<string, ToolConfigEntry> | undefined, options?: {
41
41
  includeSkillTools?: boolean;
42
42
  includeIntegrationTools?: boolean;
43
+ allowedRemoteToolNames?: string[];
43
44
  }): Promise<ToolDefinition[]>;
44
45
  //# sourceMappingURL=tool-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/tool-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYtF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACxC,cAAc,CAuBhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,QAAQ,EAAE,MAAM,GACf,IAAI,GAAG,IAAI,CAmBb;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAsBlB;AAoBD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3E,OAAO,CAAC,cAAc,EAAE,CAAC,CAwE3B"}
1
+ {"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/tool-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYtF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACxC,cAAc,CAuBhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,QAAQ,EAAE,MAAM,GACf,IAAI,GAAG,IAAI,CAmBb;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE,oBAAoB,EAC9B,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAChC,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAoBD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC,GACA,OAAO,CAAC,cAAc,EAAE,CAAC,CA4E3B"}
@@ -59,7 +59,7 @@ export function resolveConfiguredTool(toolsConfig, toolName) {
59
59
  }
60
60
  return null;
61
61
  }
62
- export async function executeConfiguredTool(toolName, input, toolsConfig, context) {
62
+ export async function executeConfiguredTool(toolName, input, toolsConfig, context, allowedRemoteToolNames) {
63
63
  const configuredTool = resolveConfiguredTool(toolsConfig, toolName);
64
64
  if (configuredTool) {
65
65
  return await configuredTool.execute(input, context);
@@ -71,6 +71,9 @@ export async function executeConfiguredTool(toolName, input, toolsConfig, contex
71
71
  }
72
72
  // Fall back to remote execution for integration tools (e.g., github:list-repos)
73
73
  if (isRemoteIntegrationTool(toolName)) {
74
+ if (allowedRemoteToolNames && !allowedRemoteToolNames.includes(toolName)) {
75
+ throw new Error(`Tool "${toolName}" is not allowed for this run`);
76
+ }
74
77
  return await executeRemoteIntegrationTool(toolName, input, context?.endUserId);
75
78
  }
76
79
  return await executeTool(toolName, input, context);
@@ -113,7 +116,7 @@ export async function getAvailableTools(toolsConfig, options) {
113
116
  if (options?.includeIntegrationTools !== false) {
114
117
  try {
115
118
  const { getRemoteIntegrationToolDefinitions } = await import("../../integrations/remote-tools.js");
116
- const remoteDefs = await getRemoteIntegrationToolDefinitions();
119
+ const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) => !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name));
117
120
  for (const def of remoteDefs) {
118
121
  logToolDefinition(def.name, def);
119
122
  }
@@ -143,7 +146,7 @@ export async function getAvailableTools(toolsConfig, options) {
143
146
  if (options?.includeIntegrationTools !== false) {
144
147
  try {
145
148
  const { getRemoteIntegrationToolDefinitions } = await import("../../integrations/remote-tools.js");
146
- const remoteDefs = await getRemoteIntegrationToolDefinitions();
149
+ const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) => !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name));
147
150
  for (const def of remoteDefs) {
148
151
  // Skip if already present (e.g., explicitly configured by name)
149
152
  if (!tools.some((t) => t.name === def.name)) {
@@ -1 +1 @@
1
- {"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CA+FR"}
1
+ {"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAmGR"}
@@ -54,23 +54,24 @@ export function injectHTMLContent(template, content, metadata, options) {
54
54
  environment: options.environment,
55
55
  }),
56
56
  });
57
- const hydrationScript = `<script id="veryfront-hydration-data" type="application/json">${hydrationData}</script>`;
57
+ const nonceAttr = buildNonceAttribute(options.nonce);
58
+ const hydrationScript = `<script id="veryfront-hydration-data" type="application/json"${nonceAttr}>${hydrationData}</script>`;
58
59
  html = html.replace(/<\/body>/i, `${hydrationScript}</body>`);
59
60
  }
60
61
  if (options.mode === "development") {
61
62
  const hasDevScriptsPlaceholder = /{{\s*devScripts\s*}}/i.test(html);
62
63
  if (hasDevScriptsPlaceholder) {
63
- html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts());
64
+ html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts(options.devPort, options.nonce));
64
65
  }
65
- html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles());
66
+ html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles(options.nonce));
66
67
  if (!hasDevScriptsPlaceholder && hasBodyClose) {
67
- html = html.replace(/<\/body>/i, `${getDevStyles()}${getDevScripts()}</body>`);
68
+ html = html.replace(/<\/body>/i, `${getDevStyles(options.nonce)}${getDevScripts(options.devPort, options.nonce)}</body>`);
68
69
  }
69
70
  }
70
71
  else {
71
72
  html = html.replace(/{{\s*devScripts\s*}}/gi, "");
72
73
  html = html.replace(/{{\s*devStyles\s*}}/gi, "");
73
- const prodScripts = getProdScripts(options.slug);
74
+ const prodScripts = getProdScripts(options.slug, options.nonce);
74
75
  const hasProdScriptsPlaceholder = /{{\s*prodScripts\s*}}/i.test(html);
75
76
  if (hasProdScriptsPlaceholder) {
76
77
  html = html.replace(/{{\s*prodScripts\s*}}/gi, prodScripts);
@@ -0,0 +1,2 @@
1
+ export declare function addNonceToHtmlTags(html: string, nonce?: string): string;
2
+ //# sourceMappingURL=nonce-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nonce-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/nonce-injection.ts"],"names":[],"mappings":"AAmEA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA6DvE"}
@@ -0,0 +1,104 @@
1
+ import { escapeHtml } from "../utils/html-escape.js";
2
+ function findTagEnd(html, start) {
3
+ let activeQuote = null;
4
+ for (let index = start + 1; index < html.length; index++) {
5
+ const char = html[index];
6
+ if (activeQuote) {
7
+ if (char === activeQuote)
8
+ activeQuote = null;
9
+ continue;
10
+ }
11
+ if (char === '"' || char === "'") {
12
+ activeQuote = char;
13
+ continue;
14
+ }
15
+ if (char === ">")
16
+ return index;
17
+ }
18
+ return -1;
19
+ }
20
+ function getOpeningTagName(tag) {
21
+ const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
22
+ const tagName = match?.[1]?.toLowerCase();
23
+ if (tagName === "script" || tagName === "style")
24
+ return tagName;
25
+ return undefined;
26
+ }
27
+ function isTagBoundary(char) {
28
+ return char === undefined || /\s|\/|>/u.test(char);
29
+ }
30
+ function findRawTextClosingTagStart(lowerHtml, tagName, fromIndex) {
31
+ const needle = `</${tagName}`;
32
+ let searchIndex = fromIndex;
33
+ while (searchIndex < lowerHtml.length) {
34
+ const closingIndex = lowerHtml.indexOf(needle, searchIndex);
35
+ if (closingIndex === -1)
36
+ return -1;
37
+ if (isTagBoundary(lowerHtml[closingIndex + needle.length])) {
38
+ return closingIndex;
39
+ }
40
+ searchIndex = closingIndex + needle.length;
41
+ }
42
+ return -1;
43
+ }
44
+ function injectNonceIntoOpeningTag(tag, escapedNonce) {
45
+ if (/(?:\s|<)nonce\s*=/iu.test(tag))
46
+ return tag;
47
+ const closeIndex = tag.lastIndexOf(">");
48
+ if (closeIndex === -1)
49
+ return tag;
50
+ const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
51
+ return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
52
+ }
53
+ export function addNonceToHtmlTags(html, nonce) {
54
+ if (!nonce)
55
+ return html;
56
+ const escapedNonce = escapeHtml(nonce);
57
+ const lowerHtml = html.toLowerCase();
58
+ let result = "";
59
+ let index = 0;
60
+ let rawTextTag = null;
61
+ while (index < html.length) {
62
+ if (rawTextTag) {
63
+ const closingIndex = findRawTextClosingTagStart(lowerHtml, rawTextTag, index);
64
+ if (closingIndex === -1) {
65
+ result += html.slice(index);
66
+ break;
67
+ }
68
+ result += html.slice(index, closingIndex);
69
+ index = closingIndex;
70
+ rawTextTag = null;
71
+ continue;
72
+ }
73
+ if (html.startsWith("<!--", index)) {
74
+ const commentEnd = html.indexOf("-->", index + 4);
75
+ const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
76
+ result += html.slice(index, endIndex);
77
+ index = endIndex;
78
+ continue;
79
+ }
80
+ if (html[index] !== "<") {
81
+ result += html[index];
82
+ index++;
83
+ continue;
84
+ }
85
+ const tagEnd = findTagEnd(html, index);
86
+ if (tagEnd === -1) {
87
+ result += html.slice(index);
88
+ break;
89
+ }
90
+ const tag = html.slice(index, tagEnd + 1);
91
+ const tagName = getOpeningTagName(tag);
92
+ if (!tagName) {
93
+ result += tag;
94
+ index = tagEnd + 1;
95
+ continue;
96
+ }
97
+ result += injectNonceIntoOpeningTag(tag, escapedNonce);
98
+ index = tagEnd + 1;
99
+ if (!/\/\s*>$/u.test(tag)) {
100
+ rawTextTag = tagName;
101
+ }
102
+ }
103
+ return result;
104
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAIxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAsKD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAsJ3B"}
1
+ {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAUxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAsLD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA+J3B"}
@@ -126,16 +126,38 @@ function normalizeRuntimeMessages(messages) {
126
126
  ...(message.metadata ? { metadata: message.metadata } : {}),
127
127
  }));
128
128
  }
129
+ function getAllowedRemoteToolNames(forwardedProps) {
130
+ const runtimeOverrides = isRecord(forwardedProps?.runtimeOverrides)
131
+ ? forwardedProps.runtimeOverrides
132
+ : null;
133
+ if (!runtimeOverrides || !Object.hasOwn(runtimeOverrides, "allowedTools")) {
134
+ return undefined;
135
+ }
136
+ const allowedTools = runtimeOverrides.allowedTools;
137
+ if (!Array.isArray(allowedTools)) {
138
+ return [];
139
+ }
140
+ return allowedTools.every((toolName) => typeof toolName === "string") ? allowedTools : [];
141
+ }
129
142
  export async function createRuntimeAgentStreamResponse(input, agent, deps) {
130
143
  const abortSignal = deps.sessionManager.startRun({
131
144
  runId: input.runId,
132
145
  threadId: input.threadId,
133
146
  });
134
147
  const mergedTools = buildMergedTools(agent, input, deps.sessionManager);
135
- const runtime = deps.createRuntime?.(agent, mergedTools) ?? new AgentRuntime(agent.id, {
136
- ...agent.config,
137
- tools: mergedTools,
138
- });
148
+ const allowedRemoteToolNames = getAllowedRemoteToolNames(input.forwardedProps);
149
+ const runtimeAgent = {
150
+ ...agent,
151
+ config: {
152
+ ...agent.config,
153
+ tools: mergedTools,
154
+ ...(allowedRemoteToolNames !== undefined
155
+ ? { __vfAllowedRemoteTools: allowedRemoteToolNames }
156
+ : {}),
157
+ },
158
+ };
159
+ const runtime = deps.createRuntime?.(runtimeAgent, mergedTools) ??
160
+ new AgentRuntime(runtimeAgent.id, runtimeAgent.config);
139
161
  let completedResponse = null;
140
162
  const runtimeMessages = normalizeRuntimeMessages(input.messages);
141
163
  let runtimeStream;
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA2HhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAajE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAgDZ,sBAAsB;YAiCtB,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAgF9B;;;;OAIG;YACW,gBAAgB;IA2D9B,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAyD5C"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqBhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAajE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAgDZ,sBAAsB;YAiCtB,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAgF9B;;;;OAIG;YACW,gBAAgB;IA2D9B,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAyD5C"}
@@ -2,7 +2,7 @@ import { join } from "../../platform/compat/path/index.js";
2
2
  import { getExtensionName } from "../../utils/path-utils.js";
3
3
  import { buildImportMapJson, extractHTMLMetadata, generateHTMLShellParts, injectHTMLContent, isFullHTMLDocument, } from "../../html/index.js";
4
4
  import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
5
- import { escapeHtml } from "../../utils/html-escape.js";
5
+ import { addNonceToHtmlTags } from "../../html/nonce-injection.js";
6
6
  import { injectElementSelectors } from "../../studio/element-selector-injector.js";
7
7
  import { computeSourceHash } from "../../studio/hash-utils.js";
8
8
  import { extractRelativePath } from "../../utils/route-path-utils.js";
@@ -16,92 +16,6 @@ import { getRouteCandidates } from "./css-candidate-manifest.js";
16
16
  import { resolveStyleContentVersion } from "../../html/styles-builder/content-version.js";
17
17
  import { createStyleScopeProfile } from "../../html/styles-builder/style-scope-profile.js";
18
18
  const logger = rendererLogger.component("html-generator");
19
- function findTagEnd(html, start) {
20
- let activeQuote = null;
21
- for (let index = start + 1; index < html.length; index++) {
22
- const char = html[index];
23
- if (activeQuote) {
24
- if (char === activeQuote)
25
- activeQuote = null;
26
- continue;
27
- }
28
- if (char === '"' || char === "'") {
29
- activeQuote = char;
30
- continue;
31
- }
32
- if (char === ">")
33
- return index;
34
- }
35
- return -1;
36
- }
37
- function getOpeningTagName(tag) {
38
- const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
39
- const tagName = match?.[1]?.toLowerCase();
40
- if (tagName === "script" || tagName === "style")
41
- return tagName;
42
- return undefined;
43
- }
44
- function injectNonceIntoOpeningTag(tag, escapedNonce) {
45
- if (/\bnonce\s*=/iu.test(tag))
46
- return tag;
47
- const closeIndex = tag.lastIndexOf(">");
48
- if (closeIndex === -1)
49
- return tag;
50
- const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
51
- return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
52
- }
53
- function addNonceToRenderedTags(html, nonce) {
54
- if (!nonce)
55
- return html;
56
- const escapedNonce = escapeHtml(nonce);
57
- const lowerHtml = html.toLowerCase();
58
- let result = "";
59
- let index = 0;
60
- let rawTextTag = null;
61
- while (index < html.length) {
62
- if (rawTextTag) {
63
- const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
64
- if (closingIndex === -1) {
65
- result += html.slice(index);
66
- break;
67
- }
68
- result += html.slice(index, closingIndex);
69
- index = closingIndex;
70
- rawTextTag = null;
71
- continue;
72
- }
73
- if (html.startsWith("<!--", index)) {
74
- const commentEnd = html.indexOf("-->", index + 4);
75
- const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
76
- result += html.slice(index, endIndex);
77
- index = endIndex;
78
- continue;
79
- }
80
- if (html[index] !== "<") {
81
- result += html[index];
82
- index++;
83
- continue;
84
- }
85
- const tagEnd = findTagEnd(html, index);
86
- if (tagEnd === -1) {
87
- result += html.slice(index);
88
- break;
89
- }
90
- const tag = html.slice(index, tagEnd + 1);
91
- const tagName = getOpeningTagName(tag);
92
- if (!tagName) {
93
- result += tag;
94
- index = tagEnd + 1;
95
- continue;
96
- }
97
- result += injectNonceIntoOpeningTag(tag, escapedNonce);
98
- index = tagEnd + 1;
99
- if (!/\/\s*>$/u.test(tag)) {
100
- rawTextTag = tagName;
101
- }
102
- }
103
- return result;
104
- }
105
19
  export class HTMLGenerator {
106
20
  config;
107
21
  constructor(config) {
@@ -115,7 +29,7 @@ export class HTMLGenerator {
115
29
  if (context.options?.studioEmbed) {
116
30
  logger.debug("Injected element selectors for Studio");
117
31
  }
118
- return addNonceToRenderedTags(finalHtml, context.options?.nonce);
32
+ return addNonceToHtmlTags(finalHtml, context.options?.nonce);
119
33
  }
120
34
  async generateHTMLStream(reactStream, context) {
121
35
  const fullContext = context;
@@ -137,7 +51,7 @@ export class HTMLGenerator {
137
51
  }
138
52
  const { start, end } = await profilePhase("html.generate_shell_parts", () => this.generateShellParts(fullContext, mergedFrontmatter, htmlOptions, reactContent, projectCSSPromise));
139
53
  const encoder = new TextEncoder();
140
- const fullHtml = addNonceToRenderedTags(`${start}${reactContent}${end}`, context.options?.nonce);
54
+ const fullHtml = addNonceToHtmlTags(`${start}${reactContent}${end}`, context.options?.nonce);
141
55
  return new ReadableStream({
142
56
  start(controller) {
143
57
  controller.enqueue(encoder.encode(fullHtml));
@@ -152,6 +152,7 @@ async function generateFullHtml(htmlBody, context) {
152
152
  mode: options.mode,
153
153
  slug,
154
154
  devPort: options.config?.dev?.port ?? DEFAULT_DASHBOARD_PORT,
155
+ nonce: options.nonce,
155
156
  });
156
157
  }
157
158
  const htmlOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAUnG,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,EAAE,eAAe,CAOvB;IAEF,OAAO,CAAC,aAAa,CAA2B;IAEhD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,cAAc;CAiEvB"}
1
+ {"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBnG,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,EAAE,eAAe,CAOvB;IAEF,OAAO,CAAC,aAAa,CAA2B;IAEhD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,cAAc;CAuEvB"}
@@ -3,6 +3,11 @@ import { hasMatchingEtag } from "../utils/etag.js";
3
3
  import { HTTP_NOT_FOUND, HTTP_OK, PRIORITY_MEDIUM_STATIC, } from "../../../utils/constants/index.js";
4
4
  import { withSpan } from "../../../observability/tracing/otlp-setup.js";
5
5
  import { StaticFileService } from "../../services/static/index.js";
6
+ import { addNonceToHtmlTags } from "../../../html/nonce-injection.js";
7
+ import { computeEtag } from "../utils/etag.js";
8
+ function isHtmlResponse(contentType) {
9
+ return /\btext\/html\b/i.test(contentType);
10
+ }
6
11
  export class StaticHandler extends BaseHandler {
7
12
  metadata = {
8
13
  name: "StaticHandler",
@@ -31,6 +36,8 @@ export class StaticHandler extends BaseHandler {
31
36
  const isHead = method === "HEAD";
32
37
  const isLocal = !!ctx.isLocalProject;
33
38
  const isPreviewMode = ctx.requestContext?.mode === "preview" && !isLocal;
39
+ const builder = this.createResponseBuilder(ctx)
40
+ .withCORS(req, ctx.securityConfig?.cors);
34
41
  const result = await this.staticService.resolveFile(pathname, {
35
42
  projectDir: ctx.projectDir,
36
43
  adapter: ctx.adapter,
@@ -40,24 +47,25 @@ export class StaticHandler extends BaseHandler {
40
47
  if (!result) {
41
48
  if (!this.staticService.isAssetRequest(pathname))
42
49
  return null;
43
- return this.createResponseBuilder(ctx)
44
- .withCORS(req, ctx.securityConfig?.cors)
50
+ return builder
45
51
  .withSecurity(ctx.securityConfig ?? undefined, req)
46
52
  .withCache("no-cache")
47
53
  .withContentType("text/plain; charset=utf-8", isHead ? null : "Not Found", HTTP_NOT_FOUND);
48
54
  }
49
- if (hasMatchingEtag(req, result.etag)) {
50
- return this.createResponseBuilder(ctx)
51
- .withCORS(req, ctx.securityConfig?.cors)
55
+ const responseData = isHtmlResponse(result.contentType)
56
+ ? new TextEncoder().encode(addNonceToHtmlTags(new TextDecoder().decode(result.data), builder.nonce))
57
+ : result.data;
58
+ const etag = computeEtag(responseData);
59
+ if (hasMatchingEtag(req, etag)) {
60
+ return builder
52
61
  .withSecurity(ctx.securityConfig ?? undefined, req)
53
- .notModified(result.etag);
62
+ .notModified(etag);
54
63
  }
55
- const body = isHead ? null : result.data.slice();
56
- const response = this.createResponseBuilder(ctx)
57
- .withCORS(req, ctx.securityConfig?.cors)
64
+ const body = isHead ? null : responseData.slice();
65
+ const response = builder
58
66
  .withSecurity(ctx.securityConfig ?? undefined, req)
59
67
  .withCache(result.cacheStrategy)
60
- .withETag(result.etag)
68
+ .withETag(etag)
61
69
  .withContentType(result.contentType, body, HTTP_OK);
62
70
  this.logDebug(`Served static file: ${result.path}`, {
63
71
  contentType: result.contentType,
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.131";
1
+ export declare const VERSION = "0.1.132";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.131";
3
+ export const VERSION = "0.1.132";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.131",
3
+ "version": "0.1.132",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -506,6 +506,33 @@ if (!Uint8Array.prototype.findLast) {
506
506
  };
507
507
  }
508
508
 
509
+ export {};
510
+ // https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
511
+ if (!Object.hasOwn) {
512
+ Object.defineProperty(Object, "hasOwn", {
513
+ value: function (object: any, property: any) {
514
+ if (object == null) {
515
+ throw new TypeError("Cannot convert undefined or null to object");
516
+ }
517
+ return Object.prototype.hasOwnProperty.call(Object(object), property);
518
+ },
519
+ configurable: true,
520
+ enumerable: false,
521
+ writable: true,
522
+ });
523
+ }
524
+
525
+ declare global {
526
+ interface Object {
527
+ /**
528
+ * Determines whether an object has a property with the specified name.
529
+ * @param o An object.
530
+ * @param v A property name.
531
+ */
532
+ hasOwn(o: object, v: PropertyKey): boolean;
533
+ }
534
+ }
535
+
509
536
  export {};
510
537
  declare global {
511
538
  // https://github.com/denoland/deno/blob/0bfa0cc0276e94f1a308aaad5f925eaacb6e3db2/cli/tsc/dts/lib.es2021.promise.d.ts#L53
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.131",
3
+ "version": "0.1.132",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -77,6 +77,10 @@ import { resolveConfiguredAgentModel, resolveRuntimeModel } from "./model-resolu
77
77
  const logger = serverLogger.component("agent");
78
78
  const LOAD_SKILL_TOOL_ID = "load-skill";
79
79
 
80
+ type RuntimeToolFilterConfig = AgentConfig & {
81
+ __vfAllowedRemoteTools?: string[];
82
+ };
83
+
80
84
  function createAbortError(reason?: unknown): Error {
81
85
  if (reason instanceof Error) {
82
86
  return reason;
@@ -187,6 +191,18 @@ function isLocalModel(model: LanguageModel): boolean {
187
191
  (typeof m.modelId === "string" && m.modelId.startsWith("local/"));
188
192
  }
189
193
 
194
+ function getRuntimeAllowedRemoteTools(config: AgentConfig): string[] | undefined {
195
+ const configWithRuntimeFilters = config as RuntimeToolFilterConfig;
196
+ if (!Object.hasOwn(configWithRuntimeFilters, "__vfAllowedRemoteTools")) {
197
+ return undefined;
198
+ }
199
+ const raw = configWithRuntimeFilters.__vfAllowedRemoteTools;
200
+ if (!Array.isArray(raw)) {
201
+ return [];
202
+ }
203
+ return raw.every((toolName) => typeof toolName === "string") ? raw : [];
204
+ }
205
+
190
206
  export class AgentRuntime {
191
207
  private id: string;
192
208
  private config: AgentConfig;
@@ -418,6 +434,7 @@ export class AgentRuntime {
418
434
 
419
435
  // Request-scoped skill policy (not class-level mutable state)
420
436
  let activeSkillPolicy: string[] | undefined;
437
+ const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
421
438
 
422
439
  for (let step = 0; step < maxSteps; step++) {
423
440
  this.status = "thinking";
@@ -425,6 +442,7 @@ export class AgentRuntime {
425
442
 
426
443
  let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
427
444
  includeSkillTools: Boolean(this.config.skills),
445
+ allowedRemoteToolNames,
428
446
  });
429
447
 
430
448
  // Layer 1: Filter tools based on active skill policy (planning-time)
@@ -548,6 +566,7 @@ export class AgentRuntime {
548
566
  toolCallId: tc.toolCallId,
549
567
  projectId: cacheCtx?.projectId,
550
568
  },
569
+ allowedRemoteToolNames,
551
570
  );
552
571
 
553
572
  toolCall.status = "completed";
@@ -662,6 +681,7 @@ export class AgentRuntime {
662
681
  // Request-scoped skill policy (not class-level mutable state)
663
682
  let activeSkillPolicy: string[] | undefined;
664
683
  let finalFinishReason: string | undefined;
684
+ const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
665
685
 
666
686
  for (let step = 0; step < maxSteps; step++) {
667
687
  throwIfAborted(abortSignal);
@@ -669,6 +689,7 @@ export class AgentRuntime {
669
689
 
670
690
  let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
671
691
  includeSkillTools: Boolean(this.config.skills),
692
+ allowedRemoteToolNames,
672
693
  });
673
694
 
674
695
  // Layer 1: Filter tools based on active skill policy (planning-time)
@@ -791,6 +812,7 @@ export class AgentRuntime {
791
812
  toolCallId: tc.id,
792
813
  ...toolContext,
793
814
  },
815
+ allowedRemoteToolNames,
794
816
  );
795
817
  throwIfAborted(abortSignal);
796
818
 
@@ -100,6 +100,7 @@ export async function executeConfiguredTool(
100
100
  input: Record<string, unknown>,
101
101
  toolsConfig: true | Record<string, ToolConfigEntry> | undefined,
102
102
  context?: ToolExecutionContext,
103
+ allowedRemoteToolNames?: string[],
103
104
  ): Promise<unknown> {
104
105
  const configuredTool = resolveConfiguredTool(toolsConfig, toolName);
105
106
  if (configuredTool) {
@@ -114,6 +115,9 @@ export async function executeConfiguredTool(
114
115
 
115
116
  // Fall back to remote execution for integration tools (e.g., github:list-repos)
116
117
  if (isRemoteIntegrationTool(toolName)) {
118
+ if (allowedRemoteToolNames && !allowedRemoteToolNames.includes(toolName)) {
119
+ throw new Error(`Tool "${toolName}" is not allowed for this run`);
120
+ }
117
121
  return await executeRemoteIntegrationTool(
118
122
  toolName,
119
123
  input,
@@ -152,7 +156,11 @@ function addToolDefinition(
152
156
  */
153
157
  export async function getAvailableTools(
154
158
  toolsConfig: true | Record<string, ToolConfigEntry> | undefined,
155
- options?: { includeSkillTools?: boolean; includeIntegrationTools?: boolean },
159
+ options?: {
160
+ includeSkillTools?: boolean;
161
+ includeIntegrationTools?: boolean;
162
+ allowedRemoteToolNames?: string[];
163
+ },
156
164
  ): Promise<ToolDefinition[]> {
157
165
  if (!toolsConfig) return [];
158
166
 
@@ -176,7 +184,9 @@ export async function getAvailableTools(
176
184
  const { getRemoteIntegrationToolDefinitions } = await import(
177
185
  "../../integrations/remote-tools.js"
178
186
  );
179
- const remoteDefs = await getRemoteIntegrationToolDefinitions();
187
+ const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) =>
188
+ !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name)
189
+ );
180
190
  for (const def of remoteDefs) {
181
191
  logToolDefinition(def.name, def);
182
192
  }
@@ -211,7 +221,9 @@ export async function getAvailableTools(
211
221
  const { getRemoteIntegrationToolDefinitions } = await import(
212
222
  "../../integrations/remote-tools.js"
213
223
  );
214
- const remoteDefs = await getRemoteIntegrationToolDefinitions();
224
+ const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) =>
225
+ !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name)
226
+ );
215
227
  for (const def of remoteDefs) {
216
228
  // Skip if already present (e.g., explicitly configured by name)
217
229
  if (!tools.some((t) => t.name === def.name)) {
@@ -116,8 +116,9 @@ export function injectHTMLContent(
116
116
  environment: options.environment,
117
117
  }),
118
118
  });
119
+ const nonceAttr = buildNonceAttribute(options.nonce);
119
120
  const hydrationScript =
120
- `<script id="veryfront-hydration-data" type="application/json">${hydrationData}</script>`;
121
+ `<script id="veryfront-hydration-data" type="application/json"${nonceAttr}>${hydrationData}</script>`;
121
122
  html = html.replace(/<\/body>/i, `${hydrationScript}</body>`);
122
123
  }
123
124
 
@@ -125,19 +126,22 @@ export function injectHTMLContent(
125
126
  const hasDevScriptsPlaceholder = /{{\s*devScripts\s*}}/i.test(html);
126
127
 
127
128
  if (hasDevScriptsPlaceholder) {
128
- html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts());
129
+ html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts(options.devPort, options.nonce));
129
130
  }
130
131
 
131
- html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles());
132
+ html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles(options.nonce));
132
133
 
133
134
  if (!hasDevScriptsPlaceholder && hasBodyClose) {
134
- html = html.replace(/<\/body>/i, `${getDevStyles()}${getDevScripts()}</body>`);
135
+ html = html.replace(
136
+ /<\/body>/i,
137
+ `${getDevStyles(options.nonce)}${getDevScripts(options.devPort, options.nonce)}</body>`,
138
+ );
135
139
  }
136
140
  } else {
137
141
  html = html.replace(/{{\s*devScripts\s*}}/gi, "");
138
142
  html = html.replace(/{{\s*devStyles\s*}}/gi, "");
139
143
 
140
- const prodScripts = getProdScripts(options.slug);
144
+ const prodScripts = getProdScripts(options.slug, options.nonce);
141
145
  const hasProdScriptsPlaceholder = /{{\s*prodScripts\s*}}/i.test(html);
142
146
 
143
147
  if (hasProdScriptsPlaceholder) {
@@ -0,0 +1,129 @@
1
+ import { escapeHtml } from "../utils/html-escape.js";
2
+
3
+ function findTagEnd(html: string, start: number): number {
4
+ let activeQuote: '"' | "'" | null = null;
5
+
6
+ for (let index = start + 1; index < html.length; index++) {
7
+ const char = html[index];
8
+
9
+ if (activeQuote) {
10
+ if (char === activeQuote) activeQuote = null;
11
+ continue;
12
+ }
13
+
14
+ if (char === '"' || char === "'") {
15
+ activeQuote = char;
16
+ continue;
17
+ }
18
+
19
+ if (char === ">") return index;
20
+ }
21
+
22
+ return -1;
23
+ }
24
+
25
+ function getOpeningTagName(tag: string): "script" | "style" | undefined {
26
+ const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
27
+ const tagName = match?.[1]?.toLowerCase();
28
+ if (tagName === "script" || tagName === "style") return tagName;
29
+ return undefined;
30
+ }
31
+
32
+ function isTagBoundary(char: string | undefined): boolean {
33
+ return char === undefined || /\s|\/|>/u.test(char);
34
+ }
35
+
36
+ function findRawTextClosingTagStart(
37
+ lowerHtml: string,
38
+ tagName: "script" | "style",
39
+ fromIndex: number,
40
+ ): number {
41
+ const needle = `</${tagName}`;
42
+ let searchIndex = fromIndex;
43
+
44
+ while (searchIndex < lowerHtml.length) {
45
+ const closingIndex = lowerHtml.indexOf(needle, searchIndex);
46
+ if (closingIndex === -1) return -1;
47
+
48
+ if (isTagBoundary(lowerHtml[closingIndex + needle.length])) {
49
+ return closingIndex;
50
+ }
51
+
52
+ searchIndex = closingIndex + needle.length;
53
+ }
54
+
55
+ return -1;
56
+ }
57
+
58
+ function injectNonceIntoOpeningTag(tag: string, escapedNonce: string): string {
59
+ if (/(?:\s|<)nonce\s*=/iu.test(tag)) return tag;
60
+
61
+ const closeIndex = tag.lastIndexOf(">");
62
+ if (closeIndex === -1) return tag;
63
+
64
+ const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
65
+ return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
66
+ }
67
+
68
+ export function addNonceToHtmlTags(html: string, nonce?: string): string {
69
+ if (!nonce) return html;
70
+
71
+ const escapedNonce = escapeHtml(nonce);
72
+ const lowerHtml = html.toLowerCase();
73
+ let result = "";
74
+ let index = 0;
75
+ let rawTextTag: "script" | "style" | null = null;
76
+
77
+ while (index < html.length) {
78
+ if (rawTextTag) {
79
+ const closingIndex = findRawTextClosingTagStart(lowerHtml, rawTextTag, index);
80
+ if (closingIndex === -1) {
81
+ result += html.slice(index);
82
+ break;
83
+ }
84
+
85
+ result += html.slice(index, closingIndex);
86
+ index = closingIndex;
87
+ rawTextTag = null;
88
+ continue;
89
+ }
90
+
91
+ if (html.startsWith("<!--", index)) {
92
+ const commentEnd = html.indexOf("-->", index + 4);
93
+ const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
94
+ result += html.slice(index, endIndex);
95
+ index = endIndex;
96
+ continue;
97
+ }
98
+
99
+ if (html[index] !== "<") {
100
+ result += html[index];
101
+ index++;
102
+ continue;
103
+ }
104
+
105
+ const tagEnd = findTagEnd(html, index);
106
+ if (tagEnd === -1) {
107
+ result += html.slice(index);
108
+ break;
109
+ }
110
+
111
+ const tag = html.slice(index, tagEnd + 1);
112
+ const tagName = getOpeningTagName(tag);
113
+
114
+ if (!tagName) {
115
+ result += tag;
116
+ index = tagEnd + 1;
117
+ continue;
118
+ }
119
+
120
+ result += injectNonceIntoOpeningTag(tag, escapedNonce);
121
+ index = tagEnd + 1;
122
+
123
+ if (!/\/\s*>$/u.test(tag)) {
124
+ rawTextTag = tagName;
125
+ }
126
+ }
127
+
128
+ return result;
129
+ }
@@ -20,6 +20,12 @@ import type { RuntimeRunAgentInput } from "./schema.js";
20
20
 
21
21
  const anyObjectSchema = z.record(z.string(), z.unknown());
22
22
 
23
+ type RuntimeFilteredAgent = Agent & {
24
+ config: Agent["config"] & {
25
+ __vfAllowedRemoteTools?: string[];
26
+ };
27
+ };
28
+
23
29
  export interface RuntimeAgentStreamExecutionDeps {
24
30
  sessionManager: AgentRunSessionManager;
25
31
  createRuntime?: (
@@ -203,6 +209,22 @@ function normalizeRuntimeMessages(messages: RuntimeRunAgentInput["messages"]): M
203
209
  }));
204
210
  }
205
211
 
212
+ function getAllowedRemoteToolNames(
213
+ forwardedProps: RuntimeRunAgentInput["forwardedProps"],
214
+ ): string[] | undefined {
215
+ const runtimeOverrides = isRecord(forwardedProps?.runtimeOverrides)
216
+ ? forwardedProps.runtimeOverrides
217
+ : null;
218
+ if (!runtimeOverrides || !Object.hasOwn(runtimeOverrides, "allowedTools")) {
219
+ return undefined;
220
+ }
221
+ const allowedTools = runtimeOverrides.allowedTools;
222
+ if (!Array.isArray(allowedTools)) {
223
+ return [];
224
+ }
225
+ return allowedTools.every((toolName) => typeof toolName === "string") ? allowedTools : [];
226
+ }
227
+
206
228
  export async function createRuntimeAgentStreamResponse(
207
229
  input: RuntimeRunAgentInput,
208
230
  agent: Agent,
@@ -214,10 +236,19 @@ export async function createRuntimeAgentStreamResponse(
214
236
  });
215
237
 
216
238
  const mergedTools = buildMergedTools(agent, input, deps.sessionManager);
217
- const runtime = deps.createRuntime?.(agent, mergedTools) ?? new AgentRuntime(agent.id, {
218
- ...agent.config,
219
- tools: mergedTools,
220
- });
239
+ const allowedRemoteToolNames = getAllowedRemoteToolNames(input.forwardedProps);
240
+ const runtimeAgent: RuntimeFilteredAgent = {
241
+ ...agent,
242
+ config: {
243
+ ...agent.config,
244
+ tools: mergedTools,
245
+ ...(allowedRemoteToolNames !== undefined
246
+ ? { __vfAllowedRemoteTools: allowedRemoteToolNames }
247
+ : {}),
248
+ },
249
+ };
250
+ const runtime = deps.createRuntime?.(runtimeAgent, mergedTools) ??
251
+ new AgentRuntime(runtimeAgent.id, runtimeAgent.config);
221
252
 
222
253
  let completedResponse: AgentResponse | null = null;
223
254
  const runtimeMessages = normalizeRuntimeMessages(input.messages);
@@ -19,7 +19,7 @@ import type {
19
19
  PageBundle,
20
20
  } from "../../types/index.js";
21
21
  import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
22
- import { escapeHtml } from "../../utils/html-escape.js";
22
+ import { addNonceToHtmlTags } from "../../html/nonce-injection.js";
23
23
  import type { RenderOptions } from "./types.js";
24
24
  import { injectElementSelectors } from "../../studio/element-selector-injector.js";
25
25
  import { computeSourceHash } from "../../studio/hash-utils.js";
@@ -41,108 +41,6 @@ import type { ResolvedContentContext } from "../../platform/adapters/fs/veryfron
41
41
  const logger = rendererLogger.component("html-generator");
42
42
  type ProjectCSSResult = Awaited<ReturnType<typeof getProjectCSS>> | null;
43
43
 
44
- function findTagEnd(html: string, start: number): number {
45
- let activeQuote: '"' | "'" | null = null;
46
-
47
- for (let index = start + 1; index < html.length; index++) {
48
- const char = html[index];
49
-
50
- if (activeQuote) {
51
- if (char === activeQuote) activeQuote = null;
52
- continue;
53
- }
54
-
55
- if (char === '"' || char === "'") {
56
- activeQuote = char;
57
- continue;
58
- }
59
-
60
- if (char === ">") return index;
61
- }
62
-
63
- return -1;
64
- }
65
-
66
- function getOpeningTagName(tag: string): "script" | "style" | undefined {
67
- const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
68
- const tagName = match?.[1]?.toLowerCase();
69
- if (tagName === "script" || tagName === "style") return tagName;
70
- return undefined;
71
- }
72
-
73
- function injectNonceIntoOpeningTag(tag: string, escapedNonce: string): string {
74
- if (/\bnonce\s*=/iu.test(tag)) return tag;
75
-
76
- const closeIndex = tag.lastIndexOf(">");
77
- if (closeIndex === -1) return tag;
78
-
79
- const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
80
- return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
81
- }
82
-
83
- function addNonceToRenderedTags(html: string, nonce?: string): string {
84
- if (!nonce) return html;
85
-
86
- const escapedNonce = escapeHtml(nonce);
87
- const lowerHtml = html.toLowerCase();
88
- let result = "";
89
- let index = 0;
90
- let rawTextTag: "script" | "style" | null = null;
91
-
92
- while (index < html.length) {
93
- if (rawTextTag) {
94
- const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
95
- if (closingIndex === -1) {
96
- result += html.slice(index);
97
- break;
98
- }
99
-
100
- result += html.slice(index, closingIndex);
101
- index = closingIndex;
102
- rawTextTag = null;
103
- continue;
104
- }
105
-
106
- if (html.startsWith("<!--", index)) {
107
- const commentEnd = html.indexOf("-->", index + 4);
108
- const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
109
- result += html.slice(index, endIndex);
110
- index = endIndex;
111
- continue;
112
- }
113
-
114
- if (html[index] !== "<") {
115
- result += html[index];
116
- index++;
117
- continue;
118
- }
119
-
120
- const tagEnd = findTagEnd(html, index);
121
- if (tagEnd === -1) {
122
- result += html.slice(index);
123
- break;
124
- }
125
-
126
- const tag = html.slice(index, tagEnd + 1);
127
- const tagName = getOpeningTagName(tag);
128
-
129
- if (!tagName) {
130
- result += tag;
131
- index = tagEnd + 1;
132
- continue;
133
- }
134
-
135
- result += injectNonceIntoOpeningTag(tag, escapedNonce);
136
- index = tagEnd + 1;
137
-
138
- if (!/\/\s*>$/u.test(tag)) {
139
- rawTextTag = tagName;
140
- }
141
- }
142
-
143
- return result;
144
- }
145
-
146
44
  export interface HTMLGeneratorConfig {
147
45
  projectDir: string;
148
46
  adapter: RuntimeAdapter;
@@ -182,7 +80,7 @@ export class HTMLGenerator {
182
80
  logger.debug("Injected element selectors for Studio");
183
81
  }
184
82
 
185
- return addNonceToRenderedTags(finalHtml, context.options?.nonce);
83
+ return addNonceToHtmlTags(finalHtml, context.options?.nonce);
186
84
  }
187
85
 
188
86
  async generateHTMLStream(
@@ -223,7 +121,7 @@ export class HTMLGenerator {
223
121
  );
224
122
 
225
123
  const encoder = new TextEncoder();
226
- const fullHtml = addNonceToRenderedTags(
124
+ const fullHtml = addNonceToHtmlTags(
227
125
  `${start}${reactContent}${end}`,
228
126
  context.options?.nonce,
229
127
  );
@@ -239,6 +239,7 @@ async function generateFullHtml(
239
239
  mode: options.mode,
240
240
  slug,
241
241
  devPort: options.config?.dev?.port ?? DEFAULT_DASHBOARD_PORT,
242
+ nonce: options.nonce,
242
243
  });
243
244
  }
244
245
 
@@ -21,6 +21,12 @@ import {
21
21
  } from "../../../utils/constants/index.js";
22
22
  import { withSpan } from "../../../observability/tracing/otlp-setup.js";
23
23
  import { StaticFileService } from "../../services/static/index.js";
24
+ import { addNonceToHtmlTags } from "../../../html/nonce-injection.js";
25
+ import { computeEtag } from "../utils/etag.js";
26
+
27
+ function isHtmlResponse(contentType: string): boolean {
28
+ return /\btext\/html\b/i.test(contentType);
29
+ }
24
30
 
25
31
  export class StaticHandler extends BaseHandler {
26
32
  metadata: HandlerMetadata = {
@@ -59,6 +65,8 @@ export class StaticHandler extends BaseHandler {
59
65
  const isHead = method === "HEAD";
60
66
  const isLocal = !!ctx.isLocalProject;
61
67
  const isPreviewMode = ctx.requestContext?.mode === "preview" && !isLocal;
68
+ const builder = this.createResponseBuilder(ctx)
69
+ .withCORS(req, ctx.securityConfig?.cors);
62
70
 
63
71
  const result = await this.staticService.resolveFile(pathname, {
64
72
  projectDir: ctx.projectDir,
@@ -70,8 +78,7 @@ export class StaticHandler extends BaseHandler {
70
78
  if (!result) {
71
79
  if (!this.staticService.isAssetRequest(pathname)) return null;
72
80
 
73
- return this.createResponseBuilder(ctx)
74
- .withCORS(req, ctx.securityConfig?.cors)
81
+ return builder
75
82
  .withSecurity(ctx.securityConfig ?? undefined, req)
76
83
  .withCache("no-cache")
77
84
  .withContentType(
@@ -81,19 +88,24 @@ export class StaticHandler extends BaseHandler {
81
88
  );
82
89
  }
83
90
 
84
- if (hasMatchingEtag(req, result.etag)) {
85
- return this.createResponseBuilder(ctx)
86
- .withCORS(req, ctx.securityConfig?.cors)
91
+ const responseData = isHtmlResponse(result.contentType)
92
+ ? new TextEncoder().encode(
93
+ addNonceToHtmlTags(new TextDecoder().decode(result.data), builder.nonce),
94
+ )
95
+ : result.data;
96
+ const etag = computeEtag(responseData);
97
+
98
+ if (hasMatchingEtag(req, etag)) {
99
+ return builder
87
100
  .withSecurity(ctx.securityConfig ?? undefined, req)
88
- .notModified(result.etag);
101
+ .notModified(etag);
89
102
  }
90
103
 
91
- const body: dntShim.BodyInit | null = isHead ? null : result.data.slice();
92
- const response = this.createResponseBuilder(ctx)
93
- .withCORS(req, ctx.securityConfig?.cors)
104
+ const body: dntShim.BodyInit | null = isHead ? null : responseData.slice();
105
+ const response = builder
94
106
  .withSecurity(ctx.securityConfig ?? undefined, req)
95
107
  .withCache(result.cacheStrategy)
96
- .withETag(result.etag)
108
+ .withETag(etag)
97
109
  .withContentType(result.contentType, body, HTTP_OK);
98
110
 
99
111
  this.logDebug(
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.131";
3
+ export const VERSION = "0.1.132";