veryfront 0.1.739 → 0.1.743

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 (63) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/agent/hosted/child-tool-input.js +1 -1
  3. package/esm/src/mcp/http-transport.js +1 -1
  4. package/esm/src/mcp/session.d.ts +23 -0
  5. package/esm/src/mcp/session.d.ts.map +1 -1
  6. package/esm/src/mcp/session.js +46 -3
  7. package/esm/src/modules/manifest/route-module-manifest.d.ts.map +1 -1
  8. package/esm/src/modules/manifest/route-module-manifest.js +12 -4
  9. package/esm/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.d.ts.map +1 -1
  10. package/esm/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.js +2 -1
  11. package/esm/src/modules/server/cross-project-source-limit.d.ts +7 -0
  12. package/esm/src/modules/server/cross-project-source-limit.d.ts.map +1 -0
  13. package/esm/src/modules/server/cross-project-source-limit.js +46 -0
  14. package/esm/src/modules/server/module-batch-handler.d.ts.map +1 -1
  15. package/esm/src/modules/server/module-batch-handler.js +3 -4
  16. package/esm/src/modules/server/module-server.d.ts.map +1 -1
  17. package/esm/src/modules/server/module-server.js +11 -1
  18. package/esm/src/oauth/providers/base.d.ts +3 -0
  19. package/esm/src/oauth/providers/base.d.ts.map +1 -1
  20. package/esm/src/oauth/providers/base.js +24 -2
  21. package/esm/src/provider/runtime-loader/tool-input-status.d.ts.map +1 -1
  22. package/esm/src/provider/runtime-loader/tool-input-status.js +16 -8
  23. package/esm/src/rendering/context/render-context.d.ts.map +1 -1
  24. package/esm/src/rendering/context/render-context.js +7 -1
  25. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts +2 -0
  26. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts.map +1 -1
  27. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.js +23 -10
  28. package/esm/src/rendering/renderer-concurrency.d.ts.map +1 -1
  29. package/esm/src/rendering/renderer-concurrency.js +9 -2
  30. package/esm/src/security/sandbox/worker-permissions.d.ts +10 -7
  31. package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -1
  32. package/esm/src/security/sandbox/worker-permissions.js +32 -18
  33. package/esm/src/server/context/enriched-context.d.ts.map +1 -1
  34. package/esm/src/server/context/enriched-context.js +15 -3
  35. package/esm/src/server/handlers/request/api/project-discovery.js +2 -2
  36. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  37. package/esm/src/server/services/rendering/ssr.service.js +6 -3
  38. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.d.ts +4 -0
  39. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.d.ts.map +1 -1
  40. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.js +22 -18
  41. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fetcher.d.ts.map +1 -1
  42. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fetcher.js +27 -8
  43. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.d.ts.map +1 -1
  44. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.js +24 -14
  45. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts +1 -1
  46. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
  47. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +1 -1
  48. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts +4 -0
  49. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts.map +1 -1
  50. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.js +45 -37
  51. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.d.ts +5 -0
  52. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.d.ts.map +1 -1
  53. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.js +27 -2
  54. package/esm/src/transforms/mdx/esm-module-loader/types.d.ts +2 -0
  55. package/esm/src/transforms/mdx/esm-module-loader/types.d.ts.map +1 -1
  56. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts +23 -0
  57. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts.map +1 -0
  58. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.js +188 -0
  59. package/esm/src/utils/version-constant.d.ts +1 -1
  60. package/esm/src/utils/version-constant.js +1 -1
  61. package/esm/src/workflow/worker/workflow-worker.d.ts.map +1 -1
  62. package/esm/src/workflow/worker/workflow-worker.js +9 -1
  63. package/package.json +1 -1
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.739",
3
+ "version": "0.1.743",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": "P2D",
@@ -5,7 +5,7 @@ export const DEFAULT_HOSTED_CHILD_AGENT_ID = "invoke-agent-child";
5
5
  export const getHostedChildForkToolInputSchema = defineSchema((v) => v.object({
6
6
  description: v.string().describe("3-5 word task summary"),
7
7
  prompt: v.string().describe("Detailed instructions for the task"),
8
- context: v.record(v.string(), getJsonValueSchema()).describe("Required structured data payload for the child task. Use this for critical facts, records, ids, decisions, and values the child must act on. Use {} only when the delegation has no record or evidence payload."),
8
+ context: v.record(v.string(), getJsonValueSchema()).default({}).describe("Structured data payload for the child task. Use this for critical facts, records, ids, decisions, and values the child must act on. Defaults to {} when the delegation has no record or evidence payload."),
9
9
  project_id: v.string().optional().describe("Override project context. Use after studio_open_project."),
10
10
  tools: v.array(v.string()).optional().describe("Tool subset for this fork. Omit = inherit all parent tools."),
11
11
  model: v.string().optional().describe('Model override (e.g. "sonnet" for cheaper work).'),
@@ -76,7 +76,7 @@ export function createMCPHTTPHandler(dependencies) {
76
76
  return createJSONResponse(rpcResponse, { headers: responseHeaders });
77
77
  }
78
78
  let sessionId;
79
- if (sessionManager.size > 0) {
79
+ if (sessionManager.requiresSessionHeader()) {
80
80
  sessionId = request.headers.get("MCP-Session-Id") ?? undefined;
81
81
  if (!sessionId) {
82
82
  return createJSONRPCErrorResponse(400, -32600, "Missing MCP-Session-Id header");
@@ -1,9 +1,32 @@
1
+ /**
2
+ * Manages MCP sessions for the Streamable HTTP transport.
3
+ * Sessions are created during initialization and validated on subsequent requests.
4
+ *
5
+ * Sessions expire after a period of inactivity so that clients which disconnect
6
+ * uncleanly (closed tab, crash, dropped network) don't leak entries forever.
7
+ * Expiry is lazy: stale entries are pruned on access, so no background timer is
8
+ * required.
9
+ */
10
+ export interface SessionManagerOptions {
11
+ /** Inactivity TTL in ms (default 30 minutes). */
12
+ ttlMs?: number;
13
+ /** Clock, injectable for tests. Defaults to Date.now. */
14
+ now?: () => number;
15
+ }
1
16
  export declare class SessionManager {
17
+ /** id -> last-seen timestamp (ms). */
2
18
  private sessions;
19
+ private readonly ttlMs;
20
+ private readonly now;
21
+ private sessionHeaderRequired;
22
+ constructor(options?: SessionManagerOptions);
3
23
  create(): string;
4
24
  isValid(id: string): boolean;
5
25
  terminate(id: string): void;
6
26
  get size(): number;
7
27
  clear(): void;
28
+ requiresSessionHeader(): boolean;
29
+ private isExpired;
30
+ private pruneExpired;
8
31
  }
9
32
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/session.ts"],"names":[],"mappings":"AAMA,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqB;IAErC,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI5B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI3B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,cAAc;IACzB,sCAAsC;IACtC,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,qBAAqB,CAAS;gBAE1B,OAAO,GAAE,qBAA0B;IAK/C,MAAM,IAAI,MAAM;IAQhB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAY5B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK3B,IAAI,IAAI,IAAI,MAAM,CAGjB;IAED,KAAK,IAAI,IAAI;IAKb,qBAAqB,IAAI,OAAO;IAIhC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;CAMrB"}
@@ -1,25 +1,68 @@
1
1
  /**
2
2
  * Manages MCP sessions for the Streamable HTTP transport.
3
3
  * Sessions are created during initialization and validated on subsequent requests.
4
+ *
5
+ * Sessions expire after a period of inactivity so that clients which disconnect
6
+ * uncleanly (closed tab, crash, dropped network) don't leak entries forever.
7
+ * Expiry is lazy: stale entries are pruned on access, so no background timer is
8
+ * required.
4
9
  */
10
+ /** Default inactivity window before a session is considered expired (30 min). */
5
11
  import * as dntShim from "../../_dnt.shims.js";
12
+ const DEFAULT_SESSION_TTL_MS = 30 * 60_000;
6
13
  export class SessionManager {
7
- sessions = new Set();
14
+ /** id -> last-seen timestamp (ms). */
15
+ sessions = new Map();
16
+ ttlMs;
17
+ now;
18
+ sessionHeaderRequired = false;
19
+ constructor(options = {}) {
20
+ this.ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;
21
+ this.now = options.now ?? Date.now;
22
+ }
8
23
  create() {
24
+ this.pruneExpired();
9
25
  const id = dntShim.crypto.randomUUID();
10
- this.sessions.add(id);
26
+ this.sessions.set(id, this.now());
27
+ this.sessionHeaderRequired = true;
11
28
  return id;
12
29
  }
13
30
  isValid(id) {
14
- return this.sessions.has(id);
31
+ const lastSeen = this.sessions.get(id);
32
+ if (lastSeen === undefined)
33
+ return false;
34
+ if (this.isExpired(lastSeen)) {
35
+ this.sessions.delete(id);
36
+ return false;
37
+ }
38
+ // Touch: activity refreshes the inactivity window.
39
+ this.sessions.set(id, this.now());
40
+ return true;
15
41
  }
16
42
  terminate(id) {
17
43
  this.sessions.delete(id);
44
+ if (this.sessions.size === 0)
45
+ this.sessionHeaderRequired = false;
18
46
  }
19
47
  get size() {
48
+ this.pruneExpired();
20
49
  return this.sessions.size;
21
50
  }
22
51
  clear() {
23
52
  this.sessions.clear();
53
+ this.sessionHeaderRequired = false;
54
+ }
55
+ requiresSessionHeader() {
56
+ return this.sessionHeaderRequired;
57
+ }
58
+ isExpired(lastSeen) {
59
+ return this.now() - lastSeen > this.ttlMs;
60
+ }
61
+ pruneExpired() {
62
+ const cutoff = this.now() - this.ttlMs;
63
+ for (const [id, lastSeen] of this.sessions) {
64
+ if (lastSeen < cutoff)
65
+ this.sessions.delete(id);
66
+ }
24
67
  }
25
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"route-module-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/manifest/route-module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAuBD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,UAAQ,GAChB,IAAI,CAEN;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,eAAe,GAAE,MAAM,EAAO,GAC7B,IAAI,CAwCN;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,aAAa,GAAG,IAAI,CAYtB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAOV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CA2BN;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAK,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,IAAI;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E,CAcA;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAS/D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
1
+ {"version":3,"file":"route-module-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/manifest/route-module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAyBD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,UAAQ,GAChB,IAAI,CAEN;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,eAAe,GAAE,MAAM,EAAO,GAC7B,IAAI,CAwCN;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,aAAa,GAAG,IAAI,CAYtB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAOV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CA2BN;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAK,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,IAAI;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E,CAcA;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAU/D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
@@ -10,9 +10,16 @@
10
10
  * @module module-system/manifest/route-module-manifest
11
11
  */
12
12
  import { serverLogger } from "../../utils/index.js";
13
+ import { LRUCache } from "../../utils/lru-wrapper.js";
13
14
  const logger = serverLogger.component("route-module-manifest");
14
- const manifestStore = new Map();
15
- const pendingCollections = new Map();
15
+ /** Bound on tracked routes; manifests are a regenerable preload optimization. */
16
+ const MAX_TRACKED_ROUTES = 2_000;
17
+ /** Bound on in-flight collections; abandoned ones (render errors) get evicted. */
18
+ const MAX_PENDING_COLLECTIONS = 2_000;
19
+ const manifestStore = new LRUCache({ maxEntries: MAX_TRACKED_ROUTES });
20
+ const pendingCollections = new LRUCache({
21
+ maxEntries: MAX_PENDING_COLLECTIONS,
22
+ });
16
23
  function buildKey(projectSlug, route) {
17
24
  return `${projectSlug ?? "default"}:${route || "index"}`;
18
25
  }
@@ -132,7 +139,7 @@ export function generateModulePreloadHintsFromManifest(projectSlug, route, maxHi
132
139
  export function getManifestStats() {
133
140
  const routes = [];
134
141
  let totalModules = 0;
135
- for (const [key, manifest] of manifestStore) {
142
+ for (const [key, manifest] of manifestStore.entries()) {
136
143
  routes.push({
137
144
  route: key,
138
145
  moduleCount: manifest.moduleCount,
@@ -144,7 +151,8 @@ export function getManifestStats() {
144
151
  }
145
152
  export function clearProjectManifests(projectSlug) {
146
153
  const prefix = `${projectSlug}:`;
147
- for (const key of manifestStore.keys()) {
154
+ // Snapshot keys before deleting to avoid mutating during iteration.
155
+ for (const key of [...manifestStore.keys()]) {
148
156
  if (!key.startsWith(prefix))
149
157
  continue;
150
158
  manifestStore.delete(key);
@@ -1 +1 @@
1
- {"version":3,"file":"cross-project-import-loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,EAAE,cAAc,IAAI,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,UAAU,uBAAuB;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,KAAK,IAAI,UAAU,CAAC;CACrB;AAED,UAAU,sCAAsC;IAC9C,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,OAAO,EAAE,IAAI,CACX,sBAAsB,EACtB,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAC/E,CAAC;IACF,KAAK,EAAE,uBAAuB,CAAC;IAC/B,qBAAqB,EAAE,CAAC,CAAC,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KACxB,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,iBAAiB,CAAC,EAAE,OAAO,aAAa,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC,OAAO,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,wBAAsB,+BAA+B,CACnD,WAAW,EAAE,sCAAsC,GAClD,OAAO,CAAC,MAAM,CAAC,CA0GjB"}
1
+ {"version":3,"file":"cross-project-import-loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,EAAE,cAAc,IAAI,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGzD,UAAU,uBAAuB;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,KAAK,IAAI,UAAU,CAAC;CACrB;AAED,UAAU,sCAAsC;IAC9C,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,OAAO,EAAE,IAAI,CACX,sBAAsB,EACtB,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAC/E,CAAC;IACF,KAAK,EAAE,uBAAuB,CAAC;IAC/B,qBAAqB,EAAE,CAAC,CAAC,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KACxB,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,iBAAiB,CAAC,EAAE,OAAO,aAAa,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC,OAAO,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,wBAAsB,+BAA+B,CACnD,WAAW,EAAE,sCAAsC,GAClD,OAAO,CAAC,MAAM,CAAC,CA0GjB"}
@@ -7,6 +7,7 @@ import { HTTP_FETCH_TIMEOUT_MS } from "../../../utils/constants/http.js";
7
7
  import { writeCacheFile } from "../../../utils/cache-file-ops.js";
8
8
  import { rendererLogger as logger } from "../../../utils/index.js";
9
9
  import { globalCrossProjectCache } from "./cache/index.js";
10
+ import { readLimitedCrossProjectSource } from "../../server/cross-project-source-limit.js";
10
11
  function getRegistryBaseUrl(apiBaseUrl) {
11
12
  const resolvedApiBaseUrl = apiBaseUrl || getApiBaseUrlEnv();
12
13
  return resolvedApiBaseUrl.replace(/\/api\/?$/, "");
@@ -40,7 +41,7 @@ export async function transformCrossProjectImportFlow(flowOptions) {
40
41
  detail: `Failed to fetch ${registryUrl}: ${response.status} ${response.statusText}`,
41
42
  });
42
43
  }
43
- const sourceCode = await response.text();
44
+ const sourceCode = await readLimitedCrossProjectSource(response, registryUrl);
44
45
  const contentHash = await cache.hashContentAsync(sourceCode);
45
46
  const ext = path.match(/\.(tsx?|jsx?|mdx)$/)?.[0] ?? ".tsx";
46
47
  const syntheticFilePath = `cross-project/${projectRef}/@/${path}`;
@@ -0,0 +1,7 @@
1
+ /** Max size of a fetched cross-project module source, to bound memory use. */
2
+ export declare const MAX_CROSS_PROJECT_SOURCE_BYTES: number;
3
+ export declare class CrossProjectSourceTooLargeError extends Error {
4
+ constructor(registryUrl: string, maxBytes?: number);
5
+ }
6
+ export declare function readLimitedCrossProjectSource(response: Response, registryUrl: string, maxBytes?: number): Promise<string>;
7
+ //# sourceMappingURL=cross-project-source-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-project-source-limit.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/cross-project-source-limit.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B,QAAkB,CAAC;AAE9D,qBAAa,+BAAgC,SAAQ,KAAK;gBAC5C,WAAW,EAAE,MAAM,EAAE,QAAQ,SAAiC;CAI3E;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAiC,GACxC,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
@@ -0,0 +1,46 @@
1
+ /** Max size of a fetched cross-project module source, to bound memory use. */
2
+ export const MAX_CROSS_PROJECT_SOURCE_BYTES = 5 * 1024 * 1024; // 5MB
3
+ export class CrossProjectSourceTooLargeError extends Error {
4
+ constructor(registryUrl, maxBytes = MAX_CROSS_PROJECT_SOURCE_BYTES) {
5
+ super(`Cross-project source exceeds size limit: ${registryUrl} (${maxBytes} bytes)`);
6
+ this.name = "CrossProjectSourceTooLargeError";
7
+ }
8
+ }
9
+ export async function readLimitedCrossProjectSource(response, registryUrl, maxBytes = MAX_CROSS_PROJECT_SOURCE_BYTES) {
10
+ const declaredLength = Number(response.headers.get("content-length") ?? "");
11
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
12
+ await response.body?.cancel();
13
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
14
+ }
15
+ if (!response.body) {
16
+ const text = await response.text();
17
+ if (new TextEncoder().encode(text).byteLength > maxBytes) {
18
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
19
+ }
20
+ return text;
21
+ }
22
+ const reader = response.body.getReader();
23
+ const decoder = new TextDecoder();
24
+ const chunks = [];
25
+ let totalBytes = 0;
26
+ try {
27
+ while (true) {
28
+ const { done, value } = await reader.read();
29
+ if (done)
30
+ break;
31
+ totalBytes += value.byteLength;
32
+ if (totalBytes > maxBytes) {
33
+ await reader.cancel();
34
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
35
+ }
36
+ chunks.push(decoder.decode(value, { stream: true }));
37
+ }
38
+ const tail = decoder.decode();
39
+ if (tail.length > 0)
40
+ chunks.push(tail);
41
+ return chunks.join("");
42
+ }
43
+ finally {
44
+ reader.releaseLock();
45
+ }
46
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAqDtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AA4JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
1
+ {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAqDtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AA2JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
@@ -298,10 +298,9 @@ function generateBatchBundle(successes, failures) {
298
298
  * Converts ES module syntax to work within the bundle wrapper
299
299
  */
300
300
  function transformExportsForBundle(code) {
301
- return code
302
- .split("\n")
303
- .map((line) => ` ${line}`)
304
- .join("\n");
301
+ // Indent every line by two spaces. A single regex avoids allocating an
302
+ // intermediate array of lines per module on the batch hot path.
303
+ return code.replace(/^/gm, " ");
305
304
  }
306
305
  /**
307
306
  * Clear the transform cache (on deployment or memory pressure)
@@ -1 +1 @@
1
- {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAsBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AASF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0TzF;AA+PD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
1
+ {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAuBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AAQF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0TzF;AA+PD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
@@ -15,6 +15,7 @@ import { applySSRImportRewrites } from "./ssr-import-rewriter.js";
15
15
  import { addHMRTimestamps } from "../../transforms/esm/import-rewriter.js";
16
16
  import { FRAMEWORK_ROOT, resolveFrameworkSourcePath, } from "../../platform/compat/framework-source-resolver.js";
17
17
  import { getReactUrls, REACT_DEFAULT_VERSION } from "../../utils/constants/cdn.js";
18
+ import { readLimitedCrossProjectSource } from "./cross-project-source-limit.js";
18
19
  const logger = serverLogger.component("module-server");
19
20
  /**
20
21
  * Embedded polyfills for compiled Deno binaries.
@@ -600,5 +601,14 @@ async function fetchCrossProjectSource(projectRef, filePath) {
600
601
  });
601
602
  return null;
602
603
  }
603
- return response.text();
604
+ try {
605
+ return await readLimitedCrossProjectSource(response, registryUrl);
606
+ }
607
+ catch (error) {
608
+ logger.warn("Cross-project source too large", {
609
+ registryUrl,
610
+ error: error instanceof Error ? error.message : String(error),
611
+ });
612
+ return null;
613
+ }
604
614
  }
@@ -36,9 +36,11 @@ export declare class OAuthProvider {
36
36
  export declare class OAuthService extends OAuthProvider {
37
37
  protected serviceConfig: OAuthServiceConfig;
38
38
  protected tokenStore?: TokenStore;
39
+ private refreshPromises;
39
40
  constructor(config: OAuthServiceConfig, tokenStore?: TokenStore, envReader?: EnvReader);
40
41
  get serviceId(): string;
41
42
  get apiBaseUrl(): string;
43
+ private refreshKey;
42
44
  createAuthorizationUrl(options?: AuthorizationUrlOptions): Promise<{
43
45
  url: string;
44
46
  state: OAuthState;
@@ -51,6 +53,7 @@ export declare class OAuthService extends OAuthProvider {
51
53
  * tokens. See VULN-AUTH-2.
52
54
  */
53
55
  getAccessToken(userId: string): Promise<string | null>;
56
+ private refreshAndStoreAccessToken;
54
57
  /**
55
58
  * Resolve `endpoint` against `apiBaseUrl`, validating that absolute URLs
56
59
  * share the configured origin.
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/providers/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAarB,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAuB5D,gCAAgC;AAChC,qBAAa,aAAa;IACxB,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACtC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;gBAEnB,MAAM,EAAE,mBAAmB,EAAE,SAAS,GAAE,SAAkB;IAKtE,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,OAAO;IAIjB,sBAAsB,CAC1B,OAAO,GAAE,uBAAuB,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACnE,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IA0C9C,OAAO,CAAC,iBAAiB;IAazB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;YA0CZ,gBAAgB;IAe9B,OAAO,CAAC,4BAA4B;YAQtB,aAAa;IAyCrB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA+BzE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBjE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBnD;AAED,+BAA+B;AAC/B,qBAAa,YAAa,SAAQ,aAAa;IAC7C,SAAS,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC5C,SAAS,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;gBAEtB,MAAM,EAAE,kBAAkB,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,SAAS;IAMtF,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEQ,sBAAsB,CAC7B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAO9C;;;;;;OAMG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmB5D;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAuBpB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;CA+BxF"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/providers/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAarB,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAuB5D,gCAAgC;AAChC,qBAAa,aAAa;IACxB,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACtC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;gBAEnB,MAAM,EAAE,mBAAmB,EAAE,SAAS,GAAE,SAAkB;IAKtE,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,OAAO;IAIjB,sBAAsB,CAC1B,OAAO,GAAE,uBAAuB,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACnE,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IA0C9C,OAAO,CAAC,iBAAiB;IAazB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;YA0CZ,gBAAgB;IAe9B,OAAO,CAAC,4BAA4B;YAQtB,aAAa;IAyCrB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgCzE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBjE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBnD;AAED,+BAA+B;AAC/B,qBAAa,YAAa,SAAQ,aAAa;IAC7C,SAAS,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC5C,SAAS,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IAClC,OAAO,CAAC,eAAe,CAA6C;gBAExD,MAAM,EAAE,kBAAkB,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,SAAS;IAMtF,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,OAAO,CAAC,UAAU;IAIT,sBAAsB,CAC7B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAO9C;;;;;;OAMG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAyB9C,0BAA0B;IAcxC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAuBpB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;CA+BxF"}
@@ -183,7 +183,9 @@ export class OAuthProvider {
183
183
  return {
184
184
  success: false,
185
185
  error: "OAuth not configured",
186
- errorDescription: `Missing ${this.config.clientIdEnvVar} or ${this.config.clientSecretEnvVar}`,
186
+ // Don't leak internal env var names to the caller; this result can
187
+ // propagate to HTTP responses via OAuthService.
188
+ errorDescription: "OAuth provider credentials are not configured",
187
189
  };
188
190
  }
189
191
  const body = new URLSearchParams({
@@ -231,6 +233,7 @@ export class OAuthProvider {
231
233
  export class OAuthService extends OAuthProvider {
232
234
  serviceConfig;
233
235
  tokenStore;
236
+ refreshPromises = new Map();
234
237
  constructor(config, tokenStore, envReader) {
235
238
  super(config, envReader);
236
239
  this.serviceConfig = config;
@@ -242,6 +245,9 @@ export class OAuthService extends OAuthProvider {
242
245
  get apiBaseUrl() {
243
246
  return this.serviceConfig.apiBaseUrl;
244
247
  }
248
+ refreshKey(userId) {
249
+ return JSON.stringify([this.serviceId, userId]);
250
+ }
245
251
  createAuthorizationUrl(options = {}) {
246
252
  return super.createAuthorizationUrl({
247
253
  ...options,
@@ -264,7 +270,23 @@ export class OAuthService extends OAuthProvider {
264
270
  return tokens.accessToken;
265
271
  if (!tokens.refreshToken)
266
272
  return null;
267
- const result = await this.refreshTokens(tokens.refreshToken);
273
+ const key = this.refreshKey(userId);
274
+ const existingRefresh = this.refreshPromises.get(key);
275
+ if (existingRefresh)
276
+ return existingRefresh;
277
+ const refreshPromise = this.refreshAndStoreAccessToken(userId, tokens.refreshToken);
278
+ this.refreshPromises.set(key, refreshPromise);
279
+ try {
280
+ return await refreshPromise;
281
+ }
282
+ finally {
283
+ if (this.refreshPromises.get(key) === refreshPromise) {
284
+ this.refreshPromises.delete(key);
285
+ }
286
+ }
287
+ }
288
+ async refreshAndStoreAccessToken(userId, refreshToken) {
289
+ const result = await this.refreshTokens(refreshToken);
268
290
  if (!result.success || !result.tokens)
269
291
  return null;
270
292
  if (!this.tokenStore) {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-input-status.d.ts","sourceRoot":"","sources":["../../../../src/src/provider/runtime-loader/tool-input-status.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,+BAA+B,OAAQ,CAAC;AAErD,KAAK,uBAAuB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAEnE,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;CAC5C,CAAC;AAOF,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAexE;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC7C,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GAClB,KAAK,CAAC;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,eAAe,CAAA;KAAE,CAAA;CAAE,CAAC,CAsBjG;AAED,6CAA6C;AAC7C,wBAAuB,8BAA8B,CACnD,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAC9B,WAAW,SAAkC,GAC5C,aAAa,CAAC,OAAO,CAAC,CAkLxB"}
1
+ {"version":3,"file":"tool-input-status.d.ts","sourceRoot":"","sources":["../../../../src/src/provider/runtime-loader/tool-input-status.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,+BAA+B,OAAQ,CAAC;AAErD,KAAK,uBAAuB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAEnE,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;CAC5C,CAAC;AAOF,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAexE;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC7C,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GAClB,KAAK,CAAC;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,eAAe,CAAA;KAAE,CAAA;CAAE,CAAC,CAsBjG;AAED,6CAA6C;AAC7C,wBAAuB,8BAA8B,CACnD,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAC9B,WAAW,SAAkC,GAC5C,aAAa,CAAC,OAAO,CAAC,CA2LxB"}
@@ -137,14 +137,22 @@ export async function* withToolInputStatusTransitions(stream, thresholdMs = TOOL
137
137
  .sort((left, right) => left - right)[0] ?? null;
138
138
  if (nextDueAt !== null) {
139
139
  let timeoutId = null;
140
- const timeoutResult = await Promise.race([
141
- nextPartPromise.then((result) => ({ kind: "part", result })),
142
- new Promise((resolve) => {
143
- timeoutId = dntShim.setTimeout(() => resolve({ kind: "timeout" }), Math.max(0, nextDueAt - Date.now()));
144
- }),
145
- ]);
146
- if (timeoutId !== null) {
147
- clearTimeout(timeoutId);
140
+ // Clear the timer in finally so it is released even when the race
141
+ // rejects (iterator error) or the generator is abandoned mid-await
142
+ // (consumer break/return), not just on the happy path.
143
+ let timeoutResult;
144
+ try {
145
+ timeoutResult = await Promise.race([
146
+ nextPartPromise.then((result) => ({ kind: "part", result })),
147
+ new Promise((resolve) => {
148
+ timeoutId = dntShim.setTimeout(() => resolve({ kind: "timeout" }), Math.max(0, nextDueAt - Date.now()));
149
+ }),
150
+ ]);
151
+ }
152
+ finally {
153
+ if (timeoutId !== null) {
154
+ clearTimeout(timeoutId);
155
+ }
148
156
  }
149
157
  if (timeoutResult.kind === "timeout") {
150
158
  const readyResult = await readPartIfReady();
@@ -1 +1 @@
1
- {"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/context/render-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAEhF,OAAO,EAIL,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,2GAA2G;IAC3G,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA4Cf;AAaD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA8Bf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,eAAO,MAAM,aAAa,4BAAsB,CAAC;AAEjD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAExE"}
1
+ {"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/context/render-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAEhF,OAAO,EAIL,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,2GAA2G;IAC3G,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA4Cf;AAoBD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,0BAA0B,GACnC,aAAa,CA8Bf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,eAAO,MAAM,aAAa,4BAAsB,CAAC;AAEjD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAExE"}
@@ -40,8 +40,14 @@ export function createRenderContext(ctx, options) {
40
40
  function getReleaseKey(isLocal, environment, branch, releaseId) {
41
41
  if (isLocal)
42
42
  return branch ?? "main";
43
- if (environment === "production")
43
+ if (environment === "production") {
44
+ if (!releaseId) {
45
+ throw INVALID_ARGUMENT.create({
46
+ detail: "Production requires releaseId for cache isolation",
47
+ });
48
+ }
44
49
  return releaseId;
50
+ }
45
51
  return branch ?? "main";
46
52
  }
47
53
  export function createRenderContextFromEnriched(enriched, options) {
@@ -3,6 +3,8 @@ import type { RuntimeAdapter } from "../../../platform/adapters/base.js";
3
3
  export type ResolvedModuleDependency = {
4
4
  full: string;
5
5
  path: string;
6
+ start: number;
7
+ end: number;
6
8
  relativePath: string;
7
9
  depFilePath: string | null;
8
10
  isLocalLib: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/dependency-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AASzE,sEAAsE;AACtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AAgFD,yEAAyE;AACzE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuBrC;AAED,2EAA2E;AAC3E,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,2BAA2B,EAAE,GAC7C,MAAM,CAMR"}
1
+ {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/dependency-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAczE,sEAAsE;AACtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AAgGD,yEAAyE;AACzE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuBrC;AAED,2EAA2E;AAC3E,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,2BAA2B,EAAE,GAC7C,MAAM,CAQR"}
@@ -1,16 +1,25 @@
1
1
  import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
2
2
  import { parallelMap, rendererLogger } from "../../../utils/index.js";
3
+ import { findStaticImportFromSpans, replaceSourceSpans, } from "../../../transforms/mdx/esm-module-loader/utils/source-spans.js";
3
4
  import { findSourceFile } from "../file-resolver/index.js";
4
5
  const logger = rendererLogger.component("module-loader");
5
6
  function collectAliasImports(fileContent) {
6
- return [...fileContent.matchAll(/from\s+["'](@\/[^"']+)["']/g)].map((m) => ({
7
- full: m[0],
8
- path: m[1] ?? "",
7
+ return findStaticImportFromSpans(fileContent, (specifier) => specifier.startsWith("@/") ? specifier : null).map(({ original, path, start, end }) => ({
8
+ full: original,
9
+ path,
10
+ start,
11
+ end,
9
12
  }));
10
13
  }
11
14
  function collectRelativeImports(fileContent, fileDir) {
12
- return [...fileContent.matchAll(/from\s+["'](\.\.?\/[^"']+)["']/g)]
13
- .map((m) => ({ full: m[0], path: m[1] ?? "", fromDir: fileDir }))
15
+ return findStaticImportFromSpans(fileContent, (specifier) => specifier.match(/^(\.\.?\/[^?]+)(?:\?.*)?$/)?.[1])
16
+ .map(({ original, path, start, end }) => ({
17
+ full: original,
18
+ path,
19
+ fromDir: fileDir,
20
+ start,
21
+ end,
22
+ }))
14
23
  // Ignore already-transformed file:// imports.
15
24
  .filter((imp) => !imp.path.includes("file://"));
16
25
  }
@@ -56,6 +65,8 @@ async function resolveRelativeImport(imp, adapter) {
56
65
  return {
57
66
  full: imp.full,
58
67
  path: imp.path,
68
+ start: imp.start,
69
+ end: imp.end,
59
70
  relativePath: imp.path,
60
71
  depFilePath,
61
72
  isLocalLib: false,
@@ -79,9 +90,11 @@ export async function resolveModuleDependencies(input) {
79
90
  }
80
91
  /** Rewrites resolved local imports to their transformed temp file URLs. */
81
92
  export function rewriteResolvedDependencyImports(fileContent, transformedDeps) {
82
- let rewritten = fileContent;
83
- for (const dep of transformedDeps) {
84
- rewritten = rewritten.replace(dep.full, `from "file://${dep.depTempPath}"`);
85
- }
86
- return rewritten;
93
+ const replacements = transformedDeps.map((dep) => ({
94
+ start: dep.start,
95
+ end: dep.end,
96
+ expected: dep.full,
97
+ replacement: `from "file://${dep.depTempPath}"`,
98
+ }));
99
+ return replaceSourceSpans(fileContent, replacements);
87
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"renderer-concurrency.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer-concurrency.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,oEAAoE,CAAC;AAQ/F;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAA8C,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QACC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAS/C;;;;GAIG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IA+BhD,OAAO,CAAC,OAAO;IASf,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF;AAYD,eAAO,MAAM,eAAe,WAE1B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC;AA8B7D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAef"}
1
+ {"version":3,"file":"renderer-concurrency.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer-concurrency.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,oEAAoE,CAAC;AAQ/F;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAA8C,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QACC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAS/C;;;;GAIG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IA+BhD,OAAO,CAAC,OAAO;IASf,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF;AAYD,eAAO,MAAM,eAAe,WAE1B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC;AA8B7D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAwBf"}
@@ -154,17 +154,24 @@ export async function acquireProjectSlot(projectId) {
154
154
  export async function releaseProjectSlot(projectId) {
155
155
  if (RENDER_PER_PROJECT_LIMIT <= 0)
156
156
  return;
157
- const release = await acquireProjectLock(projectId);
157
+ const mutex = getProjectMutex(projectId);
158
+ const release = await mutex.acquire(LOCK_TIMEOUT_MS);
159
+ let deleteIdleMutex = false;
158
160
  try {
159
161
  const current = projectRenderCounts.get(projectId) ?? 0;
160
162
  if (current <= 1) {
161
163
  projectRenderCounts.delete(projectId);
162
- projectMutexes.delete(projectId);
164
+ deleteIdleMutex = mutex.waiting === 0;
163
165
  return;
164
166
  }
165
167
  projectRenderCounts.set(projectId, current - 1);
166
168
  }
167
169
  finally {
168
170
  release();
171
+ if (deleteIdleMutex &&
172
+ !projectRenderCounts.has(projectId) &&
173
+ projectMutexes.get(projectId) === mutex) {
174
+ projectMutexes.delete(projectId);
175
+ }
169
176
  }
170
177
  }
@@ -1,10 +1,6 @@
1
1
  /**
2
- * Worker Permission Builder
3
- *
4
- * Builds scoped Deno Worker permissions for per-project isolation.
5
- * Each project worker gets the minimum required permissions.
6
- *
7
- * @module security/sandbox/worker-permissions
2
+ * Deno Worker permission object.
3
+ * See: https://docs.deno.com/runtime/fundamentals/permissions/
8
4
  */
9
5
  export interface WorkerPermissions {
10
6
  read: string[] | boolean;
@@ -15,6 +11,12 @@ export interface WorkerPermissions {
15
11
  ffi: boolean;
16
12
  sys: boolean;
17
13
  }
14
+ interface WorkerPermissionOptions {
15
+ /** Override for tests that need to exercise compiled-binary behavior. */
16
+ isCompiledBinary?: boolean;
17
+ /** Override for tests that need deterministic compiled-binary support paths. */
18
+ compiledReadPaths?: string[];
19
+ }
18
20
  /**
19
21
  * Build scoped permissions for a project worker.
20
22
  *
@@ -26,5 +28,6 @@ export interface WorkerPermissions {
26
28
  * - ffi: denied (no native code from user code)
27
29
  * - sys: denied (no system info access from user code)
28
30
  */
29
- export declare function buildWorkerPermissions(readPaths: string[]): WorkerPermissions;
31
+ export declare function buildWorkerPermissions(readPaths: string[], options?: WorkerPermissionOptions): WorkerPermissions;
32
+ export {};
30
33
  //# sourceMappingURL=worker-permissions.d.ts.map