veryfront 0.1.56 → 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 (48) 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/middleware/builtin/security/rate-limit.d.ts +2 -0
  10. package/esm/src/middleware/builtin/security/rate-limit.d.ts.map +1 -1
  11. package/esm/src/middleware/builtin/security/rate-limit.js +18 -2
  12. package/esm/src/oauth/token-store/memory.d.ts +3 -0
  13. package/esm/src/oauth/token-store/memory.d.ts.map +1 -1
  14. package/esm/src/oauth/token-store/memory.js +11 -4
  15. package/esm/src/proxy/main.js +3 -0
  16. package/esm/src/routing/api/module-loader/security-config.d.ts.map +1 -1
  17. package/esm/src/routing/api/module-loader/security-config.js +4 -0
  18. package/esm/src/security/http/config.d.ts.map +1 -1
  19. package/esm/src/security/http/config.js +6 -1
  20. package/esm/src/server/handlers/dev/dashboard/api.d.ts.map +1 -1
  21. package/esm/src/server/handlers/dev/dashboard/api.js +2 -0
  22. package/esm/src/server/handlers/request/openapi.handler.js +1 -1
  23. package/esm/src/server/services/static/static-file.service.d.ts +1 -0
  24. package/esm/src/server/services/static/static-file.service.d.ts.map +1 -1
  25. package/esm/src/server/services/static/static-file.service.js +11 -0
  26. package/esm/src/tool/factory.d.ts.map +1 -1
  27. package/esm/src/tool/factory.js +10 -0
  28. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts.map +1 -1
  29. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.js +15 -0
  30. package/esm/src/workflow/claude-code/tool.d.ts +0 -8
  31. package/esm/src/workflow/claude-code/tool.d.ts.map +1 -1
  32. package/esm/src/workflow/claude-code/tool.js +8 -10
  33. package/package.json +1 -1
  34. package/src/deno.js +1 -1
  35. package/src/src/agent/chat-handler.ts +11 -1
  36. package/src/src/agent/memory/redis.ts +5 -1
  37. package/src/src/agent/runtime/index.ts +2 -1
  38. package/src/src/middleware/builtin/security/rate-limit.ts +18 -2
  39. package/src/src/oauth/token-store/memory.ts +13 -4
  40. package/src/src/proxy/main.ts +3 -0
  41. package/src/src/routing/api/module-loader/security-config.ts +6 -0
  42. package/src/src/security/http/config.ts +9 -1
  43. package/src/src/server/handlers/dev/dashboard/api.ts +2 -0
  44. package/src/src/server/handlers/request/openapi.handler.ts +1 -1
  45. package/src/src/server/services/static/static-file.service.ts +11 -0
  46. package/src/src/tool/factory.ts +10 -0
  47. package/src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts +22 -0
  48. 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.56",
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
  }
@@ -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
+ }
@@ -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;
@@ -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();
@@ -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.56",
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.56",
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
  }
@@ -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
+ }
@@ -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;
@@ -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();
@@ -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
  }