Compare commits

..

1 Commits

Author SHA1 Message Date
bd6284df8f docs: add information about E2B 2024-06-19 21:57:40 -04:00
52 changed files with 1001 additions and 4020 deletions

View File

@ -7,9 +7,6 @@
"": { "": {
"name": "ai", "name": "ai",
"version": "0.0.0", "version": "0.0.0",
"dependencies": {
"@anthropic-ai/sdk": "^0.27.2"
},
"devDependencies": { "devDependencies": {
"@cloudflare/vitest-pool-workers": "^0.1.0", "@cloudflare/vitest-pool-workers": "^0.1.0",
"@cloudflare/workers-types": "^4.20240512.0", "@cloudflare/workers-types": "^4.20240512.0",
@ -18,28 +15,6 @@
"wrangler": "^3.0.0" "wrangler": "^3.0.0"
} }
}, },
"node_modules/@anthropic-ai/sdk": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.27.2.tgz",
"integrity": "sha512-Q6gOx4fyHQ+NCSaVeXEKFZfoFWCR3ctUA+sK5oGB7RKUkzUvK64aYM7v1T9ekJKwn8TwRq6IGjqS31n9PbjCIA==",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7"
}
},
"node_modules/@anthropic-ai/sdk/node_modules/@types/node": {
"version": "18.19.50",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz",
"integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@cloudflare/kv-asset-handler": { "node_modules/@cloudflare/kv-asset-handler": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz", "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz",
@ -886,19 +861,11 @@
"version": "20.12.11", "version": "20.12.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz",
"integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==",
"dev": true,
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
}, },
"node_modules/@types/node-fetch": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/@types/node-forge": { "node_modules/@types/node-forge": {
"version": "1.3.11", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
@ -977,17 +944,6 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
} }
}, },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.11.3", "version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@ -1009,17 +965,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/agentkeepalive": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
"integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==",
"dependencies": {
"humanize-ms": "^1.2.1"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/ansi-styles": { "node_modules/ansi-styles": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
@ -1063,11 +1008,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1201,17 +1141,6 @@
"integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==",
"dev": true "dev": true
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "12.0.0", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
@ -1285,14 +1214,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/devalue": { "node_modules/devalue": {
"version": "4.3.3", "version": "4.3.3",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.3.tgz", "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.3.tgz",
@ -1366,14 +1287,6 @@
"@types/estree": "^1.0.0" "@types/estree": "^1.0.0"
} }
}, },
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/execa": { "node_modules/execa": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
@ -1421,36 +1334,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/form-data-encoder": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
},
"node_modules/formdata-node": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
"dependencies": {
"node-domexception": "1.0.0",
"web-streams-polyfill": "4.0.0-beta.3"
},
"engines": {
"node": ">= 12.20"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -1569,14 +1452,6 @@
"node": ">=16.17.0" "node": ">=16.17.0"
} }
}, },
"node_modules/humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"dependencies": {
"ms": "^2.0.0"
}
},
"node_modules/inflight": { "node_modules/inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -1735,25 +1610,6 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-fn": { "node_modules/mimic-fn": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@ -1819,7 +1675,8 @@
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}, },
"node_modules/mustache": { "node_modules/mustache": {
"version": "4.2.0", "version": "4.2.0",
@ -1848,43 +1705,6 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-forge": { "node_modules/node-forge": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@ -2402,11 +2222,6 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-json-schema-generator": { "node_modules/ts-json-schema-generator": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-1.5.1.tgz", "resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-1.5.1.tgz",
@ -2477,7 +2292,8 @@
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "5.26.5", "version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.2.11", "version": "5.2.11",
@ -3011,28 +2827,6 @@
} }
} }
}, },
"node_modules/web-streams-polyfill": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
"engines": {
"node": ">= 14"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -15,8 +15,5 @@
"typescript": "^5.0.4", "typescript": "^5.0.4",
"vitest": "1.3.0", "vitest": "1.3.0",
"wrangler": "^3.0.0" "wrangler": "^3.0.0"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.27.2"
} }
} }

View File

@ -1,77 +1,43 @@
import { Anthropic } from "@anthropic-ai/sdk";
export interface Env { export interface Env {
ANTHROPIC_API_KEY: string; AI: any
} }
export default { export default {
async fetch(request: Request, env: Env): Promise<Response> { async fetch(request, env): Promise<Response> {
if (request.method !== "GET") { if (request.method !== "GET") {
return new Response("Method Not Allowed", { status: 405 }); return new Response("Method Not Allowed", { status: 405 })
} }
const url = new URL(request.url); const url = new URL(request.url)
// const fileName = url.searchParams.get("fileName"); const fileName = url.searchParams.get("fileName")
// const line = url.searchParams.get("line"); const instructions = url.searchParams.get("instructions")
const instructions = url.searchParams.get("instructions"); const line = url.searchParams.get("line")
const code = url.searchParams.get("code"); const code = url.searchParams.get("code")
const prompt = ` const response = await env.AI.run("@cf/meta/llama-3-8b-instruct", {
Make the following changes to the code below: messages: [
- ${instructions} {
role: "system",
content:
"You are an expert coding assistant. You read code from a file, and you suggest new code to add to the file. You may be given instructions on what to generate, which you should follow. You should generate code that is CORRECT, efficient, and follows best practices. You may generate multiple lines of code if necessary. When you generate code, you should ONLY return the code, and nothing else. You MUST NOT include backticks in the code you generate.",
},
{
role: "user",
content: `The file is called ${fileName}.`,
},
{
role: "user",
content: `Here are my instructions on what to generate: ${instructions}.`,
},
{
role: "user",
content: `Suggest me code to insert at line ${line} in my file. Give only the code, and NOTHING else. DO NOT include backticks in your response. My code file content is as follows
Return the complete code chunk. Do not refer to other code files. Do not add code before or after the chunk. Start your reponse with \`\`\`, and end with \`\`\`. Do not include any other text. ${code}`,
},
],
})
\`\`\` return new Response(JSON.stringify(response))
${code} },
\`\`\` } satisfies ExportedHandler<Env>
`;
console.log(prompt);
try {
const anthropic = new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
interface TextBlock {
type: "text";
text: string;
}
interface ToolUseBlock {
type: "tool_use";
tool_use: {
// Add properties if needed
};
}
type ContentBlock = TextBlock | ToolUseBlock;
function getTextContent(content: ContentBlock[]): string {
for (const block of content) {
if (block.type === "text") {
return block.text;
}
}
return "No text content found";
}
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20240620",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
});
const message = response.content as ContentBlock[];
const textBlockContent = getTextContent(message);
const pattern = /```[a-zA-Z]*\n([\s\S]*?)\n```/;
const match = textBlockContent.match(pattern);
const codeContent = match ? match[1] : "Error: Could not extract code.";
return new Response(JSON.stringify({ "response": codeContent }))
} catch (error) {
console.error("Error:", error);
return new Response("Internal Server Error", { status: 500 });
}
},
};

View File

@ -101,7 +101,7 @@ export default {
return success return success
} else if (method === "PUT") { } else if (method === "PUT") {
const initSchema = z.object({ const initSchema = z.object({
type: z.string(), type: z.enum(["react", "node"]),
name: z.string(), name: z.string(),
userId: z.string(), userId: z.string(),
visibility: z.enum(["public", "private"]), visibility: z.enum(["public", "private"]),

View File

@ -26,7 +26,7 @@ export const sandbox = sqliteTable("sandbox", {
.primaryKey() .primaryKey()
.unique(), .unique(),
name: text("name").notNull(), name: text("name").notNull(),
type: text("type").notNull(), type: text("type", { enum: ["react", "node"] }).notNull(),
visibility: text("visibility", { enum: ["public", "private"] }), visibility: text("visibility", { enum: ["public", "private"] }),
createdAt: integer("createdAt", { mode: "timestamp_ms" }), createdAt: integer("createdAt", { mode: "timestamp_ms" }),
userId: text("user_id") userId: text("user_id")

View File

@ -1,13 +1,8 @@
# Set WORKERS_KEY to be the same as KEY in /backend/storage/wrangler.toml. # Set WORKERS_KEY to be the same as KEY in /backend/storage/wrangler.toml.
# Set DATABASE_WORKER_URL and STORAGE_WORKER_URL after deploying the workers. # Set DATABASE_WORKER_URL and STORAGE_WORKER_URL after deploying the workers.
# DOKKU_HOST and DOKKU_USERNAME are used to authenticate via SSH with the Dokku server
# DOKKU_KEY is the path to an SSH (.pem) key on the local machine
PORT=4000 PORT=4000
WORKERS_KEY= WORKERS_KEY=
DATABASE_WORKER_URL= DATABASE_WORKER_URL=
STORAGE_WORKER_URL= STORAGE_WORKER_URL=
E2B_API_KEY= E2B_API_KEY=
DOKKU_HOST=
DOKKU_USERNAME=
DOKKU_KEY=

View File

@ -12,28 +12,25 @@
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"e2b": "^0.16.2-beta.47", "e2b": "^0.16.1",
"express": "^4.19.2", "express": "^4.19.2",
"rate-limiter-flexible": "^5.0.3", "rate-limiter-flexible": "^5.0.3",
"simple-git": "^3.25.0",
"socket.io": "^4.7.5", "socket.io": "^4.7.5",
"ssh2": "^1.15.0",
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node": "^20.12.7", "@types/node": "^20.12.7",
"@types/ssh2": "^1.15.0",
"nodemon": "^3.1.0", "nodemon": "^3.1.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.5" "typescript": "^5.4.5"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.25.0", "version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@ -41,28 +38,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@bufbuild/protobuf": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz",
"integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag=="
},
"node_modules/@connectrpc/connect": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.4.0.tgz",
"integrity": "sha512-vZeOkKaAjyV4+RH3+rJZIfDFJAfr+7fyYr6sLDKbYX3uuTVszhFe9/YKf5DNqrDb5cKdKVlYkGn6DTDqMitAnA==",
"peerDependencies": {
"@bufbuild/protobuf": "^1.4.2"
}
},
"node_modules/@connectrpc/connect-web": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.4.0.tgz",
"integrity": "sha512-13aO4psFbbm7rdOFGV0De2Za64DY/acMspgloDlcOKzLPPs0yZkhp1OOzAQeiAIr7BM/VOHIA3p8mF0inxCYTA==",
"peerDependencies": {
"@bufbuild/protobuf": "^1.4.2",
"@connectrpc/connect": "1.4.0"
}
},
"node_modules/@cspotcode/source-map-support": { "node_modules/@cspotcode/source-map-support": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -85,9 +60,9 @@
} }
}, },
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0", "version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true "dev": true
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
@ -100,44 +75,10 @@
"@jridgewell/sourcemap-codec": "^1.4.10" "@jridgewell/sourcemap-codec": "^1.4.10"
} }
}, },
"node_modules/@kwsites/file-exists": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
"integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
"dependencies": {
"debug": "^4.1.1"
}
},
"node_modules/@kwsites/file-exists/node_modules/debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@kwsites/file-exists/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/@kwsites/promise-deferred": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
"integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw=="
},
"node_modules/@socket.io/component-emitter": { "node_modules/@socket.io/component-emitter": {
"version": "3.1.2", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" "integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg=="
}, },
"node_modules/@tsconfig/node10": { "node_modules/@tsconfig/node10": {
"version": "1.0.11", "version": "1.0.11",
@ -208,9 +149,9 @@
} }
}, },
"node_modules/@types/express-serve-static-core": { "node_modules/@types/express-serve-static-core": {
"version": "4.19.5", "version": "4.19.0",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
"integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
@ -232,9 +173,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.14.15", "version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
"integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==", "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
@ -272,23 +213,11 @@
"@types/send": "*" "@types/send": "*"
} }
}, },
"node_modules/@types/ssh2": { "node_modules/abbrev": {
"version": "1.15.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true, "dev": true
"dependencies": {
"@types/node": "^18.11.18"
}
},
"node_modules/@types/ssh2/node_modules/@types/node": {
"version": "18.19.44",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.44.tgz",
"integrity": "sha512-ZsbGerYg72WMXUIE9fYxtvfzLEuq6q8mKERdWFnqTmOvudMxnz+CBNRoOwJ2kNpFOncrKjT1hZwxjlFgQ9qvQA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
}, },
"node_modules/accepts": { "node_modules/accepts": {
"version": "1.3.8", "version": "1.3.8",
@ -303,9 +232,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.12.1", "version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true, "dev": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
@ -315,13 +244,10 @@
} }
}, },
"node_modules/acorn-walk": { "node_modules/acorn-walk": {
"version": "8.3.3", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
"integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
"dev": true, "dev": true,
"dependencies": {
"acorn": "^8.11.0"
},
"engines": { "engines": {
"node": ">=0.4.0" "node": ">=0.4.0"
} }
@ -372,14 +298,6 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
}, },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -394,14 +312,6 @@
"node": "^4.5.0 || >= 5.9" "node": "^4.5.0 || >= 5.9"
} }
}, },
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dependencies": {
"tweetnacl": "^0.14.3"
}
},
"node_modules/binary-extensions": { "node_modules/binary-extensions": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -448,12 +358,12 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.3", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"fill-range": "^7.1.1" "fill-range": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -465,7 +375,6 @@
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
"peer": true,
"dependencies": { "dependencies": {
"node-gyp-build": "^4.3.0" "node-gyp-build": "^4.3.0"
}, },
@ -473,15 +382,6 @@
"node": ">=6.14.2" "node": ">=6.14.2"
} }
}, },
"node_modules/buildcheck": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz",
"integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==",
"optional": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -523,6 +423,14 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/chalk/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/chalk/node_modules/supports-color": { "node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -587,11 +495,6 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"node_modules/compare-versions": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz",
"integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -624,6 +527,28 @@
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1" "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
} }
}, },
"node_modules/concurrently/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/concurrently/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -668,20 +593,6 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/cpu-features": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
"integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"buildcheck": "~0.0.6",
"nan": "^2.19.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/create-require": { "node_modules/create-require": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@ -765,19 +676,56 @@
} }
}, },
"node_modules/e2b": { "node_modules/e2b": {
"version": "0.16.2-beta.47", "version": "0.16.1",
"resolved": "https://registry.npmjs.org/e2b/-/e2b-0.16.2-beta.47.tgz", "resolved": "https://registry.npmjs.org/e2b/-/e2b-0.16.1.tgz",
"integrity": "sha512-tMPDYLMD+8+JyLPrsWft3NHBhK5YKOFOXzKMwpOKR5KvXOkd1silkArDwplmBUzN/eG/uRzWdtHZs9mHUQ5b9g==", "integrity": "sha512-2L1R/REEB+EezD4Q4MmcXXNATjvCYov2lv/69+PY6V95+wl1PZblIMTYAe7USxX6P6sqANxNs+kXqZr6RvXkSw==",
"dependencies": { "dependencies": {
"@bufbuild/protobuf": "^1.10.0", "isomorphic-ws": "^5.0.0",
"@connectrpc/connect": "^1.4.0", "normalize-path": "^3.0.0",
"@connectrpc/connect-web": "^1.4.0", "openapi-typescript-fetch": "^1.1.3",
"compare-versions": "^6.1.0", "path-browserify": "^1.0.1",
"openapi-fetch": "^0.9.7", "platform": "^1.3.6",
"platform": "^1.3.6" "ws": "^8.15.1"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
},
"optionalDependencies": {
"bufferutil": "^4.0.8",
"utf-8-validate": "^6.0.3"
}
},
"node_modules/e2b/node_modules/utf-8-validate": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz",
"integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/e2b/node_modules/ws": {
"version": "8.17.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
"integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
} }
}, },
"node_modules/ee-first": { "node_modules/ee-first": {
@ -799,9 +747,9 @@
} }
}, },
"node_modules/engine.io": { "node_modules/engine.io": {
"version": "6.5.5", "version": "6.5.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz",
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==",
"dependencies": { "dependencies": {
"@types/cookie": "^0.4.1", "@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
@ -812,16 +760,16 @@
"cors": "~2.8.5", "cors": "~2.8.5",
"debug": "~4.3.1", "debug": "~4.3.1",
"engine.io-parser": "~5.2.1", "engine.io-parser": "~5.2.1",
"ws": "~8.17.1" "ws": "~8.11.0"
}, },
"engines": { "engines": {
"node": ">=10.2.0" "node": ">=10.2.0"
} }
}, },
"node_modules/engine.io-parser": { "node_modules/engine.io-parser": {
"version": "5.2.3", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
} }
@ -835,9 +783,9 @@
} }
}, },
"node_modules/engine.io/node_modules/debug": { "node_modules/engine.io/node_modules/debug": {
"version": "4.3.6", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -855,26 +803,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/engine.io/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
@ -957,9 +885,9 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
@ -1073,11 +1001,12 @@
} }
}, },
"node_modules/has-flag": { "node_modules/has-flag": {
"version": "4.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=4"
} }
}, },
"node_modules/has-property-descriptors": { "node_modules/has-property-descriptors": {
@ -1219,11 +1148,31 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/isomorphic-ws": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
"peerDependencies": {
"ws": "*"
}
},
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/make-error": { "node_modules/make-error": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@ -1298,12 +1247,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}, },
"node_modules/nan": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
"integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
"optional": true
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -1317,7 +1260,6 @@
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
"integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
"optional": true, "optional": true,
"peer": true,
"bin": { "bin": {
"node-gyp-build": "bin.js", "node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js", "node-gyp-build-optional": "optional.js",
@ -1325,9 +1267,9 @@
} }
}, },
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.1.4", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",
"integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chokidar": "^3.5.2", "chokidar": "^3.5.2",
@ -1353,9 +1295,9 @@
} }
}, },
"node_modules/nodemon/node_modules/debug": { "node_modules/nodemon/node_modules/debug": {
"version": "4.3.6", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
@ -1369,38 +1311,31 @@
} }
} }
}, },
"node_modules/nodemon/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/nodemon/node_modules/ms": { "node_modules/nodemon/node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "dev": true
}, },
"node_modules/nodemon/node_modules/supports-color": { "node_modules/nopt": {
"version": "5.5.0", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"has-flag": "^3.0.0" "abbrev": "1"
},
"bin": {
"nopt": "bin/nopt.js"
}, },
"engines": { "engines": {
"node": ">=4" "node": "*"
} }
}, },
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -1414,12 +1349,9 @@
} }
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.2", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
"engines": {
"node": ">= 0.4"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@ -1435,19 +1367,15 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/openapi-fetch": { "node_modules/openapi-typescript-fetch": {
"version": "0.9.8", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.9.8.tgz", "resolved": "https://registry.npmjs.org/openapi-typescript-fetch/-/openapi-typescript-fetch-1.1.3.tgz",
"integrity": "sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==", "integrity": "sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==",
"dependencies": { "engines": {
"openapi-typescript-helpers": "^0.0.8" "node": ">= 12.0.0",
"npm": ">= 7.0.0"
} }
}, },
"node_modules/openapi-typescript-helpers": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.8.tgz",
"integrity": "sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g=="
},
"node_modules/parseurl": { "node_modules/parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -1456,6 +1384,11 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
@ -1595,10 +1528,13 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.6.3", "version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true, "dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
}, },
@ -1694,41 +1630,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/simple-git": {
"version": "3.25.0",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.25.0.tgz",
"integrity": "sha512-KIY5sBnzc4yEcJXW7Tdv4viEz8KyG+nU0hay+DWZasvdFOYKeUZ6Xc25LUHHjw0tinPT7O1eY6pzX7pRT1K8rw==",
"dependencies": {
"@kwsites/file-exists": "^1.1.1",
"@kwsites/promise-deferred": "^1.1.1",
"debug": "^4.3.5"
},
"funding": {
"type": "github",
"url": "https://github.com/steveukx/git-js?sponsor=1"
}
},
"node_modules/simple-git/node_modules/debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/simple-git/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/simple-update-notifier": { "node_modules/simple-update-notifier": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
@ -1759,18 +1660,18 @@
} }
}, },
"node_modules/socket.io-adapter": { "node_modules/socket.io-adapter": {
"version": "2.5.5", "version": "2.5.4",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz",
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==",
"dependencies": { "dependencies": {
"debug": "~4.3.4", "debug": "~4.3.4",
"ws": "~8.17.1" "ws": "~8.11.0"
} }
}, },
"node_modules/socket.io-adapter/node_modules/debug": { "node_modules/socket.io-adapter/node_modules/debug": {
"version": "4.3.6", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -1788,26 +1689,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/socket.io-adapter/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/socket.io-parser": { "node_modules/socket.io-parser": {
"version": "4.2.4", "version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
@ -1821,9 +1702,9 @@
} }
}, },
"node_modules/socket.io-parser/node_modules/debug": { "node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.6", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -1842,9 +1723,9 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/socket.io/node_modules/debug": { "node_modules/socket.io/node_modules/debug": {
"version": "4.3.6", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -1867,23 +1748,6 @@
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz",
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==" "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ=="
}, },
"node_modules/ssh2": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.15.0.tgz",
"integrity": "sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==",
"hasInstallScript": true,
"dependencies": {
"asn1": "^0.2.6",
"bcrypt-pbkdf": "^1.0.2"
},
"engines": {
"node": ">=10.16.0"
},
"optionalDependencies": {
"cpu-features": "~0.0.9",
"nan": "^2.18.0"
}
},
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@ -1917,17 +1781,15 @@
} }
}, },
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "8.1.1", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": { "dependencies": {
"has-flag": "^4.0.0" "has-flag": "^3.0.0"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=4"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
} }
}, },
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
@ -1951,10 +1813,13 @@
} }
}, },
"node_modules/touch": { "node_modules/touch": {
"version": "3.1.1", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
"dev": true, "dev": true,
"dependencies": {
"nopt": "~1.0.10"
},
"bin": { "bin": {
"nodetouch": "bin/nodetouch.js" "nodetouch": "bin/nodetouch.js"
} }
@ -2011,14 +1876,9 @@
} }
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.3", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
}, },
"node_modules/type-is": { "node_modules/type-is": {
"version": "1.6.18", "version": "1.6.18",
@ -2033,9 +1893,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.5.4", "version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -2065,9 +1925,9 @@
} }
}, },
"node_modules/utf-8-validate": { "node_modules/utf-8-validate": {
"version": "6.0.4", "version": "5.0.10",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
"integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==", "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
"peer": true, "peer": true,
@ -2116,6 +1976,26 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@ -2124,6 +2004,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@ -2159,9 +2045,9 @@
} }
}, },
"node_modules/zod": { "node_modules/zod": {
"version": "3.23.8", "version": "3.22.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }

View File

@ -14,19 +14,16 @@
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"e2b": "^0.16.2-beta.47", "e2b": "^0.16.1",
"express": "^4.19.2", "express": "^4.19.2",
"rate-limiter-flexible": "^5.0.3", "rate-limiter-flexible": "^5.0.3",
"simple-git": "^3.25.0",
"socket.io": "^4.7.5", "socket.io": "^4.7.5",
"ssh2": "^1.15.0",
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node": "^20.12.7", "@types/node": "^20.12.7",
"@types/ssh2": "^1.15.0",
"nodemon": "^3.1.0", "nodemon": "^3.1.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.5" "typescript": "^5.4.5"

View File

@ -1,37 +0,0 @@
import { SSHSocketClient, SSHConfig } from "./SSHSocketClient"
export interface DokkuResponse {
ok: boolean;
output: string;
}
export class DokkuClient extends SSHSocketClient {
constructor(config: SSHConfig) {
super(
config,
"/var/run/dokku-daemon/dokku-daemon.sock"
)
}
async sendCommand(command: string): Promise<DokkuResponse> {
try {
const response = await this.sendData(command);
if (typeof response !== "string") {
throw new Error("Received data is not a string");
}
return JSON.parse(response);
} catch (error: any) {
throw new Error(`Failed to send command: ${error.message}`);
}
}
async listApps(): Promise<string[]> {
const response = await this.sendCommand("apps:list");
return response.output.split("\n").slice(1); // Split by newline and ignore the first line (header)
}
}
export { SSHConfig };

View File

@ -1,90 +0,0 @@
import { Client } from "ssh2";
export interface SSHConfig {
host: string;
port?: number;
username: string;
privateKey: Buffer;
}
export class SSHSocketClient {
private conn: Client;
private config: SSHConfig;
private socketPath: string;
private isConnected: boolean = false;
constructor(config: SSHConfig, socketPath: string) {
this.conn = new Client();
this.config = { ...config, port: 22};
this.socketPath = socketPath;
this.setupTerminationHandlers();
}
private setupTerminationHandlers() {
process.on("SIGINT", this.closeConnection.bind(this));
process.on("SIGTERM", this.closeConnection.bind(this));
}
private closeConnection() {
console.log("Closing SSH connection...");
this.conn.end();
this.isConnected = false;
process.exit(0);
}
connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.conn
.on("ready", () => {
console.log("SSH connection established");
this.isConnected = true;
resolve();
})
.on("error", (err) => {
console.error("SSH connection error:", err);
this.isConnected = false;
reject(err);
})
.on("close", () => {
console.log("SSH connection closed");
this.isConnected = false;
})
.connect(this.config);
});
}
sendData(data: string): Promise<string> {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
reject(new Error("SSH connection is not established"));
return;
}
this.conn.exec(
`echo "${data}" | nc -U ${this.socketPath}`,
(err, stream) => {
if (err) {
reject(err);
return;
}
stream
.on("close", (code: number, signal: string) => {
reject(
new Error(
`Stream closed with code ${code} and signal ${signal}`
)
);
})
.on("data", (data: Buffer) => {
resolve(data.toString());
})
.stderr.on("data", (data: Buffer) => {
reject(new Error(data.toString()));
});
}
);
});
}
}

View File

@ -1,82 +0,0 @@
import simpleGit, { SimpleGit } from "simple-git";
import path from "path";
import fs from "fs";
import os from "os";
export type FileData = {
id: string;
data: string;
};
export class SecureGitClient {
private gitUrl: string;
private sshKeyPath: string;
constructor(gitUrl: string, sshKeyPath: string) {
this.gitUrl = gitUrl;
this.sshKeyPath = sshKeyPath;
}
async pushFiles(fileData: FileData[], repository: string): Promise<void> {
let tempDir: string | undefined;
try {
// Create a temporary directory
tempDir = fs.mkdtempSync(path.posix.join(os.tmpdir(), 'git-push-'));
console.log(`Temporary directory created: ${tempDir}`);
// Write files to the temporary directory
console.log(`Writing ${fileData.length} files.`);
for (const { id, data } of fileData) {
const filePath = path.posix.join(tempDir, id);
const dirPath = path.dirname(filePath);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
fs.writeFileSync(filePath, data);
}
// Initialize the simple-git instance with the temporary directory and custom SSH command
const git: SimpleGit = simpleGit(tempDir, {
config: [
'core.sshCommand=ssh -i ' + this.sshKeyPath + ' -o IdentitiesOnly=yes'
]
}).outputHandler((_command, stdout, stderr) => {
stdout.pipe(process.stdout);
stderr.pipe(process.stderr);
});;
// Initialize a new Git repository
await git.init();
// Add remote repository
await git.addRemote("origin", `${this.gitUrl}:${repository}`);
// Add files to the repository
for (const {id, data} of fileData) {
await git.add(id);
}
// Commit the changes
await git.commit("Add files.");
// Push the changes to the remote repository
await git.push("origin", "master", {'--force': null});
console.log("Files successfully pushed to the repository");
if (tempDir) {
fs.rmSync(tempDir, { recursive: true, force: true });
console.log(`Temporary directory removed: ${tempDir}`);
}
} catch (error) {
if (tempDir) {
fs.rmSync(tempDir, { recursive: true, force: true });
console.log(`Temporary directory removed: ${tempDir}`);
}
console.error("Error pushing files to the repository:", error);
throw error;
}
}
}

View File

@ -1,67 +0,0 @@
import { Sandbox, ProcessHandle } from "e2b";
// Terminal class to manage a pseudo-terminal (PTY) in a sandbox environment
export class Terminal {
private pty: ProcessHandle | undefined; // Holds the PTY process handle
private sandbox: Sandbox; // Reference to the sandbox environment
// Constructor initializes the Terminal with a sandbox
constructor(sandbox: Sandbox) {
this.sandbox = sandbox;
}
// Initialize the terminal with specified rows, columns, and data handler
async init({
rows = 20,
cols = 80,
onData,
}: {
rows?: number;
cols?: number;
onData: (responseData: string) => void;
}): Promise<void> {
// Create a new PTY process
this.pty = await this.sandbox.pty.create({
rows,
cols,
timeout: 0,
onData: (data: Uint8Array) => {
onData(new TextDecoder().decode(data)); // Convert received data to string and pass to handler
},
});
}
// Send data to the terminal
async sendData(data: string) {
if (this.pty) {
await this.sandbox.pty.sendInput(this.pty.pid, new TextEncoder().encode(data));
} else {
console.log("Cannot send data because pty is not initialized.");
}
}
// Resize the terminal
async resize(size: { cols: number; rows: number }): Promise<void> {
if (this.pty) {
await this.sandbox.pty.resize(this.pty.pid, size);
} else {
console.log("Cannot resize terminal because pty is not initialized.");
}
}
// Close the terminal, killing the PTY process and stopping the input stream
async close(): Promise<void> {
if (this.pty) {
await this.pty.kill();
} else {
console.log("Cannot kill pty because it is not initialized.");
}
}
}
// Usage example:
// const terminal = new Terminal(sandbox);
// await terminal.init();
// terminal.sendData('ls -la');
// await terminal.resize({ cols: 100, rows: 30 });
// await terminal.close();

View File

@ -55,7 +55,7 @@ const processFiles = async (paths: string[], id: string) => {
for (let i = 0; i < parts.length; i++) { for (let i = 0; i < parts.length; i++) {
const part = parts[i]; const part = parts[i];
const isFile = i === parts.length - 1 && part.length; const isFile = i === parts.length - 1 && part.includes(".");
const existing = current.children.find((child) => child.name === part); const existing = current.children.find((child) => child.name === part);
if (existing) { if (existing) {

View File

@ -1,12 +1,10 @@
import os from "os";
import path from "path"; import path from "path";
import cors from "cors"; import cors from "cors";
import express, { Express } from "express"; import express, { Express } from "express";
import dotenv from "dotenv"; import dotenv from "dotenv";
import { createServer } from "http"; import { createServer } from "http";
import { Server } from "socket.io"; import { Server } from "socket.io";
import { DokkuClient } from "./DokkuClient";
import { SecureGitClient, FileData } from "./SecureGitClient";
import fs from "fs";
import { z } from "zod"; import { z } from "zod";
import { User } from "./types"; import { User } from "./types";
@ -20,11 +18,7 @@ import {
saveFile, saveFile,
} from "./fileoperations"; } from "./fileoperations";
import { LockManager } from "./utils"; import { LockManager } from "./utils";
import { Sandbox, Terminal, FilesystemManager } from "e2b";
import { Sandbox, Filesystem } from "e2b";
import { Terminal } from "./Terminal"
import { import {
MAX_BODY_SIZE, MAX_BODY_SIZE,
createFileRL, createFileRL,
@ -56,12 +50,12 @@ const terminals: Record<string, Terminal> = {};
const dirName = "/home/user"; const dirName = "/home/user";
const moveFile = async ( const moveFile = async (
filesystem: Filesystem, filesystem: FilesystemManager,
filePath: string, filePath: string,
newFilePath: string newFilePath: string
) => { ) => {
const fileContents = await filesystem.read(filePath); const fileContents = await filesystem.readBytes(filePath);
await filesystem.write(newFilePath, fileContents); await filesystem.writeBytes(newFilePath, fileContents);
await filesystem.remove(filePath); await filesystem.remove(filePath);
}; };
@ -118,25 +112,6 @@ io.use(async (socket, next) => {
const lockManager = new LockManager(); const lockManager = new LockManager();
if (!process.env.DOKKU_HOST) console.error('Environment variable DOKKU_HOST is not defined');
if (!process.env.DOKKU_USERNAME) console.error('Environment variable DOKKU_USERNAME is not defined');
if (!process.env.DOKKU_KEY) console.error('Environment variable DOKKU_KEY is not defined');
const client =
process.env.DOKKU_HOST && process.env.DOKKU_KEY && process.env.DOKKU_USERNAME
? new DokkuClient({
host: process.env.DOKKU_HOST,
username: process.env.DOKKU_USERNAME,
privateKey: fs.readFileSync(process.env.DOKKU_KEY),
})
: null;
client?.connect();
const git = process.env.DOKKU_HOST && process.env.DOKKU_KEY ? new SecureGitClient(
`dokku@${process.env.DOKKU_HOST}`,
process.env.DOKKU_KEY
) : null;
io.on("connection", async (socket) => { io.on("connection", async (socket) => {
try { try {
if (inactivityTimeout) clearTimeout(inactivityTimeout); if (inactivityTimeout) clearTimeout(inactivityTimeout);
@ -159,10 +134,13 @@ io.on("connection", async (socket) => {
await lockManager.acquireLock(data.sandboxId, async () => { await lockManager.acquireLock(data.sandboxId, async () => {
try { try {
// Start a new container if the container doesn't exist or it timed out. if (!containers[data.sandboxId]) {
if (!containers[data.sandboxId] || !(await containers[data.sandboxId].isRunning())) { containers[data.sandboxId] = await Sandbox.create();
containers[data.sandboxId] = await Sandbox.create({ timeoutMs: 1200_000 });
console.log("Created container ", data.sandboxId); console.log("Created container ", data.sandboxId);
io.emit(
"previewURL",
"https://" + containers[data.sandboxId].getHostname(5173)
);
} }
} catch (e: any) { } catch (e: any) {
console.error(`Error creating container ${data.sandboxId}:`, e); console.error(`Error creating container ${data.sandboxId}:`, e);
@ -172,28 +150,19 @@ io.on("connection", async (socket) => {
// Change the owner of the project directory to user // Change the owner of the project directory to user
const fixPermissions = async () => { const fixPermissions = async () => {
await containers[data.sandboxId].commands.run( await containers[data.sandboxId].process.startAndWait(
`sudo chown -R user "${path.posix.join(dirName, "projects", data.sandboxId)}"` `sudo chown -R user "${path.join(dirName, "projects", data.sandboxId)}"`
); );
}; };
// Copy all files from the project to the container
const sandboxFiles = await getSandboxFiles(data.sandboxId); const sandboxFiles = await getSandboxFiles(data.sandboxId);
const containerFiles = containers[data.sandboxId].files; sandboxFiles.fileData.forEach(async (file) => {
const promises = sandboxFiles.fileData.map(async (file) => { const filePath = path.join(dirName, file.id);
try { await containers[data.sandboxId].filesystem.makeDir(
const filePath = path.posix.join(dirName, file.id); path.dirname(filePath)
const parentDirectory = path.dirname(filePath); );
if (!containerFiles.exists(parentDirectory)) { await containers[data.sandboxId].filesystem.write(filePath, file.data);
await containerFiles.makeDir(parentDirectory);
}
await containerFiles.write(filePath, file.data);
} catch (e: any) {
console.log("Failed to create file: " + e);
}
}); });
await Promise.all(promises);
fixPermissions(); fixPermissions();
socket.emit("loaded", sandboxFiles.files); socket.emit("loaded", sandboxFiles.files);
@ -223,8 +192,6 @@ io.on("connection", async (socket) => {
// todo: send diffs + debounce for efficiency // todo: send diffs + debounce for efficiency
socket.on("saveFile", async (fileId: string, body: string) => { socket.on("saveFile", async (fileId: string, body: string) => {
if (!fileId) return; // handles saving when no file is open
try { try {
if (Buffer.byteLength(body, "utf-8") > MAX_BODY_SIZE) { if (Buffer.byteLength(body, "utf-8") > MAX_BODY_SIZE) {
socket.emit( socket.emit(
@ -245,8 +212,8 @@ io.on("connection", async (socket) => {
if (!file) return; if (!file) return;
file.data = body; file.data = body;
await containers[data.sandboxId].files.write( await containers[data.sandboxId].filesystem.write(
path.posix.join(dirName, file.id), path.join(dirName, file.id),
body body
); );
fixPermissions(); fixPermissions();
@ -267,9 +234,9 @@ io.on("connection", async (socket) => {
const newFileId = folderId + "/" + parts.pop(); const newFileId = folderId + "/" + parts.pop();
await moveFile( await moveFile(
containers[data.sandboxId].files, containers[data.sandboxId].filesystem,
path.posix.join(dirName, fileId), path.join(dirName, fileId),
path.posix.join(dirName, newFileId) path.join(dirName, newFileId)
); );
fixPermissions(); fixPermissions();
@ -285,59 +252,6 @@ io.on("connection", async (socket) => {
} }
); );
interface CallbackResponse {
success: boolean;
apps?: string[];
message?: string;
}
socket.on(
"list",
async (callback: (response: CallbackResponse) => void) => {
console.log("Retrieving apps list...");
try {
if (!client) throw Error("Failed to retrieve apps list: No Dokku client")
callback({
success: true,
apps: await client.listApps()
});
} catch (error) {
callback({
success: false,
message: "Failed to retrieve apps list",
});
}
}
);
socket.on(
"deploy",
async (callback: (response: CallbackResponse) => void) => {
try {
// Push the project files to the Dokku server
console.log("Deploying project ${data.sandboxId}...");
if (!git) throw Error("Failed to retrieve apps list: No git client")
// Remove the /project/[id]/ component of each file path:
const fixedFilePaths = sandboxFiles.fileData.map((file) => {
return {
...file,
id: file.id.split("/").slice(2).join("/"),
};
});
// Push all files to Dokku.
await git.pushFiles(fixedFilePaths, data.sandboxId);
callback({
success: true,
});
} catch (error) {
callback({
success: false,
message: "Failed to deploy project: " + error,
});
}
}
);
socket.on("createFile", async (name: string, callback) => { socket.on("createFile", async (name: string, callback) => {
try { try {
const size: number = await getProjectSize(data.sandboxId); const size: number = await getProjectSize(data.sandboxId);
@ -360,8 +274,8 @@ io.on("connection", async (socket) => {
const id = `projects/${data.sandboxId}/${name}`; const id = `projects/${data.sandboxId}/${name}`;
await containers[data.sandboxId].files.write( await containers[data.sandboxId].filesystem.write(
path.posix.join(dirName, id), path.join(dirName, id),
"" ""
); );
fixPermissions(); fixPermissions();
@ -397,8 +311,8 @@ io.on("connection", async (socket) => {
const id = `projects/${data.sandboxId}/${name}`; const id = `projects/${data.sandboxId}/${name}`;
await containers[data.sandboxId].files.makeDir( await containers[data.sandboxId].filesystem.makeDir(
path.posix.join(dirName, id) path.join(dirName, id)
); );
callback(); callback();
@ -426,9 +340,9 @@ io.on("connection", async (socket) => {
parts.slice(0, parts.length - 1).join("/") + "/" + newName; parts.slice(0, parts.length - 1).join("/") + "/" + newName;
await moveFile( await moveFile(
containers[data.sandboxId].files, containers[data.sandboxId].filesystem,
path.posix.join(dirName, fileId), path.join(dirName, fileId),
path.posix.join(dirName, newFileId) path.join(dirName, newFileId)
); );
fixPermissions(); fixPermissions();
await renameFile(fileId, newFileId, file.data); await renameFile(fileId, newFileId, file.data);
@ -449,8 +363,8 @@ io.on("connection", async (socket) => {
const file = sandboxFiles.fileData.find((f) => f.id === fileId); const file = sandboxFiles.fileData.find((f) => f.id === fileId);
if (!file) return; if (!file) return;
await containers[data.sandboxId].files.remove( await containers[data.sandboxId].filesystem.remove(
path.posix.join(dirName, fileId) path.join(dirName, fileId)
); );
sandboxFiles.fileData = sandboxFiles.fileData.filter( sandboxFiles.fileData = sandboxFiles.fileData.filter(
(f) => f.id !== fileId (f) => f.id !== fileId
@ -476,8 +390,8 @@ io.on("connection", async (socket) => {
await Promise.all( await Promise.all(
files.map(async (file) => { files.map(async (file) => {
await containers[data.sandboxId].files.remove( await containers[data.sandboxId].filesystem.remove(
path.posix.join(dirName, file) path.join(dirName, file)
); );
sandboxFiles.fileData = sandboxFiles.fileData.filter( sandboxFiles.fileData = sandboxFiles.fileData.filter(
@ -505,42 +419,17 @@ io.on("connection", async (socket) => {
await lockManager.acquireLock(data.sandboxId, async () => { await lockManager.acquireLock(data.sandboxId, async () => {
try { try {
terminals[id] = new Terminal(containers[data.sandboxId]) terminals[id] = await containers[data.sandboxId].terminal.start({
await terminals[id].init({ onData: (data: string) => {
onData: (responseString: string) => { io.emit("terminalResponse", { id, data });
io.emit("terminalResponse", { id, data: responseString });
function extractPortNumber(inputString: string) {
// Remove ANSI escape codes
const cleanedString = inputString.replace(/\x1B\[[0-9;]*m/g, '');
// Regular expression to match port number
const regex = /http:\/\/localhost:(\d+)/;
// If a match is found, return the port number
const match = cleanedString.match(regex);
return match ? match[1] : null;
}
const port = parseInt(extractPortNumber(responseString) ?? "");
if (port) {
io.emit(
"previewURL",
"https://" + containers[data.sandboxId].getHost(port)
);
}
}, },
cols: 80, size: { cols: 80, rows: 20 },
rows: 20, onExit: () => console.log("Terminal exited", id),
//onExit: () => console.log("Terminal exited", id),
}); });
await terminals[id].sendData(
const defaultDirectory = path.posix.join(dirName, "projects", data.sandboxId); `cd "${path.join(dirName, "projects", data.sandboxId)}"\r`
const defaultCommands = [ );
`cd "${defaultDirectory}"`, await terminals[id].sendData("export PS1='user> '\rclear\r");
"export PS1='user> '",
"clear"
]
for (const command of defaultCommands) await terminals[id].sendData(command + "\r");
console.log("Created terminal", id); console.log("Created terminal", id);
} catch (e: any) { } catch (e: any) {
console.error(`Error creating terminal ${id}:`, e); console.error(`Error creating terminal ${id}:`, e);
@ -569,13 +458,13 @@ io.on("connection", async (socket) => {
} }
); );
socket.on("terminalData", async (id: string, data: string) => { socket.on("terminalData", (id: string, data: string) => {
try { try {
if (!terminals[id]) { if (!terminals[id]) {
return; return;
} }
await terminals[id].sendData(data); terminals[id].sendData(data);
} catch (e: any) { } catch (e: any) {
console.error("Error writing to terminal:", e); console.error("Error writing to terminal:", e);
io.emit("error", `Error: writing to terminal. ${e.message ?? e}`); io.emit("error", `Error: writing to terminal. ${e.message ?? e}`);
@ -588,7 +477,7 @@ io.on("connection", async (socket) => {
return; return;
} }
await terminals[id].close(); await terminals[id].kill();
delete terminals[id]; delete terminals[id];
callback(); callback();
@ -624,7 +513,7 @@ io.on("connection", async (socket) => {
// Generate code from cloudflare workers AI // Generate code from cloudflare workers AI
const generateCodePromise = fetch( const generateCodePromise = fetch(
`${process.env.AI_WORKER_URL}/api?fileName=${encodeURIComponent(fileName)}&code=${encodeURIComponent(code)}&line=${encodeURIComponent(line)}&instructions=${encodeURIComponent(instructions)}`, `${process.env.AI_WORKER_URL}/api?fileName=${fileName}&code=${code}&line=${line}&instructions=${instructions}`,
{ {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -657,7 +546,7 @@ io.on("connection", async (socket) => {
if (data.isOwner && connections[data.sandboxId] <= 0) { if (data.isOwner && connections[data.sandboxId] <= 0) {
await Promise.all( await Promise.all(
Object.entries(terminals).map(async ([key, terminal]) => { Object.entries(terminals).map(async ([key, terminal]) => {
await terminal.close(); await terminal.kill();
delete terminals[key]; delete terminals[key];
}) })
); );
@ -665,7 +554,7 @@ io.on("connection", async (socket) => {
await lockManager.acquireLock(data.sandboxId, async () => { await lockManager.acquireLock(data.sandboxId, async () => {
try { try {
if (containers[data.sandboxId]) { if (containers[data.sandboxId]) {
await containers[data.sandboxId].kill(); await containers[data.sandboxId].close();
delete containers[data.sandboxId]; delete containers[data.sandboxId];
console.log("Closed container", data.sandboxId); console.log("Closed container", data.sandboxId);
} }

View File

@ -8,7 +8,6 @@
"name": "storage", "name": "storage",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"p-limit": "^6.1.0",
"zod": "^3.23.4" "zod": "^3.23.4"
}, },
"devDependencies": { "devDependencies": {
@ -895,21 +894,6 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
} }
}, },
"node_modules/@vitest/runner/node_modules/p-limit": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@vitest/snapshot": { "node_modules/@vitest/snapshot": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.0.tgz",
@ -1782,11 +1766,12 @@
} }
}, },
"node_modules/p-limit": { "node_modules/p-limit": {
"version": "6.1.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
"integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==", "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
"dev": true,
"dependencies": { "dependencies": {
"yocto-queue": "^1.1.1" "yocto-queue": "^1.0.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -2985,9 +2970,10 @@
"dev": true "dev": true
}, },
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "1.1.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
"integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
"dev": true,
"engines": { "engines": {
"node": ">=12.20" "node": ">=12.20"
}, },

View File

@ -17,7 +17,6 @@
"wrangler": "^3.0.0" "wrangler": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"p-limit": "^6.1.0",
"zod": "^3.23.4" "zod": "^3.23.4"
} }
} }

View File

@ -1,9 +1,8 @@
import { z } from "zod" import { z } from "zod"
import pLimit from 'p-limit'; import startercode from "./startercode"
export interface Env { export interface Env {
R2: R2Bucket R2: R2Bucket
Templates: R2Bucket
KEY: string KEY: string
} }
@ -138,26 +137,19 @@ export default {
} else if (path === "/api/init" && method === "POST") { } else if (path === "/api/init" && method === "POST") {
const initSchema = z.object({ const initSchema = z.object({
sandboxId: z.string(), sandboxId: z.string(),
type: z.string(), type: z.enum(["react", "node"]),
}) })
const body = await request.json() const body = await request.json()
const { sandboxId, type } = initSchema.parse(body) const { sandboxId, type } = initSchema.parse(body)
console.log(`Copying template: ${type}`); console.log(startercode[type])
// List all objects under the directory await Promise.all(
const { objects } = await env.Templates.list({ prefix: type }); startercode[type].map(async (file) => {
await env.R2.put(`projects/${sandboxId}/${file.name}`, file.body)
// Copy each object to the new directory with a 5 concurrency limit })
const limit = pLimit(5); )
await Promise.all(objects.map(({ key }) =>
limit(async () => {
const destinationKey = key.replace(type, `projects/${sandboxId}`);
const fileBody = await env.Templates.get(key).then(res => res?.body ?? "");
await env.R2.put(destinationKey, fileBody);
})
));
return success return success
} else { } else {

View File

@ -0,0 +1,151 @@
const startercode = {
node: [
{ name: "index.js", body: `console.log("Hello World!")` },
{
name: "package.json",
body: `{
"name": "nodejs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/node": "^18.0.6"
}
}`,
},
],
react: [
{
name: "package.json",
body: `{
"name": "react",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"vite": "^5.2.0"
}
}`,
},
{
name: "vite.config.js",
body: `import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
host: "0.0.0.0",
}
})
`,
},
{
name: "index.html",
body: `<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Starter Code</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
`,
},
{
name: "src/App.css",
body: `div {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: sans-serif;
}
h1 {
color: #000;
margin: 0;
}
p {
color: #777;
margin: 0;
}
button {
padding: 8px 16px;
margin-top: 16px;
}`,
},
{
name: "src/App.jsx",
body: `import './App.css'
import { useState } from 'react'
function App() {
const [count, setCount] = useState(0)
return (
<div>
<h1>React Starter Code</h1>
<p>
Edit App.jsx to get started.
</p>
<button onClick={() => setCount(count => count + 1)}>
Clicked {count} times
</button>
</div>
)
}
export default App
`,
},
{
name: "src/main.jsx",
body: `import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
`,
},
],
}
export default startercode

View File

@ -3,7 +3,7 @@ CLERK_SECRET_KEY=
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY= NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY=
LIVEBLOCKS_SECRET_KEY= LIVEBLOCKS_SECRET_KEY=
NEXT_PUBLIC_SERVER_URL=http://localhost:4000 NEXT_PUBLIC_SERVER_PORT=4000
NEXT_PUBLIC_APP_URL=http://localhost:3000 NEXT_PUBLIC_APP_URL=http://localhost:3000
# Set WORKER_URLs after deploying the workers. # Set WORKER_URLs after deploying the workers.

View File

@ -6,7 +6,6 @@ import { notFound, redirect } from "next/navigation"
import Loading from "@/components/editor/loading" import Loading from "@/components/editor/loading"
import dynamic from "next/dynamic" import dynamic from "next/dynamic"
import fs from "fs" import fs from "fs"
import { TerminalProvider } from "@/context/TerminalContext"
export const revalidate = 0 export const revalidate = 0
@ -64,6 +63,14 @@ const CodeEditor = dynamic(() => import("@/components/editor"), {
loading: () => <Loading />, loading: () => <Loading />,
}) })
function getReactDefinitionFile() {
const reactDefinitionFile = fs.readFileSync(
"node_modules/@types/react/index.d.ts",
"utf8"
)
return reactDefinitionFile
}
export default async function CodePage({ params }: { params: { id: string } }) { export default async function CodePage({ params }: { params: { id: string } }) {
const user = await currentUser() const user = await currentUser()
const sandboxId = params.id const sandboxId = params.id
@ -87,21 +94,20 @@ export default async function CodePage({ params }: { params: { id: string } }) {
return notFound() return notFound()
} }
const reactDefinitionFile = getReactDefinitionFile()
return ( return (
<>
<div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background"> <div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background">
<Room id={sandboxId}> <Room id={sandboxId}>
<TerminalProvider>
<Navbar userData={userData} sandboxData={sandboxData} shared={shared} /> <Navbar userData={userData} sandboxData={sandboxData} shared={shared} />
<div className="w-screen flex grow"> <div className="w-screen flex grow">
<CodeEditor <CodeEditor
userData={userData} userData={userData}
sandboxData={sandboxData} sandboxData={sandboxData}
reactDefinitionFile={reactDefinitionFile}
/> />
</div> </div>
</TerminalProvider>
</Room> </Room>
</div> </div>
</>
) )
} }

View File

@ -6,8 +6,6 @@ import { ThemeProvider } from "@/components/layout/themeProvider"
import { ClerkProvider } from "@clerk/nextjs" import { ClerkProvider } from "@clerk/nextjs"
import { Toaster } from "@/components/ui/sonner" import { Toaster } from "@/components/ui/sonner"
import { Analytics } from "@vercel/analytics/react" import { Analytics } from "@vercel/analytics/react"
import { PreviewProvider } from "@/context/PreviewContext";
import { SocketProvider } from '@/context/SocketContext'
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Sandbox", title: "Sandbox",
@ -15,7 +13,7 @@ export const metadata: Metadata = {
} }
export default function RootLayout({ export default function RootLayout({
children children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode children: React.ReactNode
}>) { }>) {
@ -29,11 +27,7 @@ export default function RootLayout({
forcedTheme="dark" forcedTheme="dark"
disableTransitionOnChange disableTransitionOnChange
> >
<SocketProvider>
<PreviewProvider>
{children} {children}
</PreviewProvider>
</SocketProvider>
<Analytics /> <Analytics />
<Toaster position="bottom-left" richColors /> <Toaster position="bottom-left" richColors />
</ThemeProvider> </ThemeProvider>

View File

@ -1,13 +0,0 @@
"use client"
import posthog from "posthog-js"
import { PostHogProvider } from "posthog-js/react"
if (typeof window !== "undefined") {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
})
}
export function PHProvider({ children }) {
return <PostHogProvider client={posthog}>{children}</PostHogProvider>
}

View File

@ -49,9 +49,11 @@ export default function Dashboard({
const q = searchParams.get("q") const q = searchParams.get("q")
const router = useRouter() const router = useRouter()
useEffect(() => { // update the dashboard to show a new project useEffect(() => {
if (!sandboxes) {
router.refresh() router.refresh()
}, []) }
}, [sandboxes])
return ( return (
<> <>

View File

@ -37,41 +37,43 @@ import { useRouter } from "next/navigation"
import { Loader2 } from "lucide-react" import { Loader2 } from "lucide-react"
import { Button } from "../ui/button" import { Button } from "../ui/button"
type TOptions = "react" | "node" | "python" | "more"
const data: { const data: {
id: string id: TOptions
name: string name: string
icon: string icon: string
description: string description: string
disabled: boolean disabled: boolean
}[] = [ }[] = [
{ {
id: "reactjs", id: "react",
name: "React", name: "React",
icon: "/project-icons/react.svg", icon: "/project-icons/react.svg",
description: "A JavaScript library for building user interfaces", description: "A JavaScript library for building user interfaces",
disabled: false, disabled: false,
}, },
{ {
id: "vanillajs", id: "node",
name: "HTML/JS", name: "Node",
icon: "/project-icons/more.svg",
description: "More coming soon, feel free to contribute on GitHub",
disabled: false,
},
{
id: "nextjs",
name: "NextJS",
icon: "/project-icons/node.svg", icon: "/project-icons/node.svg",
description: "A JavaScript runtime built on the V8 JavaScript engine", description: "A JavaScript runtime built on the V8 JavaScript engine",
disabled: false, disabled: false,
}, },
{ {
id: "streamlit", id: "python",
name: "Streamlit", name: "Python",
icon: "/project-icons/python.svg", icon: "/project-icons/python.svg",
description: "A JavaScript runtime built on the V8 JavaScript engine", description: "A high-level, general-purpose language, coming soon",
disabled: false, disabled: true,
} },
{
id: "more",
name: "More Languages",
icon: "/project-icons/more.svg",
description: "More coming soon, feel free to contribute on GitHub",
disabled: true,
},
] ]
const formSchema = z.object({ const formSchema = z.object({
@ -93,7 +95,7 @@ export default function NewProjectModal({
open: boolean open: boolean
setOpen: (open: boolean) => void setOpen: (open: boolean) => void
}) { }) {
const [selected, setSelected] = useState("reactjs") const [selected, setSelected] = useState<TOptions>("react")
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const router = useRouter() const router = useRouter()

View File

@ -12,7 +12,7 @@ import { toast } from "sonner";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { CanvasRevealEffect } from "./projectCard/revealEffect"; import { CanvasRevealEffect } from "./projectCard/revealEffect";
const colors: { [key: string]: number[][] } = { const colors = {
react: [ react: [
[71, 207, 237], [71, 207, 237],
[30, 126, 148], [30, 126, 148],

View File

@ -1,6 +1,6 @@
"use client" "use client"
import { useCallback, useEffect, useRef, useState } from "react" import { useEffect, useRef, useState } from "react"
import { Button } from "../ui/button" import { Button } from "../ui/button"
import { Check, Loader2, RotateCw, Sparkles, X } from "lucide-react" import { Check, Loader2, RotateCw, Sparkles, X } from "lucide-react"
import { Socket } from "socket.io-client" import { Socket } from "socket.io-client"
@ -59,7 +59,7 @@ export default function GenerateInput({
}: { }: {
regenerate?: boolean regenerate?: boolean
}) => { }) => {
if (user.generations >= 1000) { if (user.generations >= 10) {
toast.error("You reached the maximum # of generations.") toast.error("You reached the maximum # of generations.")
return return
} }
@ -84,13 +84,6 @@ export default function GenerateInput({
} }
) )
} }
const handleGenerateForm = useCallback(
(e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
handleGenerate({ regenerate: false })
},
[input, currentPrompt]
)
useEffect(() => { useEffect(() => {
if (code) { if (code) {
@ -100,23 +93,9 @@ export default function GenerateInput({
} }
}, [code]) }, [code])
useEffect(() => {
//listen to when Esc key is pressed and close the modal
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onClose()
}
}
window.addEventListener("keydown", handleKeyDown)
return () => window.removeEventListener("keydown", handleKeyDown)
}, [])
return ( return (
<div className="w-full pr-4 space-y-2"> <div className="w-full pr-4 space-y-2">
<form <div className="flex items-center font-sans space-x-2">
onSubmit={handleGenerateForm}
className="flex items-center font-sans space-x-2"
>
<input <input
ref={inputRef} ref={inputRef}
style={{ style={{
@ -130,8 +109,8 @@ export default function GenerateInput({
<Button <Button
size="sm" size="sm"
type="submit"
disabled={loading.generate || loading.regenerate || input === ""} disabled={loading.generate || loading.regenerate || input === ""}
onClick={() => handleGenerate({})}
> >
{loading.generate ? ( {loading.generate ? (
<> <>
@ -147,14 +126,13 @@ export default function GenerateInput({
</Button> </Button>
<Button <Button
onClick={onClose} onClick={onClose}
type="button"
variant="outline" variant="outline"
size="smIcon" size="smIcon"
className="bg-transparent shrink-0 border-muted-foreground" className="bg-transparent shrink-0 border-muted-foreground"
> >
<X className="h-3 w-3" /> <X className="h-3 w-3" />
</Button> </Button>
</form> </div>
{expanded ? ( {expanded ? (
<> <>
<div className="rounded-md border border-muted-foreground w-full h-28 overflow-y-scroll p-2"> <div className="rounded-md border border-muted-foreground w-full h-28 overflow-y-scroll p-2">

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { useTerminal } from "@/context/TerminalContext";
import { Play, Pause, Globe, Globe2 } from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Sandbox, User } from "@/lib/types";
export default function DeployButtonModal({
userData,
data,
}: {
userData: User;
data: Sandbox;
}) {
const { deploy } = useTerminal();
const [isDeploying, setIsDeploying] = useState(false);
const handleDeploy = () => {
if (isDeploying) {
console.log("Stopping deployment...");
setIsDeploying(false);
} else {
console.log("Starting deployment...");
setIsDeploying(true);
deploy(() => {
setIsDeploying(false);
});
}
};
return (
<>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<Globe className="w-4 h-4 mr-2" />
Deploy
</Button>
</PopoverTrigger>
<PopoverContent className="p-4 w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-lg xl:max-w-xl rounded-lg shadow-lg" style={{ backgroundColor: 'rgb(10,10,10)', color: 'white' }}>
<h3 className="font-semibold text-gray-300 mb-2">Domains</h3>
<div className="flex flex-col gap-4">
<DeploymentOption
icon={<Globe className="text-gray-500 w-5 h-5" />}
domain={`${data.id}.gitwit.app`}
timestamp="Deployed 1h ago"
user={userData.name}
/>
</div>
<Button variant="outline" className="mt-4 w-full bg-[#0a0a0a] text-white hover:bg-[#262626]" onClick={handleDeploy}>
{isDeploying ? "Deploying..." : "Update"}
</Button>
</PopoverContent>
</Popover>
</>
);
}
function DeploymentOption({ icon, domain, timestamp, user }: { icon: React.ReactNode; domain: string; timestamp: string; user: string }) {
return (
<div className="flex flex-col gap-2 w-full text-left p-2 rounded-md border border-gray-700 bg-gray-900">
<div className="flex items-start gap-2 relative">
<div className="flex-shrink-0">{icon}</div>
<a
href={`https://${domain}`}
target="_blank"
rel="noopener noreferrer"
className="font-semibold text-gray-300 hover:underline"
>
{domain}
</a>
</div>
<p className="text-sm text-gray-400 mt-0 ml-7">{timestamp} {user}</p>
</div>
);
}

View File

@ -11,8 +11,6 @@ import { useState } from "react";
import EditSandboxModal from "./edit"; import EditSandboxModal from "./edit";
import ShareSandboxModal from "./share"; import ShareSandboxModal from "./share";
import { Avatars } from "../live/avatars"; import { Avatars } from "../live/avatars";
import RunButtonModal from "./run";
import DeployButtonModal from "./deploy";
export default function Navbar({ export default function Navbar({
userData, userData,
@ -21,13 +19,15 @@ export default function Navbar({
}: { }: {
userData: User; userData: User;
sandboxData: Sandbox; sandboxData: Sandbox;
shared: { id: string; name: string }[]; shared: {
id: string;
name: string;
}[];
}) { }) {
const [isEditOpen, setIsEditOpen] = useState(false); const [isEditOpen, setIsEditOpen] = useState(false);
const [isShareOpen, setIsShareOpen] = useState(false); const [isShareOpen, setIsShareOpen] = useState(false);
const [isRunning, setIsRunning] = useState(false);
const isOwner = sandboxData.userId === userData.id;; const isOwner = sandboxData.userId === userData.id;
return ( return (
<> <>
@ -62,25 +62,14 @@ export default function Navbar({
) : null} ) : null}
</div> </div>
</div> </div>
<RunButtonModal
isRunning={isRunning}
setIsRunning={setIsRunning}
sandboxData={sandboxData}
/>
<div className="flex items-center h-full space-x-4"> <div className="flex items-center h-full space-x-4">
<Avatars /> <Avatars />
{isOwner ? ( {isOwner ? (
<>
<DeployButtonModal
data={sandboxData}
userData={userData}
/>
<Button variant="outline" onClick={() => setIsShareOpen(true)}> <Button variant="outline" onClick={() => setIsShareOpen(true)}>
<Users className="w-4 h-4 mr-2" /> <Users className="w-4 h-4 mr-2" />
Share Share
</Button> </Button>
</>
) : null} ) : null}
<UserButton userData={userData} /> <UserButton userData={userData} />
</div> </div>

View File

@ -1,73 +0,0 @@
"use client";
import React, { useEffect, useRef } from 'react';
import { Play, StopCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useTerminal } from "@/context/TerminalContext";
import { usePreview } from "@/context/PreviewContext";
import { toast } from "sonner";
import { Sandbox } from "@/lib/types";
export default function RunButtonModal({
isRunning,
setIsRunning,
sandboxData,
}: {
isRunning: boolean;
setIsRunning: (running: boolean) => void;
sandboxData: Sandbox;
}) {
const { createNewTerminal, closeTerminal, terminals } = useTerminal();
const { setIsPreviewCollapsed, previewPanelRef } = usePreview();
// Ref to keep track of the last created terminal's ID
const lastCreatedTerminalRef = useRef<string | null>(null);
// Effect to update the lastCreatedTerminalRef when a new terminal is added
useEffect(() => {
if (terminals.length > 0 && !isRunning) {
const latestTerminal = terminals[terminals.length - 1];
if (latestTerminal && latestTerminal.id !== lastCreatedTerminalRef.current) {
lastCreatedTerminalRef.current = latestTerminal.id;
}
}
}, [terminals, isRunning]);
const handleRun = async () => {
if (isRunning && lastCreatedTerminalRef.current)
{
await closeTerminal(lastCreatedTerminalRef.current);
lastCreatedTerminalRef.current = null;
setIsPreviewCollapsed(true);
previewPanelRef.current?.collapse();
}
else if (!isRunning && terminals.length < 4)
{
const command = sandboxData.type === "streamlit"
? "pip install -r requirements.txt && streamlit run main.py --server.runOnSave true"
: "yarn install && yarn dev";
try {
// Create a new terminal with the appropriate command
await createNewTerminal(command);
setIsPreviewCollapsed(false);
previewPanelRef.current?.expand();
} catch (error) {
toast.error("Failed to create new terminal.");
console.error("Error creating new terminal:", error);
return;
}
} else if (!isRunning) {
toast.error("You've reached the maximum number of terminals.");
return;
}
setIsRunning(!isRunning);
};
return (
<Button variant="outline" onClick={handleRun}>
{isRunning ? <StopCircle className="w-4 h-4 mr-2" /> : <Play className="w-4 h-4 mr-2" />}
{isRunning ? 'Stop' : 'Run'}
</Button>
);
}

View File

@ -1,14 +1,18 @@
"use client" "use client"
import { import {
ChevronLeft,
ChevronRight,
Globe,
Link, Link,
RotateCw, RotateCw,
TerminalSquare, TerminalSquare,
UnfoldVertical,
} from "lucide-react" } from "lucide-react"
import { useEffect, useRef, useState, useImperativeHandle, forwardRef } from "react" import { useRef, useState } from "react"
import { toast } from "sonner" import { toast } from "sonner"
export default forwardRef(function PreviewWindow({ export default function PreviewWindow({
collapsed, collapsed,
open, open,
src src
@ -16,39 +20,29 @@ export default forwardRef(function PreviewWindow({
collapsed: boolean collapsed: boolean
open: () => void open: () => void
src: string src: string
}, }) {
ref: React.Ref<{ const ref = useRef<HTMLIFrameElement>(null)
refreshIframe: () => void
}>) {
const frameRef = useRef<HTMLIFrameElement>(null)
const [iframeKey, setIframeKey] = useState(0) const [iframeKey, setIframeKey] = useState(0)
const refreshIframe = () => {
setIframeKey(prev => prev + 1)
}
// Refresh the preview when the URL changes.
useEffect(refreshIframe, [src])
// Expose refreshIframe method to the parent.
useImperativeHandle(ref, () => ({ refreshIframe }))
return ( return (
<> <>
<div <div
className={`${collapsed ? "h-full" : "h-10" className={`${
} select-none w-full flex gap-2`} collapsed ? "h-full" : "h-10"
} select-none w-full flex gap-2`}
> >
<div className="h-8 rounded-md px-3 bg-secondary flex items-center w-full justify-between"> <div className="h-8 rounded-md px-3 bg-secondary flex items-center w-full justify-between">
<div className="text-xs">Preview</div> <div className="text-xs">Preview</div>
<div className="flex space-x-1 translate-x-1"> <div className="flex space-x-1 translate-x-1">
{collapsed ? ( {collapsed ? (
<PreviewButton disabled onClick={() => { }}> <PreviewButton onClick={open}>
<TerminalSquare className="w-4 h-4" /> <UnfoldVertical className="w-4 h-4" />
</PreviewButton> </PreviewButton>
) : ( ) : (
<> <>
{/* Removed the unfoldvertical button since we have the same thing via the run button. {/* Todo, make this open inspector */}
{/* <PreviewButton disabled onClick={() => {}}>
<PreviewButton onClick={open}> <TerminalSquare className="w-4 h-4" />
<UnfoldVertical className="w-4 h-4" />
</PreviewButton> */} </PreviewButton> */}
<PreviewButton <PreviewButton
@ -59,7 +53,14 @@ ref: React.Ref<{
> >
<Link className="w-4 h-4" /> <Link className="w-4 h-4" />
</PreviewButton> </PreviewButton>
<PreviewButton onClick={refreshIframe}> <PreviewButton
onClick={() => {
// if (ref.current) {
// ref.current.contentWindow?.location.reload();
// }
setIframeKey((prev) => prev + 1)
}}
>
<RotateCw className="w-3 h-3" /> <RotateCw className="w-3 h-3" />
</PreviewButton> </PreviewButton>
</> </>
@ -71,7 +72,7 @@ ref: React.Ref<{
<div className="w-full grow rounded-md overflow-hidden bg-foreground"> <div className="w-full grow rounded-md overflow-hidden bg-foreground">
<iframe <iframe
key={iframeKey} key={iframeKey}
ref={frameRef} ref={ref}
width={"100%"} width={"100%"}
height={"100%"} height={"100%"}
src={src} src={src}
@ -80,7 +81,7 @@ ref: React.Ref<{
)} )}
</> </>
) )
}) }
function PreviewButton({ function PreviewButton({
children, children,
@ -93,8 +94,9 @@ function PreviewButton({
}) { }) {
return ( return (
<div <div
className={`${disabled ? "pointer-events-none opacity-50" : "" className={`${
} p-0.5 h-5 w-5 ml-0.5 flex items-center justify-center transition-colors bg-transparent hover:bg-muted-foreground/25 cursor-pointer rounded-sm`} disabled ? "pointer-events-none opacity-50" : ""
} p-0.5 h-5 w-5 ml-0.5 flex items-center justify-center transition-colors bg-transparent hover:bg-muted-foreground/25 cursor-pointer rounded-sm`}
onClick={onClick} onClick={onClick}
> >
{children} {children}

View File

@ -32,6 +32,8 @@ export default function Sidebar({
socket, socket,
setFiles, setFiles,
addNew, addNew,
ai,
setAi,
deletingFolderId, deletingFolderId,
}: { }: {
sandboxData: Sandbox; sandboxData: Sandbox;
@ -48,6 +50,8 @@ export default function Sidebar({
socket: Socket; socket: Socket;
setFiles: (files: (TFile | TFolder)[]) => void; setFiles: (files: (TFile | TFolder)[]) => void;
addNew: (name: string, type: "file" | "folder") => void; addNew: (name: string, type: "file" | "folder") => void;
ai: boolean;
setAi: React.Dispatch<React.SetStateAction<boolean>>;
deletingFolderId: string; deletingFolderId: string;
}) { }) {
const ref = useRef(null); // drop target const ref = useRef(null); // drop target
@ -182,6 +186,20 @@ export default function Sidebar({
</div> </div>
</div> </div>
<div className="w-full space-y-4"> <div className="w-full space-y-4">
<div className="flex items-center justify-between w-full">
<div className="flex items-center">
<Sparkles
className={`h-4 w-4 mr-2 ${
ai ? "text-indigo-500" : "text-muted-foreground"
}`}
/>
Copilot{" "}
<span className="font-mono text-muted-foreground inline-block ml-1.5 text-xs leading-none border border-b-2 border-muted-foreground py-1 px-1.5 rounded-md">
G
</span>
</div>
<Switch checked={ai} onCheckedChange={setAi} />
</div>
{/* <Button className="w-full"> {/* <Button className="w-full">
<MonitorPlay className="w-4 h-4 mr-2" /> Run <MonitorPlay className="w-4 h-4 mr-2" /> Run
</Button> */} </Button> */}

View File

@ -2,45 +2,35 @@
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Tab from "@/components/ui/tab"; import Tab from "@/components/ui/tab";
import { closeTerminal, createTerminal } from "@/lib/terminal";
import { Terminal } from "@xterm/xterm"; import { Terminal } from "@xterm/xterm";
import { Loader2, Plus, SquareTerminal, TerminalSquare } from "lucide-react"; import { Loader2, Plus, SquareTerminal, TerminalSquare } from "lucide-react";
import { Socket } from "socket.io-client";
import { toast } from "sonner"; import { toast } from "sonner";
import EditorTerminal from "./terminal"; import EditorTerminal from "./terminal";
import { useTerminal } from "@/context/TerminalContext"; import { useState } from "react";
import { useEffect } from "react";
import { useSocket } from "@/context/SocketContext"
export default function Terminals() {
const { socket } = useSocket();
const {
terminals,
setTerminals,
createNewTerminal,
closeTerminal,
activeTerminalId,
setActiveTerminalId,
creatingTerminal,
} = useTerminal();
export default function Terminals({
terminals,
setTerminals,
socket,
}: {
terminals: { id: string; terminal: Terminal | null }[];
setTerminals: React.Dispatch<
React.SetStateAction<
{
id: string;
terminal: Terminal | null;
}[]
>
>;
socket: Socket;
}) {
const [activeTerminalId, setActiveTerminalId] = useState("");
const [creatingTerminal, setCreatingTerminal] = useState(false);
const [closingTerminal, setClosingTerminal] = useState("");
const activeTerminal = terminals.find((t) => t.id === activeTerminalId); const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
// Effect to set the active terminal when a new one is created
useEffect(() => {
if (terminals.length > 0 && !activeTerminalId) {
setActiveTerminalId(terminals[terminals.length - 1].id);
}
}, [terminals, activeTerminalId, setActiveTerminalId]);
const handleCreateTerminal = () => {
if (terminals.length >= 4) {
toast.error("You reached the maximum # of terminals.");
return;
}
createNewTerminal();
};
return ( return (
<> <>
<div className="h-10 w-full overflow-auto flex gap-2 shrink-0 tab-scroll"> <div className="h-10 w-full overflow-auto flex gap-2 shrink-0 tab-scroll">
@ -49,7 +39,18 @@ export default function Terminals() {
key={term.id} key={term.id}
creating={creatingTerminal} creating={creatingTerminal}
onClick={() => setActiveTerminalId(term.id)} onClick={() => setActiveTerminalId(term.id)}
onClose={() => closeTerminal(term.id)} onClose={() =>
closeTerminal({
term,
terminals,
setTerminals,
setActiveTerminalId,
setClosingTerminal,
socket,
activeTerminalId,
})
}
closing={closingTerminal === term.id}
selected={activeTerminalId === term.id} selected={activeTerminalId === term.id}
> >
<SquareTerminal className="w-4 h-4 mr-2" /> <SquareTerminal className="w-4 h-4 mr-2" />
@ -58,7 +59,18 @@ export default function Terminals() {
))} ))}
<Button <Button
disabled={creatingTerminal} disabled={creatingTerminal}
onClick={handleCreateTerminal} onClick={() => {
if (terminals.length >= 4) {
toast.error("You reached the maximum # of terminals.");
return;
}
createTerminal({
setTerminals,
setActiveTerminalId,
setCreatingTerminal,
socket,
});
}}
size="smIcon" size="smIcon"
variant={"secondary"} variant={"secondary"}
className={`font-normal shrink-0 select-none text-muted-foreground disabled:opacity-50`} className={`font-normal shrink-0 select-none text-muted-foreground disabled:opacity-50`}

View File

@ -55,6 +55,7 @@ export default function EditorTerminal({
fitAddon.fit(); fitAddon.fit();
const disposableOnData = term.onData((data) => { const disposableOnData = term.onData((data) => {
console.log("terminalData", id, data);
socket.emit("terminalData", id, data); socket.emit("terminalData", id, data);
}); });
@ -73,20 +74,6 @@ export default function EditorTerminal({
}; };
}, [term, terminalRef.current]); }, [term, terminalRef.current]);
useEffect(() => {
if (!term) return;
const handleTerminalResponse = (response: { id: string; data: string }) => {
if (response.id === id) {
term.write(response.data);
}
};
socket.on("terminalResponse", handleTerminalResponse);
return () => {
socket.off("terminalResponse", handleTerminalResponse);
};
}, [term, id, socket]);
return ( return (
<> <>
<div <div

View File

@ -22,7 +22,6 @@ const buttonVariants = cva(
}, },
size: { size: {
default: "h-9 px-4 py-2", default: "h-9 px-4 py-2",
xs: "h-6 px-2.5 py-1.5 rounded-sm text-[0.7rem]",
sm: "h-8 rounded-md px-3 text-xs", sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8", lg: "h-10 rounded-md px-8",
icon: "h-9 w-9", icon: "h-9 w-9",

View File

@ -1,33 +0,0 @@
"use client"
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import { cn } from "@/lib/utils"
const Popover = PopoverPrimitive.Root
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverAnchor = PopoverPrimitive.Anchor
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }

View File

@ -42,13 +42,13 @@ export default function UserButton({ userData }: { userData: User }) {
<div className="py-1.5 px-2 w-full flex flex-col items-start text-sm"> <div className="py-1.5 px-2 w-full flex flex-col items-start text-sm">
<div className="flex items-center"> <div className="flex items-center">
<Sparkles className={`h-4 w-4 mr-2 text-indigo-500`} /> <Sparkles className={`h-4 w-4 mr-2 text-indigo-500`} />
AI Usage: {userData.generations}/1000 AI Usage: {userData.generations}/10
</div> </div>
<div className="rounded-full w-full mt-2 h-2 overflow-hidden bg-secondary"> <div className="rounded-full w-full mt-2 h-2 overflow-hidden bg-secondary">
<div <div
className="h-full bg-indigo-500 rounded-full" className="h-full bg-indigo-500 rounded-full"
style={{ style={{
width: `${(userData.generations * 100) / 1000}%`, width: `${(userData.generations * 100) / 10}%`,
}} }}
/> />
</div> </div>

View File

@ -1,34 +0,0 @@
"use client"
import React, { createContext, useContext, useState, useRef } from 'react';
import { ImperativePanelHandle } from "react-resizable-panels";
interface PreviewContextType {
isPreviewCollapsed: boolean;
setIsPreviewCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
previewURL: string;
setPreviewURL: React.Dispatch<React.SetStateAction<string>>;
previewPanelRef: React.RefObject<ImperativePanelHandle>;
}
const PreviewContext = createContext<PreviewContextType | undefined>(undefined);
export const PreviewProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isPreviewCollapsed, setIsPreviewCollapsed] = useState(true);
const [previewURL, setPreviewURL] = useState<string>("");
const previewPanelRef = useRef<ImperativePanelHandle>(null);
return (
<PreviewContext.Provider value={{ isPreviewCollapsed, setIsPreviewCollapsed, previewURL, setPreviewURL, previewPanelRef }}>
{children}
</PreviewContext.Provider>
);
};
export const usePreview = () => {
const context = useContext(PreviewContext);
if (context === undefined) {
throw new Error('usePreview must be used within a PreviewProvider');
}
return context;
};

View File

@ -1,63 +0,0 @@
"use client";
import React, { createContext, useContext, useEffect, useState } from 'react';
import { io, Socket } from 'socket.io-client';
interface SocketContextType {
socket: Socket | null;
setUserAndSandboxId: (userId: string, sandboxId: string) => void;
}
const SocketContext = createContext<SocketContextType | undefined>(undefined);
export const SocketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [socket, setSocket] = useState<Socket | null>(null);
const [userId, setUserId] = useState<string | null>(null);
const [sandboxId, setSandboxId] = useState<string | null>(null);
useEffect(() => {
if (userId && sandboxId) {
console.log("Initializing socket connection...");
const newSocket = io(`${process.env.NEXT_PUBLIC_SERVER_URL}?userId=${userId}&sandboxId=${sandboxId}`);
console.log("Socket instance:", newSocket);
setSocket(newSocket);
newSocket.on('connect', () => {
console.log("Socket connected:", newSocket.id);
});
newSocket.on('disconnect', () => {
console.log("Socket disconnected");
});
return () => {
console.log("Disconnecting socket...");
newSocket.disconnect();
};
}
}, [userId, sandboxId]);
const setUserAndSandboxId = (newUserId: string, newSandboxId: string) => {
setUserId(newUserId);
setSandboxId(newSandboxId);
};
const value = {
socket,
setUserAndSandboxId,
};
return (
<SocketContext.Provider value={ value }>
{children}
</SocketContext.Provider>
);
};
export const useSocket = (): SocketContextType => {
const context = useContext(SocketContext);
if (!context) {
throw new Error('useSocket must be used within a SocketProvider');
}
return context;
};

View File

@ -1,95 +0,0 @@
"use client";
import React, { createContext, useContext, useState } from 'react';
import { Terminal } from '@xterm/xterm';
import { createTerminal as createTerminalHelper, closeTerminal as closeTerminalHelper } from '@/lib/terminal';
import { useSocket } from '@/context/SocketContext';
interface TerminalContextType {
terminals: { id: string; terminal: Terminal | null }[];
setTerminals: React.Dispatch<React.SetStateAction<{ id: string; terminal: Terminal | null }[]>>;
activeTerminalId: string;
setActiveTerminalId: React.Dispatch<React.SetStateAction<string>>;
creatingTerminal: boolean;
setCreatingTerminal: React.Dispatch<React.SetStateAction<boolean>>;
createNewTerminal: (command?: string) => Promise<void>;
closeTerminal: (id: string) => void;
deploy: (callback: () => void) => void;
}
const TerminalContext = createContext<TerminalContextType | undefined>(undefined);
export const TerminalProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { socket } = useSocket();
const [terminals, setTerminals] = useState<{ id: string; terminal: Terminal | null }[]>([]);
const [activeTerminalId, setActiveTerminalId] = useState<string>('');
const [creatingTerminal, setCreatingTerminal] = useState<boolean>(false);
const createNewTerminal = async (command?: string): Promise<void> => {
if (!socket) return;
setCreatingTerminal(true);
try {
createTerminalHelper({
setTerminals,
setActiveTerminalId,
setCreatingTerminal,
command,
socket,
});
} catch (error) {
console.error("Error creating terminal:", error);
} finally {
setCreatingTerminal(false);
}
};
const closeTerminal = (id: string) => {
if (!socket) return;
const terminalToClose = terminals.find(term => term.id === id);
if (terminalToClose) {
closeTerminalHelper({
term: terminalToClose,
terminals,
setTerminals,
setActiveTerminalId,
setClosingTerminal: () => {},
socket,
activeTerminalId,
});
}
};
const deploy = (callback: () => void) => {
if (!socket) console.error("Couldn't deploy: No socket");
console.log("Deploying...")
socket?.emit("deploy", () => {
callback();
});
}
const value = {
terminals,
setTerminals,
activeTerminalId,
setActiveTerminalId,
creatingTerminal,
setCreatingTerminal,
createNewTerminal,
closeTerminal,
deploy
};
return (
<TerminalContext.Provider value={value}>
{children}
</TerminalContext.Provider>
);
};
export const useTerminal = (): TerminalContextType => {
const context = useContext(TerminalContext);
if (!context) {
throw new Error('useTerminal must be used within a TerminalProvider');
}
return context;
};

View File

@ -1,295 +0,0 @@
{
"_coffee": "coffeescript",
"_js": "javascript",
"adp": "tcl",
"al": "perl",
"ant": "xml",
"aw": "php",
"axml": "xml",
"bash": "shell",
"bats": "shell",
"bones": "javascript",
"boot": "clojure",
"builder": "ruby",
"bzl": "python",
"c": "c",
"c++": "cpp",
"cake": "coffeescript",
"cats": "c",
"cc": "cpp",
"ccxml": "xml",
"cfg": "ini",
"cgi": "shell",
"cjsx": "coffeescript",
"cl2": "clojure",
"clixml": "xml",
"clj": "clojure",
"cljc": "clojure",
"cljs.hl": "clojure",
"cljs": "clojure",
"cljscm": "clojure",
"cljx": "clojure",
"coffee": "coffeescript",
"command": "shell",
"cp": "cpp",
"cpp": "cpp",
"cproject": "xml",
"cql": "sql",
"csl": "xml",
"cson": "coffeescript",
"csproj": "xml",
"ct": "xml",
"ctp": "php",
"cxx": "cpp",
"ddl": "sql",
"dfm": "pascal",
"dita": "xml",
"ditamap": "xml",
"ditaval": "xml",
"dll.config": "xml",
"dotsettings": "xml",
"dpr": "pascal",
"ecl": "ecl",
"eclxml": "ecl",
"es": "javascript",
"es6": "javascript",
"ex": "elixir",
"exs": "elixir",
"fcgi": "shell",
"filters": "xml",
"frag": "javascript",
"fsproj": "xml",
"fxml": "xml",
"gemspec": "ruby",
"geojson": "json",
"glade": "xml",
"gml": "xml",
"god": "ruby",
"grxml": "xml",
"gs": "javascript",
"gyp": "python",
"h": "cpp",
"h++": "cpp",
"handlebars": "handlebars",
"hbs": "handlebars",
"hcl": "hcl",
"hh": "cpp",
"hic": "clojure",
"hpp": "cpp",
"htm": "html",
"html.hl": "html",
"html": "html",
"hxx": "cpp",
"iced": "coffeescript",
"idc": "c",
"iml": "xml",
"inc": "sql",
"ini": "ini",
"inl": "cpp",
"ipp": "cpp",
"irbrc": "ruby",
"ivy": "xml",
"j2": "python",
"jake": "javascript",
"jbuilder": "ruby",
"jelly": "xml",
"jinja": "python",
"jinja2": "python",
"js": "javascript",
"jsb": "javascript",
"jscad": "javascript",
"jsfl": "javascript",
"jsm": "javascript",
"json": "json",
"jsproj": "xml",
"jss": "javascript",
"kml": "xml",
"ksh": "shell",
"kt": "kotlin",
"ktm": "kotlin",
"kts": "kotlin",
"launch": "xml",
"lmi": "python",
"lock": "json",
"lpr": "pascal",
"lua": "lua",
"markdown": "markdown",
"md": "markdown",
"mdpolicy": "xml",
"mkd": "markdown",
"mkdn": "markdown",
"mkdown": "markdown",
"mm": "xml",
"mod": "xml",
"mspec": "ruby",
"mustache": "python",
"mxml": "xml",
"njs": "javascript",
"nproj": "xml",
"nse": "lua",
"nuspec": "xml",
"odd": "xml",
"osm": "xml",
"pac": "javascript",
"pas": "pascal",
"pd_lua": "lua",
"perl": "perl",
"ph": "perl",
"php": "php",
"php3": "php",
"php4": "php",
"php5": "php",
"phps": "php",
"phpt": "php",
"pl": "perl",
"plist": "xml",
"pluginspec": "xml",
"plx": "perl",
"pm": "perl",
"pod": "perl",
"podspec": "ruby",
"pp": "pascal",
"prc": "sql",
"prefs": "ini",
"pro": "ini",
"properties": "ini",
"props": "xml",
"ps1": "powershell",
"ps1xml": "xml",
"psc1": "xml",
"psd1": "powershell",
"psgi": "perl",
"psm1": "powershell",
"pt": "xml",
"py": "python",
"pyde": "python",
"pyp": "python",
"pyt": "python",
"pyw": "python",
"r": "r",
"rabl": "ruby",
"rake": "ruby",
"rb": "ruby",
"rbuild": "ruby",
"rbw": "ruby",
"rbx": "ruby",
"rbxs": "lua",
"rd": "r",
"rdf": "xml",
"reek": "yaml",
"rest.txt": "restructuredtext",
"rest": "restructuredtext",
"ron": "markdown",
"rpy": "python",
"rq": "sparql",
"rs.in": "rust",
"rs": "rust",
"rss": "xml",
"rst.txt": "restructuredtext",
"rst": "restructuredtext",
"rsx": "r",
"ru": "ruby",
"ruby": "ruby",
"rviz": "yaml",
"sbt": "scala",
"sc": "scala",
"scala": "scala",
"scm": "scheme",
"scxml": "xml",
"sh.in": "shell",
"sh": "shell",
"sjs": "javascript",
"sld": "scheme",
"sls": "scheme",
"sparql": "sparql",
"sps": "scheme",
"sql": "sql",
"srdf": "xml",
"ss": "scheme",
"ssjs": "javascript",
"st": "html",
"storyboard": "xml",
"sttheme": "xml",
"sublime_metrics": "javascript",
"sublime_session": "javascript",
"sublime-build": "javascript",
"sublime-commands": "javascript",
"sublime-completions": "javascript",
"sublime-keymap": "javascript",
"sublime-macro": "javascript",
"sublime-menu": "javascript",
"sublime-mousemap": "javascript",
"sublime-project": "javascript",
"sublime-settings": "javascript",
"sublime-snippet": "xml",
"sublime-syntax": "yaml",
"sublime-theme": "javascript",
"sublime-workspace": "javascript",
"sv": "systemverilog",
"svh": "systemverilog",
"syntax": "yaml",
"t": "perl",
"tab": "sql",
"tac": "python",
"targets": "xml",
"tcc": "cpp",
"tcl": "tcl",
"tf": "hcl",
"thor": "ruby",
"tm": "tcl",
"tmcommand": "xml",
"tml": "xml",
"tmlanguage": "xml",
"tmpreferences": "xml",
"tmsnippet": "xml",
"tmtheme": "xml",
"tmux": "shell",
"tool": "shell",
"topojson": "json",
"tpp": "cpp",
"ts": "typescript",
"tsx": "typescript",
"udf": "sql",
"ui": "xml",
"urdf": "xml",
"ux": "xml",
"v": "verilog",
"vbproj": "xml",
"vcxproj": "xml",
"veo": "verilog",
"vh": "systemverilog",
"viw": "sql",
"vssettings": "xml",
"vxml": "xml",
"w": "c",
"watchr": "ruby",
"wlua": "lua",
"wsdl": "xml",
"wsf": "xml",
"wsgi": "python",
"wxi": "xml",
"wxl": "xml",
"wxs": "xml",
"x3d": "xml",
"xacro": "xml",
"xaml": "xml",
"xht": "html",
"xhtml": "html",
"xib": "xml",
"xlf": "xml",
"xliff": "xml",
"xmi": "xml",
"xml.dist": "xml",
"xml": "xml",
"xproj": "xml",
"xpy": "python",
"xsd": "xml",
"xsjs": "javascript",
"xsjslib": "javascript",
"xul": "xml",
"yaml-tmlanguage": "yaml",
"yaml": "yaml",
"yml": "yaml",
"zcml": "xml",
"zsh": "shell"
}

View File

@ -8,7 +8,6 @@ export const createTerminal = ({
setTerminals, setTerminals,
setActiveTerminalId, setActiveTerminalId,
setCreatingTerminal, setCreatingTerminal,
command,
socket, socket,
}: { }: {
setTerminals: React.Dispatch<React.SetStateAction<{ setTerminals: React.Dispatch<React.SetStateAction<{
@ -17,7 +16,6 @@ export const createTerminal = ({
}[]>>; }[]>>;
setActiveTerminalId: React.Dispatch<React.SetStateAction<string>>; setActiveTerminalId: React.Dispatch<React.SetStateAction<string>>;
setCreatingTerminal: React.Dispatch<React.SetStateAction<boolean>>; setCreatingTerminal: React.Dispatch<React.SetStateAction<boolean>>;
command?: string;
socket: Socket; socket: Socket;
}) => { }) => {
@ -31,7 +29,6 @@ export const createTerminal = ({
setTimeout(() => { setTimeout(() => {
socket.emit("createTerminal", id, () => { socket.emit("createTerminal", id, () => {
setCreatingTerminal(false); setCreatingTerminal(false);
if (command) socket.emit("terminalData", id, command + "\n");
}); });
}, 1000); }, 1000);
}; };

View File

@ -12,7 +12,7 @@ export type User = {
export type Sandbox = { export type Sandbox = {
id: string; id: string;
name: string; name: string;
type: string; type: "react" | "node";
visibility: "public" | "private"; visibility: "public" | "private";
createdAt: Date; createdAt: Date;
userId: string; userId: string;

View File

@ -2,19 +2,18 @@ import { type ClassValue, clsx } from "clsx"
// import { toast } from "sonner" // import { toast } from "sonner"
import { twMerge } from "tailwind-merge" import { twMerge } from "tailwind-merge"
import { Sandbox, TFile, TFolder } from "./types" import { Sandbox, TFile, TFolder } from "./types"
import fileExtToLang from "./file-extension-to-language.json"
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }
export function processFileType(file: string) { export function processFileType(file: string) {
const extension = file.split(".").pop() const ending = file.split(".").pop()
const fileExtToLangMap = fileExtToLang as Record<string, string>
if (extension && fileExtToLangMap[extension]) {
return fileExtToLangMap[extension]
}
if (ending === "ts" || ending === "tsx") return "typescript"
if (ending === "js" || ending === "jsx") return "javascript"
if (ending) return ending
return "plaintext" return "plaintext"
} }
@ -63,15 +62,12 @@ export function addNew(
} }
} }
export function debounce<T extends (...args: any[]) => void>( export function debounce<T extends (...args: any[]) => void>(func: T, wait: number): T {
func: T, let timeout: NodeJS.Timeout | null = null;
wait: number
): T {
let timeout: NodeJS.Timeout | null = null
return function (...args: Parameters<T>) { return function (...args: Parameters<T>) {
if (timeout) { if (timeout) {
clearTimeout(timeout) clearTimeout(timeout);
} }
timeout = setTimeout(() => func(...args), wait) timeout = setTimeout(() => func(...args), wait);
} as T } as T;
} }

View File

@ -24,7 +24,6 @@
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2", "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
@ -41,7 +40,6 @@
"monaco-themes": "^0.4.4", "monaco-themes": "^0.4.4",
"next": "14.1.3", "next": "14.1.3",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"posthog-js": "^1.147.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18", "react-dom": "^18",
"react-hook-form": "^7.51.3", "react-hook-form": "^7.51.3",
@ -1120,419 +1118,6 @@
} }
} }
}, },
"node_modules/@radix-ui/react-popover": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.1.tgz",
"integrity": "sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-dismissable-layer": "1.1.0",
"@radix-ui/react-focus-guards": "1.1.0",
"@radix-ui/react-focus-scope": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-popper": "1.2.0",
"@radix-ui/react-portal": "1.1.1",
"@radix-ui/react-presence": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.7"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
"integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
"dependencies": {
"@radix-ui/react-primitive": "2.0.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
"integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
"integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz",
"integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-escape-keydown": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
"integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz",
"integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
"integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
"dependencies": {
"@floating-ui/react-dom": "^2.0.0",
"@radix-ui/react-arrow": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0",
"@radix-ui/react-use-rect": "1.1.0",
"@radix-ui/react-use-size": "1.1.0",
"@radix-ui/rect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz",
"integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==",
"dependencies": {
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
"integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
"integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
"dependencies": {
"@radix-ui/react-slot": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
"integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
"integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
"integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
"integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
"dependencies": {
"@radix-ui/rect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-size": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
"integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
},
"node_modules/@radix-ui/react-popover/node_modules/react-remove-scroll": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
"integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
"dependencies": {
"react-remove-scroll-bar": "^2.3.4",
"react-style-singleton": "^2.2.1",
"tslib": "^2.1.0",
"use-callback-ref": "^1.3.0",
"use-sidecar": "^1.1.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": { "node_modules/@radix-ui/react-popper": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz",
@ -3684,30 +3269,6 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
}, },
"node_modules/posthog-js": {
"version": "1.147.0",
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.147.0.tgz",
"integrity": "sha512-cALKIcix1W9xMsfUUI/QUFhtBeabDGsQCb3lpZEFd7WCPNLOcGmpeomm4xMX7MO2OnfK6Ov91/HNyfK1wncjSA==",
"dependencies": {
"fflate": "^0.4.8",
"preact": "^10.19.3",
"web-vitals": "^4.0.1"
}
},
"node_modules/posthog-js/node_modules/fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
},
"node_modules/preact": {
"version": "10.22.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz",
"integrity": "sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/pvtsutils": { "node_modules/pvtsutils": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz",
@ -4522,11 +4083,6 @@
"@types/jasmine": "^3.6.3" "@types/jasmine": "^3.6.3"
} }
}, },
"node_modules/web-vitals": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.1.tgz",
"integrity": "sha512-U6bAxeudnhDqcXNl50JC4hLlqox9DZnngxfISZm3DMZnonW35xtJOVUc091L+DOY+6hVZVpKXoiCP0RiT6339Q=="
},
"node_modules/webcrypto-core": { "node_modules/webcrypto-core": {
"version": "1.7.9", "version": "1.7.9",
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz", "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz",

View File

@ -25,7 +25,6 @@
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2", "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
@ -42,7 +41,6 @@
"monaco-themes": "^0.4.4", "monaco-themes": "^0.4.4",
"next": "14.1.3", "next": "14.1.3",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"posthog-js": "^1.147.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18", "react-dom": "^18",
"react-hook-form": "^7.51.3", "react-hook-form": "^7.51.3",

630
package-lock.json generated
View File

@ -1,630 +0,0 @@
{
"name": "sandbox",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@radix-ui/react-popover": "^1.1.1"
}
},
"node_modules/@floating-ui/core": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz",
"integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==",
"dependencies": {
"@floating-ui/utils": "^0.2.7"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.6.10",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz",
"integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==",
"dependencies": {
"@floating-ui/core": "^1.6.0",
"@floating-ui/utils": "^0.2.7"
}
},
"node_modules/@floating-ui/react-dom": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
"integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
"dependencies": {
"@floating-ui/dom": "^1.0.0"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz",
"integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA=="
},
"node_modules/@radix-ui/primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
},
"node_modules/@radix-ui/react-arrow": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
"integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
"dependencies": {
"@radix-ui/react-primitive": "2.0.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
"integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-context": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
"integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz",
"integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-escape-keydown": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
"integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-scope": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz",
"integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popover": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.1.tgz",
"integrity": "sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-dismissable-layer": "1.1.0",
"@radix-ui/react-focus-guards": "1.1.0",
"@radix-ui/react-focus-scope": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-popper": "1.2.0",
"@radix-ui/react-portal": "1.1.1",
"@radix-ui/react-presence": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.7"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
"integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
"dependencies": {
"@floating-ui/react-dom": "^2.0.0",
"@radix-ui/react-arrow": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0",
"@radix-ui/react-use-rect": "1.1.0",
"@radix-ui/react-use-size": "1.1.0",
"@radix-ui/rect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-portal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz",
"integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==",
"dependencies": {
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
"integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
"integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
"dependencies": {
"@radix-ui/react-slot": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
"integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
"integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
"integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
"integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
"dependencies": {
"@radix-ui/rect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-size": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
"integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
},
"node_modules/aria-hidden": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
"integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/detect-node-es": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
},
"node_modules/get-nonce": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
},
"peerDependencies": {
"react": "^18.3.1"
}
},
"node_modules/react-remove-scroll": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
"integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
"dependencies": {
"react-remove-scroll-bar": "^2.3.4",
"react-style-singleton": "^2.2.1",
"tslib": "^2.1.0",
"use-callback-ref": "^1.3.0",
"use-sidecar": "^1.1.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-remove-scroll-bar": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
"dependencies": {
"react-style-singleton": "^2.2.1",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-style-singleton": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
"dependencies": {
"get-nonce": "^1.0.0",
"invariant": "^2.2.4",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/tslib": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
},
"node_modules/use-callback-ref": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
"integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
"dependencies": {
"detect-node-es": "^1.1.0",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
}
}

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"@radix-ui/react-popover": "^1.1.1"
}
}

View File

@ -1,47 +0,0 @@
// Import necessary modules
import { io, Socket } from "socket.io-client";
import dotenv from "dotenv";
dotenv.config();
interface CallbackResponse {
success: boolean;
apps?: string[];
message?: string;
}
let socketRef: Socket = io(
`http://localhost:4000?userId=user_2hFB6KcK6bb3Gx9241UXsxFq4kO&sandboxId=v30a2c48xal03tzio7mapt19`,
{
timeout: 2000,
}
);
socketRef.on("connect", async () => {
console.log("Connected to the server");
await new Promise((resolve) => setTimeout(resolve, 1000));
socketRef.emit("list", (response: CallbackResponse) => {
if (response.success) {
console.log("List of apps:", response.apps);
} else {
console.log("Error:", response.message);
}
});
socketRef.emit("deploy", (response: CallbackResponse) => {
if (response.success) {
console.log("It worked!");
} else {
console.log("Error:", response.message);
}
});
});
socketRef.on("disconnect", () => {
console.log("Disconnected from the server");
});
socketRef.on("connect_error", (error: Error) => {
console.error("Connection error:", error);
});

310
tests/package-lock.json generated
View File

@ -1,310 +0,0 @@
{
"name": "socket-io-test",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "socket-io-test",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"dotenv": "^16.4.5",
"socket.io-client": "^4.7.5",
"ts-node": "^10.9.2"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
},
"node_modules/@tsconfig/node10": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw=="
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
},
"node_modules/@types/node": {
"version": "20.14.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
"peer": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz",
"integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
},
"node_modules/debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dotenv": {
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/engine.io-client": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/socket.io-client": {
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/typescript": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz",
"integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"peer": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
},
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"engines": {
"node": ">=6"
}
}
}
}

View File

@ -1,21 +0,0 @@
{
"name": "socket-io-test",
"version": "1.0.0",
"description": "A test script for socket.io-client using ES6 modules and TypeScript",
"main": "dist/index.js",
"type": "module",
"scripts": {
"build": "tsc",
"start": "npm run build && node dist/index.js"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"dotenv": "^16.4.5",
"socket.io-client": "^4.7.5"
},
"devDependencies": {
"typescript": "^5.0.0",
"ts-node": "^10.9.2"
}
}

View File

@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist"
},
"include": ["index.ts"]
}