History

Add TypeScript typechecking for LLM-generated code before execution

Use openapi-typescript for high-fidelity JSON Schema → TypeScript conversion in tool type signatures. Typecheck code against tool declarations using the TS compiler API before creating tasks, so type errors are caught early and returned to the agent without executing. Includes 24 tests for the typechecker.

Rhys Sullivan committed 9 months ago

Commit f153aeb1 parent 91abe7a6 files · +549 −24Browse files

Unified · Split

6 files
  1. executor/apps/server/package.json +2 −1
  2. executor/apps/server/src/mcp-server.ts +33 −11
  3. executor/apps/server/src/tool-sources.ts +53 −8
  4. executor/apps/server/src/typechecker.test.ts +250 −0
  5. executor/apps/server/src/typechecker.ts +174 −0
  6. executor/bun.lock +37 −4
executor/apps/server/package.json+2−1
@@ -9,6 +9,7 @@ · 8 unmodified lines
9 "@vercel/sandbox": "latest",9 "@vercel/sandbox": "latest",
10 "convex": "latest",10 "convex": "latest",
11 "elysia": "^1.4.22",11 "elysia": "^1.4.22",
12 "openapi-typescript": "^7.10.1",
12 "zod": "^4.3.6"13 "zod": "^4.3.6"
13 },14 },
14 "scripts": {15 "scripts": {
@@ -21,6 +22,6 @@ · 6 unmodified lines
21 },22 },
22 "devDependencies": {23 "devDependencies": {
23 "@types/bun": "latest",24 "@types/bun": "latest",
24 "typescript": "latest"25 "typescript": "^5.9.3"
25 }26 }
26}27}
executor/apps/server/src/mcp-server.ts+33−11
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; · 1 unmodified line
2import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";2import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
3import { z } from "zod";3import { z } from "zod";
4import { getTaskTerminalState } from "./service";4import { getTaskTerminalState } from "./service";
5import { generateToolDeclarations, generateToolInventory, typecheckCode } from "./typechecker";
5import type { LiveTaskEvent } from "./events";6import type { LiveTaskEvent } from "./events";
6import type { AnonymousContext, CreateTaskInput, TaskRecord, ToolDescriptor } from "./types";7import type { AnonymousContext, CreateTaskInput, TaskRecord, ToolDescriptor } from "./types";
7 8
@@ -113,18 +114,9 @@ function waitForTerminalTask( · 105 unmodified lines
113 114
114function buildRunCodeDescription(tools?: ToolDescriptor[]): string {115function buildRunCodeDescription(tools?: ToolDescriptor[]): string {
115 const base =116 const base =
116 "Execute TypeScript code in a sandboxed runtime. The code has access to a `tools` object with typed methods for calling external services. Use `return` to return a value. Waits for completion and returns stdout/stderr.";117 "Execute TypeScript code in a sandboxed runtime. The code has access to a `tools` object with typed methods for calling external services. Use `return` to return a value. Waits for completion and returns stdout/stderr. Code is typechecked before execution — type errors are returned without running.";
117 118
118 if (!tools || tools.length === 0) return base;119 return base + generateToolInventory(tools ?? []);
119
120 const toolLines = tools.map((t) => {
121 const args = t.argsType ?? "unknown";
122 const returns = t.returnsType ?? "unknown";
123 const approval = t.approval === "required" ? " [approval required]" : "";
124 return ` - tools.${t.path}(${args}): ${returns}${approval} — ${t.description}`;
125 });
126
127 return `${base}\n\nAvailable tools in the sandbox:\n${toolLines.join("\n")}`;
128}120}
129 121
130// ---------------------------------------------------------------------------122// ---------------------------------------------------------------------------
@@ -177,6 +169,36 @@ function createRunCodeTool( · 46 unmodified lines
177 };169 };
178 }170 }
179 171
172 // Typecheck code before execution — get tool inventory for declarations
173 const toolsForContext = await service.listTools({
174 workspaceId: context.workspaceId,
175 actorId: context.actorId,
176 clientId: context.clientId,
177 });
178 const declarations = generateToolDeclarations(toolsForContext);
179 const typecheck = typecheckCode(input.code, declarations);
180
181 if (!typecheck.ok) {
182 const errorText = [
183 "TypeScript type errors in generated code:",
184 "",
185 ...typecheck.errors.map((e) => ` ${e}`),
186 "",
187 "Fix the type errors and try again.",
188 ].join("\n");
189
190 return {
191 content: [textContent(errorText)],
192 isError: true,
193 structuredContent: {
194 typecheckErrors: typecheck.errors,
195 workspaceId: context.workspaceId,
196 actorId: context.actorId,
197 sessionId: context.sessionId,
198 },
199 };
200 }
201
180 const created = await service.createTask({202 const created = await service.createTask({
181 code: input.code,203 code: input.code,
182 timeoutMs: input.timeoutMs,204 timeoutMs: input.timeoutMs,
executor/apps/server/src/tool-sources.ts+53−8
@@ -2,6 +2,7 @@ import SwaggerParser from "@apidevtools/swagger-parser"; · 1 unmodified line
2import { Client } from "@modelcontextprotocol/sdk/client/index.js";2import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";3import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
4import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";4import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
5import { astToString, transformSchemaObject } from "openapi-typescript";
5import type { ToolApprovalMode, ToolCredentialSpec, ToolDefinition } from "./types";6import type { ToolApprovalMode, ToolCredentialSpec, ToolDefinition } from "./types";
6 7
7type JsonSchema = Record<string, unknown>;8type JsonSchema = Record<string, unknown>;
@@ -65,7 +66,51 @@ function sanitizeSegment(value: string): string { · 57 unmodified lines
65 return cleaned.length > 0 ? cleaned : "default";66 return cleaned.length > 0 ? cleaned : "default";
66}67}
67 68
68function jsonSchemaTypeHint(schema: unknown, depth = 0): string {69// openapi-typescript context for standalone schema conversion
70function makeTransformCtx() {
71 return {
72 additionalProperties: false,
73 alphabetize: false,
74 arrayLength: false,
75 defaultNonNullable: true,
76 discriminators: { refsHandled: [] as string[], objects: {} as Record<string, unknown> },
77 emptyObjectsUnknown: false,
78 enum: false,
79 enumValues: false,
80 excludeDeprecated: false,
81 exportType: false,
82 immutable: false,
83 indentLv: 0,
84 pathParamsAsTypes: false,
85 postTransform: undefined,
86 propertiesRequiredByDefault: false,
87 redoc: undefined,
88 silent: true,
89 resolve(_ref: string) { return undefined as unknown; },
90 };
91}
92
93/**
94 * Convert a JSON Schema to a TypeScript type string using openapi-typescript.
95 * Handles allOf, oneOf, enums, nullable, additionalProperties, etc.
96 * Falls back to the simple hand-rolled version on error.
97 */
98function jsonSchemaToTypeString(schema: unknown): string {
99 if (!schema || typeof schema !== "object") return "unknown";
100 try {
101 const node = transformSchemaObject(schema as never, {
102 path: "#",
103 ctx: makeTransformCtx() as never,
104 });
105 const result = astToString(node).trim();
106 return result || "unknown";
107 } catch {
108 return jsonSchemaTypeHintFallback(schema);
109 }
110}
111
112/** Simple fallback for when openapi-typescript can't handle the schema */
113function jsonSchemaTypeHintFallback(schema: unknown, depth = 0): string {
69 if (!schema || typeof schema !== "object") return "unknown";114 if (!schema || typeof schema !== "object") return "unknown";
70 if (depth > 4) return "unknown";115 if (depth > 4) return "unknown";
71 116
@@ -77,12 +122,12 @@ function jsonSchemaTypeHint(schema: unknown, depth = 0): string { · 5 unmodified lines
77 122
78 const oneOf = Array.isArray(shape.oneOf) ? shape.oneOf : undefined;123 const oneOf = Array.isArray(shape.oneOf) ? shape.oneOf : undefined;
79 if (oneOf && oneOf.length > 0) {124 if (oneOf && oneOf.length > 0) {
80 return oneOf.map((entry) => jsonSchemaTypeHint(entry, depth + 1)).join(" | ");125 return oneOf.map((entry) => jsonSchemaTypeHintFallback(entry, depth + 1)).join(" | ");
81 }126 }
82 127
83 const anyOf = Array.isArray(shape.anyOf) ? shape.anyOf : undefined;128 const anyOf = Array.isArray(shape.anyOf) ? shape.anyOf : undefined;
84 if (anyOf && anyOf.length > 0) {129 if (anyOf && anyOf.length > 0) {
85 return anyOf.map((entry) => jsonSchemaTypeHint(entry, depth + 1)).join(" | ");130 return anyOf.map((entry) => jsonSchemaTypeHintFallback(entry, depth + 1)).join(" | ");
86 }131 }
87 132
88 const type = typeof shape.type === "string" ? shape.type : undefined;133 const type = typeof shape.type === "string" ? shape.type : undefined;
@@ -91,7 +136,7 @@ function jsonSchemaTypeHint(schema: unknown, depth = 0): string { · 2 unmodified lines
91 }136 }
92 137
93 if (type === "array") {138 if (type === "array") {
94 return `${jsonSchemaTypeHint(shape.items, depth + 1)}[]`;139 return `${jsonSchemaTypeHintFallback(shape.items, depth + 1)}[]`;
95 }140 }
96 141
97 const props = toObject(shape.properties);142 const props = toObject(shape.properties);
@@ -104,7 +149,7 @@ function jsonSchemaTypeHint(schema: unknown, depth = 0): string { · 6 unmodified lines
104 }149 }
105 const inner = propEntries150 const inner = propEntries
106 .slice(0, 12)151 .slice(0, 12)
107 .map(([key, value]) => `${key}${required.has(key) ? "" : "?"}: ${jsonSchemaTypeHint(value, depth + 1)}`)152 .map(([key, value]) => `${key}${required.has(key) ? "" : "?"}: ${jsonSchemaTypeHintFallback(value, depth + 1)}`)
108 .join("; ");153 .join("; ");
109 return `{ ${inner} }`;154 return `{ ${inner} }`;
110 }155 }
@@ -191,7 +236,7 @@ async function loadMcpTools(config: McpToolSourceConfig): Promise<ToolDefinition · 80 unmodified lines
191 approval: config.overrides?.[toolName]?.approval ?? config.defaultApproval ?? "auto",236 approval: config.overrides?.[toolName]?.approval ?? config.defaultApproval ?? "auto",
192 description: String(tool.description ?? `MCP tool ${toolName}`),237 description: String(tool.description ?? `MCP tool ${toolName}`),
193 metadata: {238 metadata: {
194 argsType: jsonSchemaTypeHint(inputSchema),239 argsType: jsonSchemaToTypeString(inputSchema),
195 returnsType: "unknown",240 returnsType: "unknown",
196 },241 },
197 run: async (input: unknown) => {242 run: async (input: unknown) => {
@@ -390,8 +435,8 @@ async function loadOpenApiTools(config: OpenApiToolSourceConfig): Promise<ToolDe · 192 unmodified lines
390 approval,435 approval,
391 description: String(operation.summary ?? operation.description ?? `${method.toUpperCase()} ${pathTemplate}`),436 description: String(operation.summary ?? operation.description ?? `${method.toUpperCase()} ${pathTemplate}`),
392 metadata: {437 metadata: {
393 argsType: jsonSchemaTypeHint(combinedSchema),438 argsType: jsonSchemaToTypeString(combinedSchema),
394 returnsType: jsonSchemaTypeHint(responseSchema),439 returnsType: jsonSchemaToTypeString(responseSchema),
395 },440 },
396 credential: credentialSpec,441 credential: credentialSpec,
397 run: async (input: unknown, context) => {442 run: async (input: unknown, context) => {
executor/apps/server/src/typechecker.test.ts+250−0
@@ -0,0 +1,250 @@
1import { test, expect, describe } from "bun:test";
2import { generateToolDeclarations, generateToolInventory, typecheckCode, type TypecheckResult } from "./typechecker";
3import type { ToolDescriptor } from "./types";
4
5// ---------------------------------------------------------------------------
6// Test fixtures
7// ---------------------------------------------------------------------------
8
9const MATH_TOOL: ToolDescriptor = {
10 path: "math.add",
11 description: "Add two numbers",
12 approval: "auto",
13 argsType: "{ a: number; b: number }",
14 returnsType: "{ result: number }",
15};
16
17const ADMIN_TOOL: ToolDescriptor = {
18 path: "admin.send_announcement",
19 description: "Send an announcement",
20 approval: "required",
21 argsType: "{ message: string; channel?: string }",
22 returnsType: "{ sent: boolean }",
23};
24
25const FLAT_TOOL: ToolDescriptor = {
26 path: "get_time",
27 description: "Get current time",
28 approval: "auto",
29 argsType: "{}",
30 returnsType: "{ iso: string; unix: number }",
31};
32
33const ALL_TOOLS = [MATH_TOOL, ADMIN_TOOL, FLAT_TOOL];
34
35// ---------------------------------------------------------------------------
36// generateToolDeclarations
37// ---------------------------------------------------------------------------
38
39describe("generateToolDeclarations", () => {
40 test("empty tools produces empty tools object", () => {
41 const result = generateToolDeclarations([]);
42 expect(result).toBe("declare const tools: {\n\n};");
43 });
44
45 test("flat tool (no dots in path beyond single segment)", () => {
46 const result = generateToolDeclarations([FLAT_TOOL]);
47 expect(result).toContain("get_time(input: {}): Promise<{ iso: string; unix: number }>;");
48 });
49
50 test("nested tool (math.add)", () => {
51 const result = generateToolDeclarations([MATH_TOOL]);
52 expect(result).toContain("math: {");
53 expect(result).toContain("add(input: { a: number; b: number }): Promise<{ result: number }>;");
54 });
55
56 test("multiple tools produce correct nesting", () => {
57 const result = generateToolDeclarations(ALL_TOOLS);
58 // math namespace
59 expect(result).toContain("math: {");
60 expect(result).toContain("add(input: { a: number; b: number }): Promise<{ result: number }>;");
61 // admin namespace
62 expect(result).toContain("admin: {");
63 expect(result).toContain("send_announcement(input: { message: string; channel?: string }): Promise<{ sent: boolean }>;");
64 // flat
65 expect(result).toContain("get_time(input: {}): Promise<{ iso: string; unix: number }>;");
66 });
67
68 test("missing argsType defaults to Record<string, unknown>", () => {
69 const tool: ToolDescriptor = {
70 path: "foo.bar",
71 description: "test",
72 approval: "auto",
73 };
74 const result = generateToolDeclarations([tool]);
75 expect(result).toContain("bar(input: Record<string, unknown>): Promise<unknown>;");
76 });
77
78 test("missing returnsType defaults to unknown", () => {
79 const tool: ToolDescriptor = {
80 path: "baz",
81 description: "test",
82 approval: "auto",
83 argsType: "{ x: number }",
84 };
85 const result = generateToolDeclarations([tool]);
86 expect(result).toContain("baz(input: { x: number }): Promise<unknown>;");
87 });
88});
89
90// ---------------------------------------------------------------------------
91// generateToolInventory
92// ---------------------------------------------------------------------------
93
94describe("generateToolInventory", () => {
95 test("empty tools returns empty string", () => {
96 expect(generateToolInventory([])).toBe("");
97 });
98
99 test("includes tool paths and type signatures", () => {
100 const result = generateToolInventory(ALL_TOOLS);
101 expect(result).toContain("tools.math.add(input: { a: number; b: number }): Promise<{ result: number }>");
102 expect(result).toContain("tools.admin.send_announcement(input: { message: string; channel?: string }): Promise<{ sent: boolean }>");
103 expect(result).toContain("tools.get_time(input: {}): Promise<{ iso: string; unix: number }>");
104 });
105
106 test("shows [approval required] for required-approval tools", () => {
107 const result = generateToolInventory(ALL_TOOLS);
108 expect(result).toContain("[approval required]");
109 // math.add is auto — should NOT have the tag
110 const mathLine = result.split("\n").find((l) => l.includes("tools.math.add"));
111 expect(mathLine).not.toContain("[approval required]");
112 // admin.send_announcement is required — should have the tag
113 const adminLine = result.split("\n").find((l) => l.includes("tools.admin.send_announcement"));
114 expect(adminLine).toContain("[approval required]");
115 });
116
117 test("includes descriptions", () => {
118 const result = generateToolInventory(ALL_TOOLS);
119 expect(result).toContain("Add two numbers");
120 expect(result).toContain("Send an announcement");
121 expect(result).toContain("Get current time");
122 });
123});
124
125// ---------------------------------------------------------------------------
126// typecheckCode
127// ---------------------------------------------------------------------------
128
129describe("typecheckCode", () => {
130 const declarations = generateToolDeclarations(ALL_TOOLS);
131
132 test("valid code passes", () => {
133 const result = typecheckCode("return 40 + 2;", declarations);
134 expect(result.ok).toBe(true);
135 expect(result.errors).toHaveLength(0);
136 });
137
138 test("valid tool call passes", () => {
139 const result = typecheckCode(
140 'const sum = await tools.math.add({ a: 1, b: 2 }); return sum.result;',
141 declarations,
142 );
143 expect(result.ok).toBe(true);
144 expect(result.errors).toHaveLength(0);
145 });
146
147 test("valid async code with await", () => {
148 const result = typecheckCode(
149 `const time = await tools.get_time({});
150 console.log(time.iso);
151 return time.unix;`,
152 declarations,
153 );
154 expect(result.ok).toBe(true);
155 });
156
157 test("console.log is available", () => {
158 const result = typecheckCode('console.log("hello"); return 1;', declarations);
159 expect(result.ok).toBe(true);
160 });
161
162 test("setTimeout is available", () => {
163 const result = typecheckCode(
164 'const id = setTimeout(() => {}, 100); clearTimeout(id); return 1;',
165 declarations,
166 );
167 expect(result.ok).toBe(true);
168 });
169
170 test("wrong argument types produce errors", () => {
171 const result = typecheckCode(
172 'const sum = await tools.math.add({ a: "not a number", b: 2 });',
173 declarations,
174 );
175 expect(result.ok).toBe(false);
176 expect(result.errors.length).toBeGreaterThan(0);
177 expect(result.errors.some((e) => e.includes("string") || e.includes("number"))).toBe(true);
178 });
179
180 test("missing required argument produces errors", () => {
181 const result = typecheckCode(
182 "const sum = await tools.math.add({ a: 1 });",
183 declarations,
184 );
185 expect(result.ok).toBe(false);
186 expect(result.errors.some((e) => e.includes("b"))).toBe(true);
187 });
188
189 test("non-existent tool produces errors", () => {
190 const result = typecheckCode(
191 "const result = await tools.nonexistent.doStuff({});",
192 declarations,
193 );
194 expect(result.ok).toBe(false);
195 expect(result.errors.some((e) => e.includes("nonexistent"))).toBe(true);
196 });
197
198 test("accessing wrong property on result produces errors", () => {
199 const result = typecheckCode(
200 "const sum = await tools.math.add({ a: 1, b: 2 }); return sum.nonexistent;",
201 declarations,
202 );
203 expect(result.ok).toBe(false);
204 expect(result.errors.some((e) => e.includes("nonexistent"))).toBe(true);
205 });
206
207 test("type errors have adjusted line numbers", () => {
208 const code = `const x = 1;
209const y = "hello";
210const z: number = y;`;
211 const result = typecheckCode(code, declarations);
212 expect(result.ok).toBe(false);
213 // The error should reference line 3 of the user code, not the wrapper
214 expect(result.errors.some((e) => e.startsWith("Line 3:"))).toBe(true);
215 });
216
217 test("empty declarations (no tools) still works for plain code", () => {
218 const emptyDecl = generateToolDeclarations([]);
219 const result = typecheckCode("return 42;", emptyDecl);
220 expect(result.ok).toBe(true);
221 });
222
223 test("complex valid code with multiple tool calls", () => {
224 const code = `
225const sum = await tools.math.add({ a: 10, b: 20 });
226const announcement = await tools.admin.send_announcement({ message: "Sum is " + sum.result });
227const time = await tools.get_time({});
228console.log(time.iso);
229return { sum: sum.result, sent: announcement.sent, time: time.unix };
230`;
231 const result = typecheckCode(code, declarations);
232 expect(result.ok).toBe(true);
233 });
234
235 test("optional parameter can be omitted", () => {
236 const result = typecheckCode(
237 'const r = await tools.admin.send_announcement({ message: "hi" }); return r.sent;',
238 declarations,
239 );
240 expect(result.ok).toBe(true);
241 });
242
243 test("optional parameter can be provided", () => {
244 const result = typecheckCode(
245 'const r = await tools.admin.send_announcement({ message: "hi", channel: "general" }); return r.sent;',
246 declarations,
247 );
248 expect(result.ok).toBe(true);
249 });
250});
executor/apps/server/src/typechecker.ts+174−0
@@ -0,0 +1,174 @@
1/**
2 * TypeScript typechecker for LLM-generated code.
3 *
4 * Generates `declare const tools: { ... }` from ToolDescriptor metadata,
5 * then validates code against those declarations using the TypeScript compiler API.
6 *
7 * This runs in the executor so all MCP clients benefit from typechecking
8 * without needing their own TypeScript setup.
9 */
10
11import type { ToolDescriptor } from "./types";
12
13// ---------------------------------------------------------------------------
14// Tool declarations generation
15// ---------------------------------------------------------------------------
16
17/**
18 * Build a `declare const tools: { ... }` block from flat tool descriptors.
19 *
20 * Tool paths like "math.add" or "admin.send_announcement" are split on "."
21 * and nested into a type tree.
22 */
23export function generateToolDeclarations(tools: ToolDescriptor[]): string {
24 // Build a nested tree from flat tool paths
25 interface TreeNode {
26 children: Map<string, TreeNode>;
27 tool?: ToolDescriptor;
28 }
29
30 const root: TreeNode = { children: new Map() };
31
32 for (const tool of tools) {
33 const segments = tool.path.split(".");
34 let node = root;
35 for (let i = 0; i < segments.length; i++) {
36 const seg = segments[i];
37 if (!node.children.has(seg)) {
38 node.children.set(seg, { children: new Map() });
39 }
40 node = node.children.get(seg)!;
41 if (i === segments.length - 1) {
42 node.tool = tool;
43 }
44 }
45 }
46
47 function renderNode(node: TreeNode, indent: number): string {
48 const pad = " ".repeat(indent);
49 const lines: string[] = [];
50
51 for (const [key, child] of node.children) {
52 if (child.tool) {
53 const args = child.tool.argsType || "Record<string, unknown>";
54 const returns = child.tool.returnsType || "unknown";
55 lines.push(`${pad}${key}(input: ${args}): Promise<${returns}>;`);
56 } else {
57 lines.push(`${pad}${key}: {`);
58 lines.push(renderNode(child, indent + 1));
59 lines.push(`${pad}};`);
60 }
61 }
62
63 return lines.join("\n");
64 }
65
66 return `declare const tools: {\n${renderNode(root, 1)}\n};`;
67}
68
69/**
70 * Generate the tool inventory text for the MCP run_code description.
71 * Includes full type signatures so the LLM can write correct code.
72 */
73export function generateToolInventory(tools: ToolDescriptor[]): string {
74 if (!tools || tools.length === 0) return "";
75
76 const lines = tools.map((t) => {
77 const args = t.argsType || "Record<string, unknown>";
78 const returns = t.returnsType || "unknown";
79 const approval = t.approval === "required" ? " [approval required]" : "";
80 return ` tools.${t.path}(input: ${args}): Promise<${returns}>${approval}\n ${t.description}`;
81 });
82
83 return `\nAvailable tools in the sandbox:\n${lines.join("\n\n")}`;
84}
85
86// ---------------------------------------------------------------------------
87// TypeScript typechecking
88// ---------------------------------------------------------------------------
89
90export interface TypecheckResult {
91 readonly ok: boolean;
92 readonly errors: readonly string[];
93}
94
95/**
96 * Typecheck LLM-generated code against tool declarations.
97 *
98 * Uses the TypeScript compiler API. Returns errors with line numbers
99 * adjusted to match the original code (not the wrapper).
100 */
101export function typecheckCode(
102 code: string,
103 toolDeclarations: string,
104): TypecheckResult {
105 let ts: typeof import("typescript");
106 try {
107 ts = require("typescript");
108 } catch {
109 // TypeScript not available — skip typechecking
110 return { ok: true, errors: [] };
111 }
112
113 // Wrap the code in an async function with the tools declaration.
114 // We declare sandbox globals (console, setTimeout, etc.) ourselves since
115 // `types: []` prevents @types/node from loading.
116 const wrappedCode = [
117 toolDeclarations,
118 "declare const console: { log(...args: any[]): void; info(...args: any[]): void; warn(...args: any[]): void; error(...args: any[]): void; };",
119 "declare function setTimeout(fn: () => void, ms: number): number;",
120 "declare function clearTimeout(id: number): void;",
121 "async function __generated() {",
122 code,
123 "}",
124 ].join("\n");
125
126 const sourceFile = ts.createSourceFile(
127 "generated.ts",
128 wrappedCode,
129 ts.ScriptTarget.ESNext,
130 true,
131 ts.ScriptKind.TS,
132 );
133
134 const compilerOptions: import("typescript").CompilerOptions = {
135 target: ts.ScriptTarget.ESNext,
136 module: ts.ModuleKind.ESNext,
137 strict: true,
138 noEmit: true,
139 lib: ["lib.es2022.d.ts"],
140 types: [], // prevent automatic @types/* (e.g. @types/node) from conflicting with our sandbox declarations
141 };
142
143 const host = ts.createCompilerHost(compilerOptions);
144 const originalGetSourceFile = host.getSourceFile.bind(host);
145 host.getSourceFile = (fileName, languageVersion) => {
146 if (fileName === "generated.ts") return sourceFile;
147 return originalGetSourceFile(fileName, languageVersion);
148 };
149
150 const program = ts.createProgram(["generated.ts"], compilerOptions, host);
151 const diagnostics = program.getSemanticDiagnostics(sourceFile);
152
153 if (diagnostics.length === 0) {
154 return { ok: true, errors: [] };
155 }
156
157 // Count header lines so we can adjust line numbers
158 const headerLineCount =
159 toolDeclarations.split("\n").length + 4; // +4 for console, setTimeout, clearTimeout, function header
160
161 const errors = diagnostics.map((d) => {
162 const message = ts.flattenDiagnosticMessageText(d.messageText, "\n");
163 if (d.start !== undefined && d.file) {
164 const { line } = d.file.getLineAndCharacterOfPosition(d.start);
165 const adjustedLine = line + 1 - headerLineCount;
166 if (adjustedLine > 0) {
167 return `Line ${adjustedLine}: ${message}`;
168 }
169 }
170 return message;
171 });
172
173 return { ok: false, errors };
174}
executor/bun.lock+37−4
@@ -23,11 +23,12 @@ · 22 unmodified lines
23 "@vercel/sandbox": "latest",23 "@vercel/sandbox": "latest",
24 "convex": "latest",24 "convex": "latest",
25 "elysia": "^1.4.22",25 "elysia": "^1.4.22",
26 "openapi-typescript": "^7.10.1",
26 "zod": "^4.3.6",27 "zod": "^4.3.6",
27 },28 },
28 "devDependencies": {29 "devDependencies": {
29 "@types/bun": "latest",30 "@types/bun": "latest",
30 "typescript": "latest",31 "typescript": "^5.9.3",
31 },32 },
32 },33 },
33 "apps/web": {34 "apps/web": {
@@ -486,6 +487,12 @@ · 452 unmodified lines
486 487
487 "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],488 "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
488 489
490 "@redocly/ajv": ["@redocly/ajv@8.17.3", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-NQsbJbB/GV7JVO88ebFkMndrnuGp/dTm5/2NISeg+JGcLzTfGBJZ01+V5zD8nKBOpi/dLLNFT+Ql6IcUk8ehng=="],
491
492 "@redocly/config": ["@redocly/config@0.22.2", "", {}, "sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ=="],
493
494 "@redocly/openapi-core": ["@redocly/openapi-core@1.34.6", "", { "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.22.0", "colorette": "^1.2.0", "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "minimatch": "^5.0.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" } }, "sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw=="],
495
489 "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],496 "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
490 497
491 "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],498 "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
@@ -630,6 +637,8 @@ · 138 unmodified lines
630 637
631 "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],638 "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
632 639
640 "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
641
633 "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],642 "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
634 643
635 "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],644 "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
@@ -708,6 +717,8 @@ · 72 unmodified lines
708 717
709 "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],718 "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
710 719
720 "change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="],
721
711 "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],722 "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
712 723
713 "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],724 "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
@@ -728,6 +739,8 @@ · 14 unmodified lines
728 739
729 "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],740 "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
730 741
742 "colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="],
743
731 "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],744 "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
732 745
733 "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],746 "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
@@ -1020,6 +1033,8 @@ · 286 unmodified lines
1020 1033
1021 "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],1034 "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
1022 1035
1036 "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="],
1037
1023 "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],1038 "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
1024 1039
1025 "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],1040 "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
@@ -1118,6 +1133,8 @@ · 92 unmodified lines
1118 1133
1119 "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],1134 "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
1120 1135
1136 "js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="],
1137
1121 "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],1138 "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
1122 1139
1123 "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],1140 "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
@@ -1276,6 +1293,8 @@ · 152 unmodified lines
1276 1293
1277 "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],1294 "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
1278 1295
1296 "openapi-typescript": ["openapi-typescript@7.10.1", "", { "dependencies": { "@redocly/openapi-core": "^1.34.5", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", "supports-color": "^10.2.2", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-rBcU8bjKGGZQT4K2ekSTY2Q5veOQbVG/lTKZ49DeCyT9z62hM2Vj/LLHjDHC9W7LJG8YMHcdXpRZDqC1ojB/lw=="],
1297
1279 "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],1298 "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
1280 1299
1281 "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],1300 "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
@@ -1294,7 +1313,7 @@ · 12 unmodified lines
1294 1313
1295 "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],1314 "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
1296 1315
1297 "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],1316 "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
1298 1317
1299 "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],1318 "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],
1300 1319
@@ -1316,6 +1335,8 @@ · 15 unmodified lines
1316 1335
1317 "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],1336 "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
1318 1337
1338 "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="],
1339
1319 "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],1340 "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
1320 1341
1321 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],1342 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
@@ -1482,7 +1503,7 @@ · 160 unmodified lines
1482 1503
1483 "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],1504 "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
1484 1505
1485 "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],1506 "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
1486 1507
1487 "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],1508 "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
1488 1509
@@ -1528,7 +1549,7 @@ · 39 unmodified lines
1528 1549
1529 "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],1550 "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
1530 1551
1531 "type-fest": ["type-fest@5.4.3", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-AXSAQJu79WGc79/3e9/CR77I/KQgeY1AhNvcShIH4PTcGYyC4xv6H4R4AUOwkPS5799KlVDAu8zExeCrkGquiA=="],1552 "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
1532 1553
1533 "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],1554 "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
1534 1555
@@ -1606,6 +1627,8 @@ · 71 unmodified lines
1606 1627
1607 "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],1628 "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
1608 1629
1630 "yaml-ast-parser": ["yaml-ast-parser@0.0.43", "", {}, "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A=="],
1631
1609 "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],1632 "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
1610 1633
1611 "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],1634 "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
@@ -1636,6 +1659,8 @@ · 24 unmodified lines
1636 1659
1637 "@next/eslint-plugin-next/fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],1660 "@next/eslint-plugin-next/fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],
1638 1661
1662 "@redocly/openapi-core/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
1663
1639 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],1664 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
1640 1665
1641 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],1666 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
@@ -1660,6 +1685,8 @@ · 18 unmodified lines
1660 1685
1661 "bun-types/@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],1686 "bun-types/@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],
1662 1687
1688 "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
1689
1663 "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],1690 "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
1664 1691
1665 "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],1692 "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -1668,6 +1695,8 @@ · 2 unmodified lines
1668 1695
1669 "convex/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],1696 "convex/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
1670 1697
1698 "cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
1699
1671 "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],1700 "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
1672 1701
1673 "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],1702 "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
@@ -1692,6 +1721,8 @@ · 18 unmodified lines
1692 1721
1693 "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],1722 "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
1694 1723
1724 "msw/type-fest": ["type-fest@5.4.3", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-AXSAQJu79WGc79/3e9/CR77I/KQgeY1AhNvcShIH4PTcGYyC4xv6H4R4AUOwkPS5799KlVDAu8zExeCrkGquiA=="],
1725
1695 "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],1726 "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
1696 1727
1697 "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],1728 "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
@@ -1734,6 +1765,8 @@ · 36 unmodified lines
1734 1765
1735 "@next/eslint-plugin-next/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],1766 "@next/eslint-plugin-next/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
1736 1767
1768 "@redocly/openapi-core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
1769
1737 "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],1770 "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
1738 1771
1739 "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],1772 "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],