veryfront 0.1.55 → 0.1.57

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 (61) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/agent/chat-handler.d.ts.map +1 -1
  3. package/esm/src/agent/chat-handler.js +9 -1
  4. package/esm/src/agent/memory/redis.d.ts +3 -0
  5. package/esm/src/agent/memory/redis.d.ts.map +1 -1
  6. package/esm/src/agent/memory/redis.js +3 -1
  7. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  8. package/esm/src/agent/runtime/index.js +2 -1
  9. package/esm/src/cache/backends/disk.d.ts.map +1 -1
  10. package/esm/src/cache/backends/disk.js +2 -1
  11. package/esm/src/middleware/builtin/security/rate-limit.d.ts +2 -0
  12. package/esm/src/middleware/builtin/security/rate-limit.d.ts.map +1 -1
  13. package/esm/src/middleware/builtin/security/rate-limit.js +18 -2
  14. package/esm/src/modules/react-loader/unified-loader.d.ts.map +1 -1
  15. package/esm/src/modules/react-loader/unified-loader.js +2 -1
  16. package/esm/src/oauth/token-store/memory.d.ts +3 -0
  17. package/esm/src/oauth/token-store/memory.d.ts.map +1 -1
  18. package/esm/src/oauth/token-store/memory.js +11 -4
  19. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
  20. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +11 -21
  21. package/esm/src/platform/compat/fs.js +1 -1
  22. package/esm/src/proxy/main.js +3 -0
  23. package/esm/src/routing/api/module-loader/security-config.d.ts.map +1 -1
  24. package/esm/src/routing/api/module-loader/security-config.js +4 -0
  25. package/esm/src/security/http/config.d.ts.map +1 -1
  26. package/esm/src/security/http/config.js +6 -1
  27. package/esm/src/server/handlers/dev/dashboard/api.d.ts.map +1 -1
  28. package/esm/src/server/handlers/dev/dashboard/api.js +2 -0
  29. package/esm/src/server/handlers/request/openapi.handler.js +1 -1
  30. package/esm/src/server/services/static/static-file.service.d.ts +1 -0
  31. package/esm/src/server/services/static/static-file.service.d.ts.map +1 -1
  32. package/esm/src/server/services/static/static-file.service.js +11 -0
  33. package/esm/src/skill/executor.js +1 -1
  34. package/esm/src/tool/factory.d.ts.map +1 -1
  35. package/esm/src/tool/factory.js +10 -0
  36. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts.map +1 -1
  37. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.js +15 -0
  38. package/esm/src/workflow/claude-code/tool.d.ts +0 -8
  39. package/esm/src/workflow/claude-code/tool.d.ts.map +1 -1
  40. package/esm/src/workflow/claude-code/tool.js +8 -10
  41. package/package.json +1 -1
  42. package/src/deno.js +1 -1
  43. package/src/src/agent/chat-handler.ts +11 -1
  44. package/src/src/agent/memory/redis.ts +5 -1
  45. package/src/src/agent/runtime/index.ts +2 -1
  46. package/src/src/cache/backends/disk.ts +2 -1
  47. package/src/src/middleware/builtin/security/rate-limit.ts +18 -2
  48. package/src/src/modules/react-loader/unified-loader.ts +2 -1
  49. package/src/src/oauth/token-store/memory.ts +13 -4
  50. package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +11 -23
  51. package/src/src/platform/compat/fs.ts +1 -1
  52. package/src/src/proxy/main.ts +3 -0
  53. package/src/src/routing/api/module-loader/security-config.ts +6 -0
  54. package/src/src/security/http/config.ts +9 -1
  55. package/src/src/server/handlers/dev/dashboard/api.ts +2 -0
  56. package/src/src/server/handlers/request/openapi.handler.ts +1 -1
  57. package/src/src/server/services/static/static-file.service.ts +11 -0
  58. package/src/src/skill/executor.ts +1 -1
  59. package/src/src/tool/factory.ts +10 -0
  60. package/src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts +22 -0
  61. package/src/src/workflow/claude-code/tool.ts +8 -11
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1 +1 @@
1
- {"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../../src/src/agent/chat-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8K1C,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,8BAA8B,KAEnC,IAAI,GACJ,OAAO,CAAC,QAAQ,GAChB,6BAA6B,GAC7B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,6BAA6B,CAAC,CAAC;AAiCrE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACD,OAAO,EAAE,OAAO,CAAC,OAAO,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAsCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,IAED,cAAc,OAAO,KAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA+E7E"}
1
+ {"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../../src/src/agent/chat-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8K1C,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,8BAA8B,KAEnC,IAAI,GACJ,OAAO,CAAC,QAAQ,GAChB,6BAA6B,GAC7B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,6BAA6B,CAAC,CAAC;AAiCrE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACD,OAAO,EAAE,OAAO,CAAC,OAAO,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAgDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,IAED,cAAc,OAAO,KAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA+E7E"}
@@ -172,6 +172,14 @@ function isRequest(obj) {
172
172
  "method" in obj &&
173
173
  typeof obj.method === "string");
174
174
  }
175
+ function extractUserId(request) {
176
+ const userId = request.headers.get("x-user-id");
177
+ if (userId)
178
+ return userId;
179
+ agentLogger.warn("No user identity found in request. Using anonymous fallback. " +
180
+ "Set x-user-id header or provide a context function for proper user isolation.");
181
+ return "anonymous";
182
+ }
175
183
  function extractRequest(requestOrCtx) {
176
184
  if (isRequest(requestOrCtx))
177
185
  return requestOrCtx;
@@ -219,7 +227,7 @@ export function createChatHandler(agentId, options) {
219
227
  const { messages: rawMessages, model: requestModel } = chatRequestSchema.parse(body);
220
228
  const context = typeof options?.context === "function"
221
229
  ? await options.context(request)
222
- : options?.context ?? { userId: "current-user" };
230
+ : options?.context ?? { userId: extractUserId(request) };
223
231
  const baseMessages = transformUIMessages(rawMessages);
224
232
  const beforeStreamResult = await options?.beforeStream?.({
225
233
  request,
@@ -25,12 +25,15 @@ export interface RedisMemoryConfig extends MemoryConfigBase {
25
25
  client: RedisClient;
26
26
  /** Key prefix for namespacing */
27
27
  keyPrefix?: string;
28
+ /** User ID for per-user memory isolation */
29
+ userId?: string;
28
30
  /** TTL in seconds (default: 24 hours) */
29
31
  ttl?: number;
30
32
  }
31
33
  export declare class RedisMemory<M extends MinimalMessage = MinimalMessage> implements Memory<M> {
32
34
  private client;
33
35
  private agentId;
36
+ private userId;
34
37
  private keyPrefix;
35
38
  private ttl;
36
39
  private config;
@@ -1 +1 @@
1
- {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/redis.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAG/B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,qBAAa,WAAW,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IACtF,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAoB;gBAEtB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB;IAQtD,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,aAAa;IAUrB,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B9B,WAAW,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAehC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,OAAO,CAAC,gBAAgB;CAazB;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACzE,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,WAAW,CAAC,CAAC,CAAC,CAEhB"}
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/redis.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAG/B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,qBAAa,WAAW,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IACtF,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAoB;gBAEtB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB;IAStD,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,aAAa;IAUrB,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B9B,WAAW,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAehC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,OAAO,CAAC,gBAAgB;CAazB;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACzE,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,WAAW,CAAC,CAAC,CAAC,CAEhB"}
@@ -11,18 +11,20 @@ const DEFAULT_KEY_PREFIX = "veryfront:agent:memory:";
11
11
  export class RedisMemory {
12
12
  client;
13
13
  agentId;
14
+ userId;
14
15
  keyPrefix;
15
16
  ttl;
16
17
  config;
17
18
  constructor(agentId, config) {
18
19
  this.client = config.client;
19
20
  this.agentId = agentId;
21
+ this.userId = config.userId ?? "anonymous";
20
22
  this.keyPrefix = config.keyPrefix ?? DEFAULT_KEY_PREFIX;
21
23
  this.ttl = config.ttl ?? DEFAULT_TTL;
22
24
  this.config = config;
23
25
  }
24
26
  getKey() {
25
- return `${this.keyPrefix}${this.agentId}`;
27
+ return `${this.keyPrefix}${this.agentId}:${this.userId}`;
26
28
  }
27
29
  parseMessages(data) {
28
30
  if (!data)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAe/D,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAqBxB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CA6BxE;AAED,gEAAgE;AAChE,KAAK,iBAAiB,GAClB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,EACvC,kBAAkB,EAAE,OAAO,GAC1B,iBAAiB,CAiBnB;AAkCD,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS3C;;OAEG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IAgCzB;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,EACD,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IA+EtC;;OAEG;YACW,gBAAgB;IAyN9B;;;;OAIG;YACW,yBAAyB;IAyNvC;;OAEG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IAOjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC;IAI5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAIF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAe/D,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAqBxB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CA6BxE;AAED,gEAAgE;AAChE,KAAK,iBAAiB,GAClB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,EACvC,kBAAkB,EAAE,OAAO,GAC1B,iBAAiB,CAiBnB;AAkCD,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS3C;;OAEG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IAgCzB;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,EACD,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAgFtC;;OAEG;YACW,gBAAgB;IAyN9B;;;;OAIG;YACW,yBAAyB;IAyNvC;;OAEG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IAOjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC;IAI5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAIF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
@@ -211,9 +211,10 @@ export class AgentRuntime {
211
211
  }
212
212
  catch (error) {
213
213
  this.status = "error";
214
+ logger.error("Agent stream error", { error });
214
215
  sendSSE(controller, encoder, {
215
216
  type: "error",
216
- error: error instanceof Error ? error.message : String(error),
217
+ error: "An internal error occurred",
217
218
  });
218
219
  controller.close();
219
220
  }
@@ -1 +1 @@
1
- {"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../../../src/src/cache/backends/disk.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0BhD,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,UAAU,CAA6B;gBAEnC,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAKhD,OAAO,CAAC,QAAQ;YAIF,SAAS;IAKjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwBxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB/B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAwCrD"}
1
+ {"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../../../src/src/cache/backends/disk.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0BhD,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,UAAU,CAA6B;gBAEnC,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAKhD,OAAO,CAAC,QAAQ;YAIF,SAAS;IAKjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwBxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB/B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAwCrD"}
@@ -1,3 +1,4 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
1
2
  import { join } from "../../platform/compat/path/index.js";
2
3
  import { getCacheBaseDir } from "../../utils/cache-dir.js";
3
4
  import { logger } from "../../utils/index.js";
@@ -65,7 +66,7 @@ export class DiskCacheBackend {
65
66
  expiresAt: ttlSeconds != null ? Date.now() + ttlSeconds * 1000 : undefined,
66
67
  };
67
68
  const filePath = this.filePath(key);
68
- const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
69
+ const tmpPath = `${filePath}.tmp.${Date.now()}.${dntShim.crypto.randomUUID().slice(0, 8)}`;
69
70
  const content = JSON.stringify(envelope);
70
71
  const { writeFile, rename, unlink } = await fsPromises;
71
72
  try {
@@ -16,4 +16,6 @@ export interface RateLimitOptions {
16
16
  keyGenerator?: (req: dntShim.Request) => string;
17
17
  }
18
18
  export declare function rateLimit(optionsOrMaxRequests?: number | RateLimitOptions, windowMsArg?: number): Middleware;
19
+ /** Pre-configured rate limiter for authentication endpoints (5 req/15min). */
20
+ export declare function authRateLimit(store?: RateLimitStore): Middleware;
19
21
  //# sourceMappingURL=rate-limit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../../../src/src/middleware/builtin/security/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjE,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,eAAe,CAAC,CAAyC;gBAErD,QAAQ,EAAE,MAAM;IAgB5B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcjE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjC,OAAO,IAAI,IAAI;CAIhB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC;CACjD;AAED,wBAAgB,SAAS,CACvB,oBAAoB,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAChD,WAAW,CAAC,EAAE,MAAM,GACnB,UAAU,CA2BZ"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../../../src/src/middleware/builtin/security/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjE,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,eAAe,CAAC,CAAyC;gBAErD,QAAQ,EAAE,MAAM;IAgB5B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcjE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjC,OAAO,IAAI,IAAI;CAIhB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC;CACjD;AAED,wBAAgB,SAAS,CACvB,oBAAoB,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAChD,WAAW,CAAC,EAAE,MAAM,GACnB,UAAU,CAkCZ;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,UAAU,CAMhE"}
@@ -49,8 +49,16 @@ export function rateLimit(optionsOrMaxRequests, windowMsArg) {
49
49
  const maxRequests = options.maxRequests ?? DEFAULT_RATE_LIMIT_REQUESTS;
50
50
  const windowMs = options.windowMs ?? DEFAULT_RATE_LIMIT_WINDOW_MS;
51
51
  const store = options.store ?? new MemoryRateLimitStore(windowMs);
52
- const keyGenerator = options.keyGenerator ??
53
- ((req) => req.headers.get("x-forwarded-for") || "anonymous");
52
+ const keyGenerator = options.keyGenerator ?? ((req) => {
53
+ const forwarded = req.headers.get("x-forwarded-for");
54
+ if (forwarded) {
55
+ const parts = forwarded.split(",").map((s) => s.trim()).filter(Boolean);
56
+ // Use rightmost IP — added by nearest trusted proxy, not spoofable by clients
57
+ if (parts.length > 0)
58
+ return parts[parts.length - 1];
59
+ }
60
+ return "anonymous";
61
+ });
54
62
  return async (ctx, next) => {
55
63
  const req = getRequest(ctx);
56
64
  const key = keyGenerator(req);
@@ -64,3 +72,11 @@ export function rateLimit(optionsOrMaxRequests, windowMsArg) {
64
72
  });
65
73
  };
66
74
  }
75
+ /** Pre-configured rate limiter for authentication endpoints (5 req/15min). */
76
+ export function authRateLimit(store) {
77
+ return rateLimit({
78
+ maxRequests: 5,
79
+ windowMs: 15 * MS_PER_MINUTE,
80
+ store,
81
+ });
82
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"unified-loader.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/react-loader/unified-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAQtF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,YAAY,CAAC,CAsCvB"}
1
+ {"version":3,"file":"unified-loader.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/react-loader/unified-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAQtF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,YAAY,CAAC,CAsCvB"}
@@ -1,3 +1,4 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
1
2
  import { join } from "../../platform/compat/path/index.js";
2
3
  import { transformToESM } from "../../transforms/esm/index.js";
3
4
  import { rendererLogger as logger } from "../../utils/index.js";
@@ -37,7 +38,7 @@ async function transformAllComponents(components, projectDir, adapter, transform
37
38
  }
38
39
  async function createTempDir(projectId, adapter) {
39
40
  const baseTmp = await getProjectTmpDir(projectId);
40
- const uniqueTmp = `unified-${Date.now()}-${Math.random().toString(16).slice(2)}`;
41
+ const uniqueTmp = `unified-${Date.now()}-${dntShim.crypto.randomUUID().slice(0, 12)}`;
41
42
  const tmpDir = join(baseTmp, uniqueTmp);
42
43
  await adapter.fs.mkdir(tmpDir, { recursive: true });
43
44
  return tmpDir;
@@ -2,6 +2,9 @@ import type { OAuthState, OAuthTokens, TokenStore } from "../types.js";
2
2
  export declare class MemoryTokenStore implements TokenStore {
3
3
  private tokens;
4
4
  private states;
5
+ private projectId;
6
+ constructor(projectId?: string);
7
+ private scopedKey;
5
8
  getTokens(serviceId: string): Promise<OAuthTokens | null>;
6
9
  setTokens(serviceId: string, tokens: OAuthTokens): Promise<void>;
7
10
  clearTokens(serviceId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKvE,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAiC;IAEzC,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIzD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAYnD,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,OAAO,CAAC,oBAAoB;IAS5B,oBAAoB,IAAI,MAAM,EAAE;IAIhC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAQvC,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKvE,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,SAAY;IAIjC,OAAO,CAAC,SAAS;IAIX,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIzD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAYnD,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,OAAO,CAAC,oBAAoB;IAS5B,oBAAoB,IAAI,MAAM,EAAE;IAIhC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAQvC,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
@@ -3,14 +3,21 @@ const STATE_EXPIRATION_MS = 10 * 60 * 1_000;
3
3
  export class MemoryTokenStore {
4
4
  tokens = new Map();
5
5
  states = new Map();
6
+ projectId;
7
+ constructor(projectId = "default") {
8
+ this.projectId = projectId;
9
+ }
10
+ scopedKey(serviceId) {
11
+ return `${this.projectId}:${serviceId}`;
12
+ }
6
13
  async getTokens(serviceId) {
7
- return this.tokens.get(serviceId) ?? null;
14
+ return this.tokens.get(this.scopedKey(serviceId)) ?? null;
8
15
  }
9
16
  async setTokens(serviceId, tokens) {
10
- this.tokens.set(serviceId, tokens);
17
+ this.tokens.set(this.scopedKey(serviceId), tokens);
11
18
  }
12
19
  async clearTokens(serviceId) {
13
- this.tokens.delete(serviceId);
20
+ this.tokens.delete(this.scopedKey(serviceId));
14
21
  }
15
22
  async getState(state) {
16
23
  const oauthState = this.states.get(state);
@@ -41,7 +48,7 @@ export class MemoryTokenStore {
41
48
  return [...this.tokens.keys()];
42
49
  }
43
50
  isConnected(serviceId) {
44
- const tokens = this.tokens.get(serviceId);
51
+ const tokens = this.tokens.get(this.scopedKey(serviceId));
45
52
  if (!tokens)
46
53
  return false;
47
54
  const isExpired = tokens.expiresAt != null && Date.now() > tokens.expiresAt;
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAwB/F,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAE7C,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,aAAa,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAqBf,OAAO,CAAC,QAAQ,CAAC,IAAI;IApBjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,0BAA0B,CAAsD;IACxF,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,0BAA0B,CAAK;IACvC,OAAO,CAAC,iCAAiC,CAAqB;IAC9D,OAAO,CAAC,WAAW,CAIjB;gBAE2B,IAAI,EAAE,aAAa;IAEhD,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,8BAA8B;IAOtC,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,2BAA2B;IAUnC,cAAc,IAAI;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA2HhC,OAAO,CAAC,iBAAiB;IAMzB,OAAO,IAAI,IAAI;IA8Bf,OAAO,CAAC,iBAAiB;IAyJzB,OAAO,CAAC,8BAA8B;IA0GtC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,6BAA6B;YAiBvB,4BAA4B;YAwI5B,mBAAmB;IA2IjC,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;CAyBpB"}
1
+ {"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAwB/F,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAE7C,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,aAAa,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAqBf,OAAO,CAAC,QAAQ,CAAC,IAAI;IApBjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,0BAA0B,CAAsD;IACxF,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,0BAA0B,CAAK;IACvC,OAAO,CAAC,iCAAiC,CAAqB;IAC9D,OAAO,CAAC,WAAW,CAIjB;gBAE2B,IAAI,EAAE,aAAa;IAEhD,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,8BAA8B;IAOtC,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,2BAA2B;IAUnC,cAAc,IAAI;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA+GhC,OAAO,CAAC,iBAAiB;IAMzB,OAAO,IAAI,IAAI;IA8Bf,OAAO,CAAC,iBAAiB;IAyJzB,OAAO,CAAC,8BAA8B;IA0GtC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,6BAA6B;YAiBvB,4BAA4B;YAwI5B,mBAAmB;IA2IjC,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;CAyBpB"}
@@ -81,33 +81,23 @@ export class WebSocketManager {
81
81
  });
82
82
  this.wsConsecutiveFailures = 0;
83
83
  }
84
- let wsUrl = this.deps.apiBaseUrl
84
+ const wsUrl = this.deps.apiBaseUrl
85
85
  .replace(/^http:/, "ws:")
86
86
  .replace(/^https:/, "wss:")
87
87
  .replace(/\/api$/, "");
88
- // Enforce TLS for non-localhost connections to protect the auth token
89
- if (wsUrl.startsWith("ws://")) {
90
- try {
91
- const host = new URL(wsUrl.replace(/^ws:/, "http:")).hostname;
92
- const isLocal = host === "localhost" || host === "127.0.0.1" ||
93
- host === "::1" || host === "[::1]";
94
- if (!isLocal) {
95
- wsUrl = wsUrl.replace(/^ws:/, "wss:");
96
- logger.warn("Upgraded WebSocket connection to wss:// for non-localhost host", this.getConnectionLogContext({ host }));
97
- }
98
- }
99
- catch {
100
- // If URL parsing fails, upgrade to be safe
101
- wsUrl = wsUrl.replace(/^ws:/, "wss:");
102
- }
103
- }
104
- const url = `${wsUrl}/ws/${projectId}/events?token=${this.deps.apiToken}`;
88
+ // The WebSocket protocol (ws vs wss) is derived from the configured
89
+ // apiBaseUrl (http→ws, https→wss). No forced upgrade is needed because
90
+ // the auth token is sent via a subprotocol header, not in the URL.
91
+ const url = `${wsUrl}/ws/${projectId}/events`;
105
92
  logger.debug("Connecting to WebSocket", this.getConnectionLogContext({
106
- url: url.replace(this.deps.apiToken, "***"),
93
+ url,
107
94
  consecutiveFailures: this.wsConsecutiveFailures,
108
95
  }));
109
96
  try {
110
- this.ws = new WebSocket(url);
97
+ // Send the API token via a WebSocket subprotocol header instead of
98
+ // a query-string parameter. Query strings can leak into server
99
+ // access logs, proxy logs, and the browser's Referer header.
100
+ this.ws = new WebSocket(url, [`bearer-${this.deps.apiToken}`]);
111
101
  this.wsConnectionId = dntShim.crypto.randomUUID().slice(0, 8);
112
102
  this.wsErrorLogged = false;
113
103
  this.ws.onopen = () => {
@@ -146,7 +136,7 @@ export class WebSocketManager {
146
136
  this.wsErrorLogged = true;
147
137
  logger.warn("WebSocket error", this.getConnectionLogContext({
148
138
  type: event.type,
149
- url: event.target?.url?.replace(/token=[^&]+/, "token=***"),
139
+ url: event.target?.url,
150
140
  readyState: event.target?.readyState,
151
141
  consecutiveFailures: this.wsConsecutiveFailures,
152
142
  }));
@@ -98,7 +98,7 @@ class NodeFileSystem {
98
98
  }
99
99
  async makeTempDir(options) {
100
100
  await this.ensureInitialized();
101
- const tempDir = this.getPath().join(this.getOs().tmpdir(), `${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`);
101
+ const tempDir = this.getPath().join(this.getOs().tmpdir(), `${options?.prefix ?? "tmp-"}${dntShim.crypto.randomUUID().slice(0, 8)}`);
102
102
  await this.getFs().mkdir(tempDir, { recursive: true });
103
103
  return tempDir;
104
104
  }
@@ -480,6 +480,9 @@ function router(req) {
480
480
  }
481
481
  switch (url.pathname) {
482
482
  case "/_proxy/stats":
483
+ if (Object.keys(proxyHandler.localProjects).length === 0) {
484
+ return Promise.resolve(new dntShim.Response("Forbidden", { status: 403 }));
485
+ }
483
486
  return handleStats();
484
487
  case "/_proxy/health":
485
488
  return Promise.resolve(dntShim.Response.json({ service: "veryfront-proxy", status: "ok" }));
@@ -1 +1 @@
1
- {"version":3,"file":"security-config.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/security-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAcnB"}
1
+ {"version":3,"file":"security-config.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/security-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBnB"}
@@ -5,6 +5,10 @@ export async function loadSecurityConfig(projectDir, adapter) {
5
5
  const cfg = await getConfig(projectDir, adapter);
6
6
  const remote = cfg.security?.remoteHosts;
7
7
  if (Array.isArray(remote)) {
8
+ if (remote.length === 0) {
9
+ logger.warn("security.remoteHosts is set to an empty array — all remote requests will be blocked. " +
10
+ "If this is intentional, you can ignore this warning.");
11
+ }
8
12
  return remote;
9
13
  }
10
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/src/security/http/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAO7D,qBAAa,oBAAoB;IAO7B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,cAAc,CAAC;IARzB,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAA8B;gBAGvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,cAAc,CAAC,EAAE,eAAe,YAAA;IAGpC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAQrB,IAAI;IAWlB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,kBAAkB;IAgB1B,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAI1C,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,aAAa,IAAI,cAAc,CAAC,MAAM,CAAC;IAIvC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,MAAwB,GAAG,MAAM;IAIjE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IASnE,KAAK,IAAI,IAAI;CAMd"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/src/security/http/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAO7D,qBAAa,oBAAoB;IAO7B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,cAAc,CAAC;IARzB,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAA8B;gBAGvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,cAAc,CAAC,EAAE,eAAe,YAAA;IAGpC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAQrB,IAAI;IAWlB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,kBAAkB;IAgB1B,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAI1C,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,aAAa,IAAI,cAAc,CAAC,MAAM,CAAC;IAIvC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,MAAwB,GAAG,MAAM;IAIjE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IASnE,KAAK,IAAI,IAAI;CAMd"}
@@ -38,7 +38,12 @@ export class SecurityConfigLoader {
38
38
  const security = cfg?.security ? { ...cfg.security } : {};
39
39
  if (security.headers)
40
40
  security.headers = { ...security.headers };
41
- security.cors ??= true;
41
+ security.cors ??= false;
42
+ if (!cfg?.security?.cors && !cfg?.security?.csrf) {
43
+ logger.warn("Neither CORS nor CSRF protection is configured. " +
44
+ "CORS is disabled by default (same-origin only). " +
45
+ "Consider explicitly configuring security.cors and security.csrf.");
46
+ }
42
47
  this.securityConfig = security;
43
48
  this.cspUserHeader = this.parseCspUserHeader(security.csp);
44
49
  this.isLoaded = true;
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/dashboard/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AA2BxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA2CrD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CA8D5D"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/dashboard/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AA2BxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA2CrD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAgE5D"}
@@ -56,6 +56,8 @@ function errorResponse(message, status = 500) {
56
56
  return jsonResponse({ error: message }, status);
57
57
  }
58
58
  export function handleDashboardAPI(req, ctx) {
59
+ if (!ctx.isLocalProject)
60
+ return errorResponse("Unauthorized", 401);
59
61
  const { pathname } = new URL(req.url);
60
62
  if (req.method === "GET") {
61
63
  switch (pathname) {
@@ -40,7 +40,7 @@ export class OpenAPIHandler extends BaseHandler {
40
40
  const isDev = !!ctx.isLocalProject;
41
41
  const response = this.createResponseBuilder(ctx)
42
42
  .withCache(isDev ? "no-cache" : { maxAge: SPEC_CACHE_MAX_AGE_SECONDS, public: true })
43
- .withCORS(req, { origin: "*" })
43
+ .withCORS(req, ctx.securityConfig?.cors)
44
44
  .withContentType(isYaml ? "text/yaml; charset=utf-8" : "application/json; charset=utf-8", content, HTTP_OK);
45
45
  return this.respond(response);
46
46
  }
@@ -75,6 +75,7 @@ export declare class StaticFileService {
75
75
  private loadManifestIndex;
76
76
  private extractManifestAssets;
77
77
  isAssetRequest(pathname: string): boolean;
78
+ private isDeniedDotfile;
78
79
  static clearCache(): void;
79
80
  }
80
81
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"static-file.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/static/static-file.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAY3E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,aAAa,EAAE,aAAa,CAAC;IAC7B,gDAAgD;IAChD,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,cAAc,CAAC;IACxB,gDAAgD;IAChD,aAAa,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,UAAU,aAAa;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAYD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC;CAC9D;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAE7E;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,aAAa,CAAoC;IAChE,OAAO,CAAC,MAAM,CAAC,eAAe,CAAoD;IAElF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAuB;gBAEnC,MAAM,CAAC,EAAE,oBAAoB;IAIzC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAWf,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAarB,eAAe;YA2Bf,mBAAmB;IA2BjC,OAAO,CAAC,sBAAsB;YAkBhB,oBAAoB;YAYpB,iBAAiB;IA+C/B,OAAO,CAAC,qBAAqB;IAyC7B,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAMzC,MAAM,CAAC,UAAU,IAAI,IAAI;CAI1B"}
1
+ {"version":3,"file":"static-file.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/static/static-file.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAY3E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,aAAa,EAAE,aAAa,CAAC;IAC7B,gDAAgD;IAChD,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,cAAc,CAAC;IACxB,gDAAgD;IAChD,aAAa,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,UAAU,aAAa;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAYD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC;CAC9D;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAE7E;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,aAAa,CAAoC;IAChE,OAAO,CAAC,MAAM,CAAC,eAAe,CAAoD;IAElF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAuB;gBAEnC,MAAM,CAAC,EAAE,oBAAoB;IAIzC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAWf,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAarB,eAAe;YA2Bf,mBAAmB;IA2BjC,OAAO,CAAC,sBAAsB;YAkBhB,oBAAoB;YAYpB,iBAAiB;IA+C/B,OAAO,CAAC,qBAAqB;IAyC7B,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAOzC,OAAO,CAAC,eAAe;IAUvB,MAAM,CAAC,UAAU,IAAI,IAAI;CAI1B"}
@@ -196,8 +196,19 @@ export class StaticFileService {
196
196
  return false;
197
197
  if (pathname.endsWith(".md"))
198
198
  return false;
199
+ if (this.isDeniedDotfile(pathname))
200
+ return false;
199
201
  return pathname.includes(".") || pathname.startsWith("/_veryfront/");
200
202
  }
203
+ isDeniedDotfile(pathname) {
204
+ const segments = pathname.split("/");
205
+ for (const segment of segments) {
206
+ if (segment.startsWith(".") && segment !== ".well-known") {
207
+ return true;
208
+ }
209
+ }
210
+ return false;
211
+ }
201
212
  static clearCache() {
202
213
  StaticFileService.manifestCache.clear();
203
214
  StaticFileService.manifestLoading.clear();
@@ -64,7 +64,7 @@ function formatEnvAssignments(env) {
64
64
  }
65
65
  function createSandboxScriptPath(scriptPath) {
66
66
  const ext = extname(scriptPath) || ".sh";
67
- const suffix = Math.random().toString(36).slice(2, 10);
67
+ const suffix = dntShim.crypto.randomUUID().slice(0, 8);
68
68
  return `/tmp/veryfront-skill-script-${Date.now()}-${suffix}${ext}`;
69
69
  }
70
70
  function getSandboxAuthOverride() {
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/tool/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA2HzE,wBAAgB,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACtD,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCvB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAiB7E"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/tool/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA2HzE,wBAAgB,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACtD,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCvB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CA2B7E"}
@@ -105,6 +105,16 @@ export function dynamicTool(config) {
105
105
  inputSchema: config.inputSchema,
106
106
  inputSchemaJson,
107
107
  execute: async (input, context) => {
108
+ if (config.inputSchema &&
109
+ typeof config.inputSchema.parse === "function") {
110
+ config.inputSchema.parse(input);
111
+ }
112
+ else if (input === undefined) {
113
+ input = {};
114
+ }
115
+ else if (input === null || typeof input !== "object") {
116
+ throw new Error("dynamicTool: input must be a non-null object");
117
+ }
108
118
  const result = await config.execute(input, context);
109
119
  return config.toModelOutput ? config.toModelOutput(result) : result;
110
120
  },
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAarE,OAAO,EAOL,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,gBAAgB,EACrB,oBAAoB,UAAQ,EAC5B,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,CAAC,CAsPjB;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4CxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAcrE,OAAO,EAOL,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAIxB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,gBAAgB,EACrB,oBAAoB,UAAQ,EAC5B,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,CAAC,CAyQjB;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4CxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
@@ -5,6 +5,7 @@
5
5
  * resolves all imports (#veryfront/, relative, React).
6
6
  */
7
7
  import { join } from "../../../../platform/compat/path/index.js";
8
+ import denoConfig from "../../../../../deno.js";
8
9
  import { rendererLogger as logger } from "../../../../utils/index.js";
9
10
  import { IMPORT_RESOLUTION_ERROR } from "../../../../errors/index.js";
10
11
  import { replaceSpecifiers } from "../../../esm/lexer.js";
@@ -17,6 +18,7 @@ import { buildReactUrl, getReactImportMap } from "../../../import-rewriter/url-b
17
18
  import { findRelativeImports } from "./import-finder.js";
18
19
  import { resolveRelativeFrameworkImport, resolveVeryfrontSourcePath } from "./path-resolver.js";
19
20
  import { EMBEDDED_SRC_DIR, FRAMEWORK_ROOT, frameworkFileCache, frameworkWriteFlight, LOG_PREFIX, MAX_RELATIVE_IMPORT_DEPTH, transformingFiles, veryfrontTransformCache, } from "./constants.js";
21
+ const DENO_CONFIG_STUB_CODE = `export default ${JSON.stringify(denoConfig)};`;
20
22
  /**
21
23
  * Check if a transformed code string is a cycle placeholder.
22
24
  * Cycle placeholders are returned when transformFrameworkCode detects a cycle
@@ -236,7 +238,20 @@ export async function transformFrameworkCode(content, sourcePath, ctx, throwOnMi
236
238
  }
237
239
  // Rewrite imports to resolved paths
238
240
  const reactImportMap = getReactImportMap(ctx.reactVersion);
241
+ // Handle Deno import-map aliases (e.g. #deno-config) that only exist in
242
+ // the Deno runtime and cannot be resolved by esm.sh or the HTTP cache.
243
+ // We create a cached JS stub module so the transformed code can import it
244
+ // without losing access to imports/exports metadata from deno.json.
245
+ let denoConfigStubUrl = null;
246
+ if (transformed.includes('"#deno-config"') || transformed.includes("'#deno-config'")) {
247
+ const stubPath = await cacheTransformedCode(DENO_CONFIG_STUB_CODE, "#deno-config-stub", ctx.fs);
248
+ denoConfigStubUrl = `file://${stubPath}`;
249
+ }
239
250
  transformed = await replaceSpecifiers(transformed, (specifier) => {
251
+ // Handle Deno import-map aliases
252
+ if (specifier === "#deno-config") {
253
+ return denoConfigStubUrl;
254
+ }
240
255
  // Handle #veryfront/ imports
241
256
  if (specifier.startsWith("#veryfront/")) {
242
257
  return veryfrontReplacements.get(specifier) ?? null;
@@ -20,21 +20,17 @@ declare const claudeCodeInputSchema: z.ZodObject<{
20
20
  files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
21
21
  /** Additional context */
22
22
  context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
23
- /** Custom system prompt */
24
- system: z.ZodOptional<z.ZodString>;
25
23
  }, "strip", z.ZodTypeAny, {
26
24
  mode: "code" | "custom" | "analysis";
27
25
  task: string;
28
26
  maxTurns: number;
29
27
  context?: Record<string, unknown> | undefined;
30
28
  files?: string[] | undefined;
31
- system?: string | undefined;
32
29
  }, {
33
30
  task: string;
34
31
  context?: Record<string, unknown> | undefined;
35
32
  files?: string[] | undefined;
36
33
  mode?: "code" | "custom" | "analysis" | undefined;
37
- system?: string | undefined;
38
34
  maxTurns?: number | undefined;
39
35
  }>;
40
36
  type ClaudeCodeInput = z.infer<typeof claudeCodeInputSchema>;
@@ -81,7 +77,6 @@ export declare const codeReviewTool: Tool<{
81
77
  maxTurns: number;
82
78
  context?: Record<string, unknown> | undefined;
83
79
  files?: string[] | undefined;
84
- system?: string | undefined;
85
80
  }, ClaudeCodeResult>;
86
81
  /** Bug fix tool (code mode) */
87
82
  export declare const bugFixTool: Tool<{
@@ -90,7 +85,6 @@ export declare const bugFixTool: Tool<{
90
85
  maxTurns: number;
91
86
  context?: Record<string, unknown> | undefined;
92
87
  files?: string[] | undefined;
93
- system?: string | undefined;
94
88
  }, ClaudeCodeResult>;
95
89
  /** Refactoring tool (code mode) */
96
90
  export declare const refactorTool: Tool<{
@@ -99,7 +93,6 @@ export declare const refactorTool: Tool<{
99
93
  maxTurns: number;
100
94
  context?: Record<string, unknown> | undefined;
101
95
  files?: string[] | undefined;
102
- system?: string | undefined;
103
96
  }, ClaudeCodeResult>;
104
97
  /** Documentation tool (code mode) */
105
98
  export declare const docsTool: Tool<{
@@ -108,7 +101,6 @@ export declare const docsTool: Tool<{
108
101
  maxTurns: number;
109
102
  context?: Record<string, unknown> | undefined;
110
103
  files?: string[] | undefined;
111
- system?: string | undefined;
112
104
  }, ClaudeCodeResult>;
113
105
  export {};
114
106
  //# sourceMappingURL=tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/claude-code/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE;;GAEG;AACH,QAAA,MAAM,qBAAqB;IACzB,qCAAqC;;IAGrC,gBAAgB;;IAOhB,oBAAoB;;IAOpB,wBAAwB;;IAMxB,yBAAyB;;IAMzB,2BAA2B;;;;;;;;;;;;;;;;EAK3B,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAmB7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,eAAe,EAAE,gBAAgB,CA+BlE,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACZ,GACL,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAiBzC;AAED;;GAEG;AAEH,kDAAkD;AAClD,eAAO,MAAM,cAAc;;;;;;;oBAazB,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,UAAU;;;;;;;oBAarB,CAAC;AAEH,mCAAmC;AACnC,eAAO,MAAM,YAAY;;;;;;;oBAavB,CAAC;AAEH,qCAAqC;AACrC,eAAO,MAAM,QAAQ;;;;;;;oBAYnB,CAAC"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/claude-code/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE;;GAEG;AACH,QAAA,MAAM,qBAAqB;IACzB,qCAAqC;;IAGrC,gBAAgB;;IAOhB,oBAAoB;;IAQpB,wBAAwB;;IAMxB,yBAAyB;;;;;;;;;;;;;;EAKzB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAmB7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,eAAe,EAAE,gBAAgB,CA6BlE,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACZ,GACL,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAqBzC;AAED;;GAEG;AAEH,kDAAkD;AAClD,eAAO,MAAM,cAAc;;;;;;oBAazB,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,UAAU;;;;;;oBAarB,CAAC;AAEH,mCAAmC;AACnC,eAAO,MAAM,YAAY;;;;;;oBAavB,CAAC;AAEH,qCAAqC;AACrC,eAAO,MAAM,QAAQ;;;;;;oBAYnB,CAAC"}
@@ -20,6 +20,7 @@ const claudeCodeInputSchema = z.object({
20
20
  /** Maximum turns */
21
21
  maxTurns: z
22
22
  .number()
23
+ .max(100)
23
24
  .optional()
24
25
  .default(20)
25
26
  .describe("Maximum agentic loop turns"),
@@ -33,11 +34,6 @@ const claudeCodeInputSchema = z.object({
33
34
  .record(z.unknown())
34
35
  .optional()
35
36
  .describe("Additional context to include in the prompt"),
36
- /** Custom system prompt */
37
- system: z
38
- .string()
39
- .optional()
40
- .describe("Custom system prompt override"),
41
37
  });
42
38
  /**
43
39
  * Build the full prompt from input
@@ -92,7 +88,6 @@ export const claudeCodeTool = {
92
88
  maxTurns: { type: "number", default: 20 },
93
89
  files: { type: "array", items: { type: "string" } },
94
90
  context: { type: "object" },
95
- system: { type: "string" },
96
91
  },
97
92
  required: ["task"],
98
93
  },
@@ -100,7 +95,6 @@ export const claudeCodeTool = {
100
95
  return executeAgent(buildPrompt(input), {
101
96
  mode: input.mode,
102
97
  maxTurns: input.maxTurns,
103
- systemPrompt: input.system,
104
98
  debug: true,
105
99
  });
106
100
  },
@@ -113,14 +107,18 @@ export function createClaudeCodeTool(options = {}) {
113
107
  ...claudeCodeTool,
114
108
  id: options.id || claudeCodeTool.id,
115
109
  description: options.description || claudeCodeTool.description,
116
- execute: (input, context) => {
110
+ execute: (input, _context) => {
117
111
  const mergedInput = {
118
112
  ...input,
119
113
  mode: input.mode || options.defaultMode || "code",
120
114
  maxTurns: input.maxTurns || options.defaultMaxTurns || 20,
121
- system: input.system || options.system,
122
115
  };
123
- return claudeCodeTool.execute(mergedInput, context);
116
+ return executeAgent(buildPrompt(mergedInput), {
117
+ mode: mergedInput.mode,
118
+ maxTurns: mergedInput.maxTurns,
119
+ systemPrompt: options.system,
120
+ debug: true,
121
+ });
124
122
  },
125
123
  };
126
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -265,6 +265,16 @@ function isRequest(obj: unknown): obj is dntShim.Request {
265
265
  );
266
266
  }
267
267
 
268
+ function extractUserId(request: dntShim.Request): string {
269
+ const userId = request.headers.get("x-user-id");
270
+ if (userId) return userId;
271
+ agentLogger.warn(
272
+ "No user identity found in request. Using anonymous fallback. " +
273
+ "Set x-user-id header or provide a context function for proper user isolation.",
274
+ );
275
+ return "anonymous";
276
+ }
277
+
268
278
  function extractRequest(requestOrCtx: unknown): dntShim.Request {
269
279
  if (isRequest(requestOrCtx)) return requestOrCtx;
270
280
  // Pages Router APIContext — has a .request property
@@ -317,7 +327,7 @@ export function createChatHandler(
317
327
 
318
328
  const context = typeof options?.context === "function"
319
329
  ? await options.context(request)
320
- : options?.context ?? { userId: "current-user" };
330
+ : options?.context ?? { userId: extractUserId(request) };
321
331
 
322
332
  const baseMessages = transformUIMessages(rawMessages);
323
333
  const beforeStreamResult = await options?.beforeStream?.({
@@ -33,6 +33,8 @@ export interface RedisMemoryConfig extends MemoryConfigBase {
33
33
  client: RedisClient;
34
34
  /** Key prefix for namespacing */
35
35
  keyPrefix?: string;
36
+ /** User ID for per-user memory isolation */
37
+ userId?: string;
36
38
  /** TTL in seconds (default: 24 hours) */
37
39
  ttl?: number;
38
40
  }
@@ -43,6 +45,7 @@ const DEFAULT_KEY_PREFIX = "veryfront:agent:memory:";
43
45
  export class RedisMemory<M extends MinimalMessage = MinimalMessage> implements Memory<M> {
44
46
  private client: RedisClient;
45
47
  private agentId: string;
48
+ private userId: string;
46
49
  private keyPrefix: string;
47
50
  private ttl: number;
48
51
  private config: RedisMemoryConfig;
@@ -50,13 +53,14 @@ export class RedisMemory<M extends MinimalMessage = MinimalMessage> implements M
50
53
  constructor(agentId: string, config: RedisMemoryConfig) {
51
54
  this.client = config.client;
52
55
  this.agentId = agentId;
56
+ this.userId = config.userId ?? "anonymous";
53
57
  this.keyPrefix = config.keyPrefix ?? DEFAULT_KEY_PREFIX;
54
58
  this.ttl = config.ttl ?? DEFAULT_TTL;
55
59
  this.config = config;
56
60
  }
57
61
 
58
62
  private getKey(): string {
59
- return `${this.keyPrefix}${this.agentId}`;
63
+ return `${this.keyPrefix}${this.agentId}:${this.userId}`;
60
64
  }
61
65
 
62
66
  private parseMessages(data: string | null): M[] {
@@ -307,9 +307,10 @@ export class AgentRuntime {
307
307
  controller.close();
308
308
  } catch (error) {
309
309
  this.status = "error";
310
+ logger.error("Agent stream error", { error });
310
311
  sendSSE(controller, encoder, {
311
312
  type: "error",
312
- error: error instanceof Error ? error.message : String(error),
313
+ error: "An internal error occurred",
313
314
  });
314
315
  controller.close();
315
316
  }
@@ -1,3 +1,4 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
1
2
  import { join } from "../../platform/compat/path/index.js";
2
3
  import { getCacheBaseDir } from "../../utils/cache-dir.js";
3
4
  import { logger } from "../../utils/index.js";
@@ -78,7 +79,7 @@ export class DiskCacheBackend implements CacheBackend {
78
79
  expiresAt: ttlSeconds != null ? Date.now() + ttlSeconds * 1000 : undefined,
79
80
  };
80
81
  const filePath = this.filePath(key);
81
- const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
82
+ const tmpPath = `${filePath}.tmp.${Date.now()}.${dntShim.crypto.randomUUID().slice(0, 8)}`;
82
83
  const content = JSON.stringify(envelope);
83
84
  const { writeFile, rename, unlink } = await fsPromises;
84
85
  try {
@@ -76,8 +76,15 @@ export function rateLimit(
76
76
  const maxRequests = options.maxRequests ?? DEFAULT_RATE_LIMIT_REQUESTS;
77
77
  const windowMs = options.windowMs ?? DEFAULT_RATE_LIMIT_WINDOW_MS;
78
78
  const store = options.store ?? new MemoryRateLimitStore(windowMs);
79
- const keyGenerator = options.keyGenerator ??
80
- ((req: dntShim.Request) => req.headers.get("x-forwarded-for") || "anonymous");
79
+ const keyGenerator = options.keyGenerator ?? ((req: dntShim.Request) => {
80
+ const forwarded = req.headers.get("x-forwarded-for");
81
+ if (forwarded) {
82
+ const parts = forwarded.split(",").map((s) => s.trim()).filter(Boolean);
83
+ // Use rightmost IP — added by nearest trusted proxy, not spoofable by clients
84
+ if (parts.length > 0) return parts[parts.length - 1]!;
85
+ }
86
+ return "anonymous";
87
+ });
81
88
 
82
89
  return async (ctx, next) => {
83
90
  const req = getRequest(ctx);
@@ -96,3 +103,12 @@ export function rateLimit(
96
103
  });
97
104
  };
98
105
  }
106
+
107
+ /** Pre-configured rate limiter for authentication endpoints (5 req/15min). */
108
+ export function authRateLimit(store?: RateLimitStore): Middleware {
109
+ return rateLimit({
110
+ maxRequests: 5,
111
+ windowMs: 15 * MS_PER_MINUTE,
112
+ store,
113
+ });
114
+ }
@@ -1,3 +1,4 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
1
2
  import { join } from "../../platform/compat/path/index.js";
2
3
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
3
4
  import { transformToESM } from "../../transforms/esm/index.js";
@@ -74,7 +75,7 @@ async function transformAllComponents(
74
75
 
75
76
  async function createTempDir(projectId: string, adapter: RuntimeAdapter): Promise<string> {
76
77
  const baseTmp = await getProjectTmpDir(projectId);
77
- const uniqueTmp = `unified-${Date.now()}-${Math.random().toString(16).slice(2)}`;
78
+ const uniqueTmp = `unified-${Date.now()}-${dntShim.crypto.randomUUID().slice(0, 12)}`;
78
79
  const tmpDir = join(baseTmp, uniqueTmp);
79
80
 
80
81
  await adapter.fs.mkdir(tmpDir, { recursive: true });
@@ -6,17 +6,26 @@ const STATE_EXPIRATION_MS = 10 * 60 * 1_000;
6
6
  export class MemoryTokenStore implements TokenStore {
7
7
  private tokens = new Map<string, OAuthTokens>();
8
8
  private states = new Map<string, OAuthState>();
9
+ private projectId: string;
10
+
11
+ constructor(projectId = "default") {
12
+ this.projectId = projectId;
13
+ }
14
+
15
+ private scopedKey(serviceId: string): string {
16
+ return `${this.projectId}:${serviceId}`;
17
+ }
9
18
 
10
19
  async getTokens(serviceId: string): Promise<OAuthTokens | null> {
11
- return this.tokens.get(serviceId) ?? null;
20
+ return this.tokens.get(this.scopedKey(serviceId)) ?? null;
12
21
  }
13
22
 
14
23
  async setTokens(serviceId: string, tokens: OAuthTokens): Promise<void> {
15
- this.tokens.set(serviceId, tokens);
24
+ this.tokens.set(this.scopedKey(serviceId), tokens);
16
25
  }
17
26
 
18
27
  async clearTokens(serviceId: string): Promise<void> {
19
- this.tokens.delete(serviceId);
28
+ this.tokens.delete(this.scopedKey(serviceId));
20
29
  }
21
30
 
22
31
  async getState(state: string): Promise<OAuthState | null> {
@@ -54,7 +63,7 @@ export class MemoryTokenStore implements TokenStore {
54
63
  }
55
64
 
56
65
  isConnected(serviceId: string): boolean {
57
- const tokens = this.tokens.get(serviceId);
66
+ const tokens = this.tokens.get(this.scopedKey(serviceId));
58
67
  if (!tokens) return false;
59
68
 
60
69
  const isExpired = tokens.expiresAt != null && Date.now() > tokens.expiresAt;
@@ -127,42 +127,30 @@ export class WebSocketManager {
127
127
  this.wsConsecutiveFailures = 0;
128
128
  }
129
129
 
130
- let wsUrl = this.deps.apiBaseUrl
130
+ const wsUrl = this.deps.apiBaseUrl
131
131
  .replace(/^http:/, "ws:")
132
132
  .replace(/^https:/, "wss:")
133
133
  .replace(/\/api$/, "");
134
134
 
135
- // Enforce TLS for non-localhost connections to protect the auth token
136
- if (wsUrl.startsWith("ws://")) {
137
- try {
138
- const host = new URL(wsUrl.replace(/^ws:/, "http:")).hostname;
139
- const isLocal = host === "localhost" || host === "127.0.0.1" ||
140
- host === "::1" || host === "[::1]";
141
- if (!isLocal) {
142
- wsUrl = wsUrl.replace(/^ws:/, "wss:");
143
- logger.warn(
144
- "Upgraded WebSocket connection to wss:// for non-localhost host",
145
- this.getConnectionLogContext({ host }),
146
- );
147
- }
148
- } catch {
149
- // If URL parsing fails, upgrade to be safe
150
- wsUrl = wsUrl.replace(/^ws:/, "wss:");
151
- }
152
- }
135
+ // The WebSocket protocol (ws vs wss) is derived from the configured
136
+ // apiBaseUrl (http→ws, https→wss). No forced upgrade is needed because
137
+ // the auth token is sent via a subprotocol header, not in the URL.
153
138
 
154
- const url = `${wsUrl}/ws/${projectId}/events?token=${this.deps.apiToken}`;
139
+ const url = `${wsUrl}/ws/${projectId}/events`;
155
140
 
156
141
  logger.debug(
157
142
  "Connecting to WebSocket",
158
143
  this.getConnectionLogContext({
159
- url: url.replace(this.deps.apiToken, "***"),
144
+ url,
160
145
  consecutiveFailures: this.wsConsecutiveFailures,
161
146
  }),
162
147
  );
163
148
 
164
149
  try {
165
- this.ws = new WebSocket(url);
150
+ // Send the API token via a WebSocket subprotocol header instead of
151
+ // a query-string parameter. Query strings can leak into server
152
+ // access logs, proxy logs, and the browser's Referer header.
153
+ this.ws = new WebSocket(url, [`bearer-${this.deps.apiToken}`]);
166
154
  this.wsConnectionId = dntShim.crypto.randomUUID().slice(0, 8);
167
155
  this.wsErrorLogged = false;
168
156
 
@@ -214,7 +202,7 @@ export class WebSocketManager {
214
202
  "WebSocket error",
215
203
  this.getConnectionLogContext({
216
204
  type: event.type,
217
- url: (event.target as WebSocket)?.url?.replace(/token=[^&]+/, "token=***"),
205
+ url: (event.target as WebSocket)?.url,
218
206
  readyState: (event.target as WebSocket)?.readyState,
219
207
  consecutiveFailures: this.wsConsecutiveFailures,
220
208
  }),
@@ -162,7 +162,7 @@ class NodeFileSystem implements FileSystem {
162
162
  await this.ensureInitialized();
163
163
  const tempDir = this.getPath().join(
164
164
  this.getOs().tmpdir(),
165
- `${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`,
165
+ `${options?.prefix ?? "tmp-"}${dntShim.crypto.randomUUID().slice(0, 8)}`,
166
166
  );
167
167
  await this.getFs().mkdir(tempDir, { recursive: true });
168
168
  return tempDir;
@@ -577,6 +577,9 @@ function router(req: dntShim.Request): Promise<dntShim.Response> {
577
577
 
578
578
  switch (url.pathname) {
579
579
  case "/_proxy/stats":
580
+ if (Object.keys(proxyHandler.localProjects).length === 0) {
581
+ return Promise.resolve(new dntShim.Response("Forbidden", { status: 403 }));
582
+ }
580
583
  return handleStats();
581
584
  case "/_proxy/health":
582
585
  return Promise.resolve(
@@ -12,6 +12,12 @@ export async function loadSecurityConfig(
12
12
  const remote = cfg.security?.remoteHosts;
13
13
 
14
14
  if (Array.isArray(remote)) {
15
+ if (remote.length === 0) {
16
+ logger.warn(
17
+ "security.remoteHosts is set to an empty array — all remote requests will be blocked. " +
18
+ "If this is intentional, you can ignore this warning.",
19
+ );
20
+ }
15
21
  return remote;
16
22
  }
17
23
  } catch (e) {
@@ -43,7 +43,15 @@ export class SecurityConfigLoader {
43
43
 
44
44
  if (security.headers) security.headers = { ...security.headers };
45
45
 
46
- security.cors ??= true;
46
+ security.cors ??= false;
47
+
48
+ if (!cfg?.security?.cors && !cfg?.security?.csrf) {
49
+ logger.warn(
50
+ "Neither CORS nor CSRF protection is configured. " +
51
+ "CORS is disabled by default (same-origin only). " +
52
+ "Consider explicitly configuring security.cors and security.csrf.",
53
+ );
54
+ }
47
55
 
48
56
  this.securityConfig = security;
49
57
  this.cspUserHeader = this.parseCspUserHeader(security.csp);
@@ -72,6 +72,8 @@ export function handleDashboardAPI(
72
72
  req: dntShim.Request,
73
73
  ctx: HandlerContext,
74
74
  ): Promise<dntShim.Response | null> | dntShim.Response | null {
75
+ if (!ctx.isLocalProject) return errorResponse("Unauthorized", 401);
76
+
75
77
  const { pathname } = new URL(req.url);
76
78
 
77
79
  if (req.method === "GET") {
@@ -56,7 +56,7 @@ export class OpenAPIHandler extends BaseHandler {
56
56
 
57
57
  const response = this.createResponseBuilder(ctx)
58
58
  .withCache(isDev ? "no-cache" : { maxAge: SPEC_CACHE_MAX_AGE_SECONDS, public: true })
59
- .withCORS(req, { origin: "*" })
59
+ .withCORS(req, ctx.securityConfig?.cors)
60
60
  .withContentType(
61
61
  isYaml ? "text/yaml; charset=utf-8" : "application/json; charset=utf-8",
62
62
  content,
@@ -312,9 +312,20 @@ export class StaticFileService {
312
312
  isAssetRequest(pathname: string): boolean {
313
313
  if (pathname.includes("/.veryfront/") || pathname.startsWith("/.veryfront")) return false;
314
314
  if (pathname.endsWith(".md")) return false;
315
+ if (this.isDeniedDotfile(pathname)) return false;
315
316
  return pathname.includes(".") || pathname.startsWith("/_veryfront/");
316
317
  }
317
318
 
319
+ private isDeniedDotfile(pathname: string): boolean {
320
+ const segments = pathname.split("/");
321
+ for (const segment of segments) {
322
+ if (segment.startsWith(".") && segment !== ".well-known") {
323
+ return true;
324
+ }
325
+ }
326
+ return false;
327
+ }
328
+
318
329
  static clearCache(): void {
319
330
  StaticFileService.manifestCache.clear();
320
331
  StaticFileService.manifestLoading.clear();
@@ -78,7 +78,7 @@ function formatEnvAssignments(env?: Record<string, string>): string[] {
78
78
 
79
79
  function createSandboxScriptPath(scriptPath: string): string {
80
80
  const ext = extname(scriptPath) || ".sh";
81
- const suffix = Math.random().toString(36).slice(2, 10);
81
+ const suffix = dntShim.crypto.randomUUID().slice(0, 8);
82
82
  return `/tmp/veryfront-skill-script-${Date.now()}-${suffix}${ext}`;
83
83
  }
84
84
 
@@ -186,6 +186,16 @@ export function dynamicTool(config: DynamicToolConfig): Tool<unknown, unknown> {
186
186
  inputSchema: config.inputSchema as z.ZodSchema<unknown>,
187
187
  inputSchemaJson,
188
188
  execute: async (input: unknown, context?: ToolExecutionContext) => {
189
+ if (
190
+ config.inputSchema &&
191
+ typeof (config.inputSchema as { parse?: unknown }).parse === "function"
192
+ ) {
193
+ (config.inputSchema as { parse: (v: unknown) => unknown }).parse(input);
194
+ } else if (input === undefined) {
195
+ input = {};
196
+ } else if (input === null || typeof input !== "object") {
197
+ throw new Error("dynamicTool: input must be a non-null object");
198
+ }
189
199
  const result = await config.execute(input, context);
190
200
  return config.toModelOutput ? config.toModelOutput(result) : result;
191
201
  },
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { createFileSystem } from "../../../../platform/compat/fs.js";
9
9
  import { join } from "../../../../platform/compat/path/index.js";
10
+ import denoConfig from "../../../../../deno.js";
10
11
  import { rendererLogger as logger } from "../../../../utils/index.js";
11
12
  import { IMPORT_RESOLUTION_ERROR } from "../../../../errors/index.js";
12
13
  import { replaceSpecifiers } from "../../../esm/lexer.js";
@@ -30,6 +31,8 @@ import {
30
31
  veryfrontTransformCache,
31
32
  } from "./constants.js";
32
33
 
34
+ const DENO_CONFIG_STUB_CODE = `export default ${JSON.stringify(denoConfig)};`;
35
+
33
36
  /**
34
37
  * Check if a transformed code string is a cycle placeholder.
35
38
  * Cycle placeholders are returned when transformFrameworkCode detects a cycle
@@ -291,7 +294,26 @@ export async function transformFrameworkCode(
291
294
  // Rewrite imports to resolved paths
292
295
  const reactImportMap = getReactImportMap(ctx.reactVersion);
293
296
 
297
+ // Handle Deno import-map aliases (e.g. #deno-config) that only exist in
298
+ // the Deno runtime and cannot be resolved by esm.sh or the HTTP cache.
299
+ // We create a cached JS stub module so the transformed code can import it
300
+ // without losing access to imports/exports metadata from deno.json.
301
+ let denoConfigStubUrl: string | null = null;
302
+ if (transformed.includes('"#deno-config"') || transformed.includes("'#deno-config'")) {
303
+ const stubPath = await cacheTransformedCode(
304
+ DENO_CONFIG_STUB_CODE,
305
+ "#deno-config-stub",
306
+ ctx.fs,
307
+ );
308
+ denoConfigStubUrl = `file://${stubPath}`;
309
+ }
310
+
294
311
  transformed = await replaceSpecifiers(transformed, (specifier) => {
312
+ // Handle Deno import-map aliases
313
+ if (specifier === "#deno-config") {
314
+ return denoConfigStubUrl;
315
+ }
316
+
295
317
  // Handle #veryfront/ imports
296
318
  if (specifier.startsWith("#veryfront/")) {
297
319
  return veryfrontReplacements.get(specifier) ?? null;
@@ -26,6 +26,7 @@ const claudeCodeInputSchema = z.object({
26
26
  /** Maximum turns */
27
27
  maxTurns: z
28
28
  .number()
29
+ .max(100)
29
30
  .optional()
30
31
  .default(20)
31
32
  .describe("Maximum agentic loop turns"),
@@ -41,12 +42,6 @@ const claudeCodeInputSchema = z.object({
41
42
  .record(z.unknown())
42
43
  .optional()
43
44
  .describe("Additional context to include in the prompt"),
44
-
45
- /** Custom system prompt */
46
- system: z
47
- .string()
48
- .optional()
49
- .describe("Custom system prompt override"),
50
45
  });
51
46
 
52
47
  type ClaudeCodeInput = z.infer<typeof claudeCodeInputSchema>;
@@ -108,7 +103,6 @@ export const claudeCodeTool: Tool<ClaudeCodeInput, ClaudeCodeResult> = {
108
103
  maxTurns: { type: "number", default: 20 },
109
104
  files: { type: "array", items: { type: "string" } },
110
105
  context: { type: "object" },
111
- system: { type: "string" },
112
106
  },
113
107
  required: ["task"],
114
108
  },
@@ -117,7 +111,6 @@ export const claudeCodeTool: Tool<ClaudeCodeInput, ClaudeCodeResult> = {
117
111
  return executeAgent(buildPrompt(input), {
118
112
  mode: input.mode as ClaudeCodeMode,
119
113
  maxTurns: input.maxTurns,
120
- systemPrompt: input.system,
121
114
  debug: true,
122
115
  });
123
116
  },
@@ -140,15 +133,19 @@ export function createClaudeCodeTool(
140
133
  id: options.id || claudeCodeTool.id,
141
134
  description: options.description || claudeCodeTool.description,
142
135
 
143
- execute: (input, context) => {
136
+ execute: (input, _context) => {
144
137
  const mergedInput: ClaudeCodeInput = {
145
138
  ...input,
146
139
  mode: input.mode || options.defaultMode || "code",
147
140
  maxTurns: input.maxTurns || options.defaultMaxTurns || 20,
148
- system: input.system || options.system,
149
141
  };
150
142
 
151
- return claudeCodeTool.execute(mergedInput, context);
143
+ return executeAgent(buildPrompt(mergedInput), {
144
+ mode: mergedInput.mode as ClaudeCodeMode,
145
+ maxTurns: mergedInput.maxTurns,
146
+ systemPrompt: options.system,
147
+ debug: true,
148
+ });
152
149
  },
153
150
  };
154
151
  }