Compare commits
130 Commits
collaborat
...
feature/ai
Author | SHA1 | Date | |
---|---|---|---|
7951221310 | |||
fae09d2b6d | |||
9e13db2020 | |||
751d9a3005 | |||
cc4a5307cd | |||
ab7ee17145 | |||
bfc687a3e6 | |||
1365fecb08 | |||
dd59608d73 | |||
62e282da63 | |||
f192d9f3ab | |||
b6569550fc | |||
f863f2f763 | |||
6ea86afc70 | |||
41dbd4a1da | |||
08fccdd506 | |||
cf6888e3d3 | |||
229b489c1e | |||
8ae166fef4 | |||
645ff5b119 | |||
7e48faa1b5 | |||
9d06808137 | |||
63f3b082d5 | |||
8e3a6d1aa6 | |||
023b3bdc5e | |||
01fb3ab921 | |||
13be78dee8 | |||
7a00d24ab9 | |||
69b1287349 | |||
09b3cf1862 | |||
f4c79bbb07 | |||
55fde2f648 | |||
0f619ccb7d | |||
b7230f1bc4 | |||
af45df28d5 | |||
c2a23fcbcb | |||
0f7eb9a856 | |||
0a99eda5ec | |||
c5b197f41c | |||
70cfb5dc3f | |||
6bfff62513 | |||
0b7cc51c6e | |||
a353863523 | |||
c94678c430 | |||
585dcb469e | |||
2f88ff6d58 | |||
0509716f34 | |||
06118e98e9 | |||
4ebd6dea96 | |||
8921cd83bb | |||
45097e0f20 | |||
62e6d64a52 | |||
0c6b2b0dfb | |||
31d74ddc2d | |||
62311faf51 | |||
208d17879f | |||
0067dc8c0c | |||
4fe749daf2 | |||
b01934bd20 | |||
a1990a189c | |||
bf79893dfa | |||
47324f15bf | |||
7149925539 | |||
665e36603f | |||
0679f99bb7 | |||
2065814aaa | |||
1502047bf2 | |||
bbd47db467 | |||
2da60ff4e4 | |||
a15c1f15f5 | |||
ae7ff3f46b | |||
f1a65106b0 | |||
7559e9804f | |||
5132850cb0 | |||
5726cecb22 | |||
6b761cc490 | |||
c674c0cab6 | |||
08c131b52d | |||
618c1e81b1 | |||
c2f4f0b6ff | |||
98da0487e4 | |||
71004c61b2 | |||
170bb45143 | |||
cd59b19ac7 | |||
61235551d3 | |||
86db64a83b | |||
d4c65ad1a3 | |||
aac602d9db | |||
2eb2c4c39b | |||
e8a3944b9e | |||
d0a9c8548c | |||
6c615f1a4f | |||
6a31161c0a | |||
a74f7bf71a | |||
2e68b0b537 | |||
02ea851fb7 | |||
7ed19188d4 | |||
74a4352323 | |||
870783940d | |||
051bf1164a | |||
deb32352fb | |||
de4923ec1e | |||
769f52816f | |||
49ca13a6c8 | |||
dead84ac4d | |||
478a332a2e | |||
2163b1dfb7 | |||
8c3e40975e | |||
62a3d6d8f7 | |||
08d562ee54 | |||
db1410f587 | |||
7a80734c25 | |||
0a21cb2637 | |||
7dd67f72d8 | |||
5bf264b807 | |||
6f6926a621 | |||
1c860bd4d9 | |||
c5247a2aaa | |||
94df975842 | |||
2fbabbd403 | |||
9f0b6a8fdc | |||
c262fb2a31 | |||
ed709210e3 | |||
97c8598717 | |||
9ec59bc781 | |||
687416e6e9 | |||
006c5cea66 | |||
869ae6c148 | |||
7353e88567 | |||
a0fb905a04 |
@ -29,7 +29,9 @@ npm run dev
|
|||||||
|
|
||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
The backend consists of a primary Express and Socket.io server, and 3 Cloudflare Workers microservices for the D1 database, R2 storage, and Workers AI. The D1 database also contains a [service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to the R2 storage worker.
|
The backend consists of a primary Express and Socket.io server, and 3 Cloudflare Workers microservices for the D1 database, R2 storage, and Workers AI. The D1 database also contains a [service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to the R2 storage worker. Each open sandbox instantiates a secure Linux sandboxes on E2B, which is used for the terminal and live preview.
|
||||||
|
|
||||||
|
You will need to make an account on [E2B](https://e2b.dev/) to get an API key.
|
||||||
|
|
||||||
#### Socket.io server
|
#### Socket.io server
|
||||||
|
|
||||||
@ -181,3 +183,4 @@ It should be in the form `category(scope or module): message` in your commit mes
|
|||||||
- [Express](https://expressjs.com/)
|
- [Express](https://expressjs.com/)
|
||||||
- [Socket.io](https://socket.io/)
|
- [Socket.io](https://socket.io/)
|
||||||
- [Drizzle ORM](https://orm.drizzle.team/)
|
- [Drizzle ORM](https://orm.drizzle.team/)
|
||||||
|
- [E2B](https://e2b.dev/)
|
||||||
|
216
backend/ai/package-lock.json
generated
216
backend/ai/package-lock.json
generated
@ -7,6 +7,9 @@
|
|||||||
"": {
|
"": {
|
||||||
"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",
|
||||||
@ -15,6 +18,28 @@
|
|||||||
"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",
|
||||||
@ -861,11 +886,19 @@
|
|||||||
"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",
|
||||||
@ -944,6 +977,17 @@
|
|||||||
"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",
|
||||||
@ -965,6 +1009,17 @@
|
|||||||
"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",
|
||||||
@ -1008,6 +1063,11 @@
|
|||||||
"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",
|
||||||
@ -1141,6 +1201,17 @@
|
|||||||
"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",
|
||||||
@ -1214,6 +1285,14 @@
|
|||||||
"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",
|
||||||
@ -1287,6 +1366,14 @@
|
|||||||
"@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",
|
||||||
@ -1334,6 +1421,36 @@
|
|||||||
"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",
|
||||||
@ -1452,6 +1569,14 @@
|
|||||||
"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",
|
||||||
@ -1610,6 +1735,25 @@
|
|||||||
"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",
|
||||||
@ -1675,8 +1819,7 @@
|
|||||||
"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",
|
||||||
@ -1705,6 +1848,43 @@
|
|||||||
"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",
|
||||||
@ -2222,6 +2402,11 @@
|
|||||||
"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",
|
||||||
@ -2292,8 +2477,7 @@
|
|||||||
"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",
|
||||||
@ -2827,6 +3011,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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",
|
||||||
|
@ -15,5 +15,8 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,121 @@
|
|||||||
|
import { Anthropic } from "@anthropic-ai/sdk";
|
||||||
|
import { MessageParam } from "@anthropic-ai/sdk/src/resources/messages.js";
|
||||||
|
|
||||||
export interface Env {
|
export interface Env {
|
||||||
AI: any
|
ANTHROPIC_API_KEY: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async fetch(request, env): Promise<Response> {
|
async fetch(request: Request, env: Env): Promise<Response> {
|
||||||
if (request.method !== "GET") {
|
// Handle CORS preflight requests
|
||||||
return new Response("Method Not Allowed", { status: 405 })
|
if (request.method === "OPTIONS") {
|
||||||
}
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
||||||
|
"Access-Control-Allow-Headers": "Content-Type",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const url = new URL(request.url)
|
if (request.method !== "GET" && request.method !== "POST") {
|
||||||
const fileName = url.searchParams.get("fileName")
|
return new Response("Method Not Allowed", { status: 405 });
|
||||||
const instructions = url.searchParams.get("instructions")
|
}
|
||||||
const line = url.searchParams.get("line")
|
|
||||||
const code = url.searchParams.get("code")
|
|
||||||
|
|
||||||
const response = await env.AI.run("@cf/meta/llama-3-8b-instruct", {
|
let body;
|
||||||
messages: [
|
let isEditCodeWidget = false;
|
||||||
{
|
if (request.method === "POST") {
|
||||||
role: "system",
|
body = await request.json() as { messages: unknown; context: unknown; activeFileContent: string };
|
||||||
content:
|
} else {
|
||||||
"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.",
|
const url = new URL(request.url);
|
||||||
},
|
const fileName = url.searchParams.get("fileName") || "";
|
||||||
{
|
const code = url.searchParams.get("code") || "";
|
||||||
role: "user",
|
const line = url.searchParams.get("line") || "";
|
||||||
content: `The file is called ${fileName}.`,
|
const instructions = url.searchParams.get("instructions") || "";
|
||||||
},
|
|
||||||
{
|
|
||||||
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
|
|
||||||
|
|
||||||
${code}`,
|
body = {
|
||||||
},
|
messages: [{ role: "human", content: instructions }],
|
||||||
],
|
context: `File: ${fileName}\nLine: ${line}\nCode:\n${code}`,
|
||||||
})
|
activeFileContent: code,
|
||||||
|
};
|
||||||
|
isEditCodeWidget = true;
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(JSON.stringify(response))
|
const messages = body.messages;
|
||||||
},
|
const context = body.context;
|
||||||
} satisfies ExportedHandler<Env>
|
const activeFileContent = body.activeFileContent;
|
||||||
|
|
||||||
|
if (!Array.isArray(messages) || messages.length === 0) {
|
||||||
|
return new Response("Invalid or empty messages", { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let systemMessage;
|
||||||
|
if (isEditCodeWidget) {
|
||||||
|
systemMessage = `You are an AI code editor. Your task is to modify the given code based on the user's instructions. Only output the modified code, without any explanations or markdown formatting. The code should be a direct replacement for the existing code.
|
||||||
|
|
||||||
|
Context:
|
||||||
|
${context}
|
||||||
|
|
||||||
|
Active File Content:
|
||||||
|
${activeFileContent}
|
||||||
|
|
||||||
|
Instructions: ${messages[0].content}
|
||||||
|
|
||||||
|
Respond only with the modified code that can directly replace the existing code.`;
|
||||||
|
} else {
|
||||||
|
systemMessage = `You are an intelligent programming assistant. Please respond to the following request concisely. If your response includes code, please format it using triple backticks (\`\`\`) with the appropriate language identifier. For example:
|
||||||
|
|
||||||
|
\`\`\`python
|
||||||
|
print("Hello, World!")
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
Provide a clear and concise explanation along with any code snippets. Keep your response brief and to the point.
|
||||||
|
|
||||||
|
${context ? `Context:\n${context}\n` : ''}
|
||||||
|
${activeFileContent ? `Active File Content:\n${activeFileContent}\n` : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const anthropicMessages = messages.map(msg => ({
|
||||||
|
role: msg.role === 'human' ? 'user' : 'assistant',
|
||||||
|
content: msg.content
|
||||||
|
})) as MessageParam[];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const anthropic = new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
|
||||||
|
|
||||||
|
const stream = await anthropic.messages.create({
|
||||||
|
model: "claude-3-5-sonnet-20240620",
|
||||||
|
max_tokens: 1024,
|
||||||
|
system: systemMessage,
|
||||||
|
messages: anthropicMessages,
|
||||||
|
stream: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
const streamResponse = new ReadableStream({
|
||||||
|
async start(controller) {
|
||||||
|
for await (const chunk of stream) {
|
||||||
|
if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
|
||||||
|
const bytes = encoder.encode(chunk.delta.text);
|
||||||
|
controller.enqueue(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(streamResponse, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "text/plain; charset=utf-8",
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
return new Response("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -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.enum(["react", "node"]),
|
type: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
visibility: z.enum(["public", "private"]),
|
visibility: z.enum(["public", "private"]),
|
||||||
@ -110,8 +110,13 @@ export default {
|
|||||||
const body = await request.json()
|
const body = await request.json()
|
||||||
const { type, name, userId, visibility } = initSchema.parse(body)
|
const { type, name, userId, visibility } = initSchema.parse(body)
|
||||||
|
|
||||||
const allSandboxes = await db.select().from(sandbox).all()
|
const userSandboxes = await db
|
||||||
if (allSandboxes.length >= 8) {
|
.select()
|
||||||
|
.from(sandbox)
|
||||||
|
.where(eq(sandbox.userId, userId))
|
||||||
|
.all()
|
||||||
|
|
||||||
|
if (userSandboxes.length >= 8) {
|
||||||
return new Response("You reached the maximum # of sandboxes.", {
|
return new Response("You reached the maximum # of sandboxes.", {
|
||||||
status: 400,
|
status: 400,
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@ export const sandbox = sqliteTable("sandbox", {
|
|||||||
.primaryKey()
|
.primaryKey()
|
||||||
.unique(),
|
.unique(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
type: text("type", { enum: ["react", "node"] }).notNull(),
|
type: text("type").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")
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
# 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=
|
||||||
|
DOKKU_HOST=
|
||||||
|
DOKKU_USERNAME=
|
||||||
|
DOKKU_KEY=
|
602
backend/server/package-lock.json
generated
602
backend/server/package-lock.json
generated
@ -12,25 +12,28 @@
|
|||||||
"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.1",
|
"e2b": "^0.16.2-beta.47",
|
||||||
"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.24.5",
|
"version": "7.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||||
"integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
|
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -38,6 +41,28 @@
|
|||||||
"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",
|
||||||
@ -60,9 +85,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
@ -75,10 +100,44 @@
|
|||||||
"@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.1",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||||
"integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg=="
|
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node10": {
|
"node_modules/@tsconfig/node10": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
@ -149,9 +208,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/express-serve-static-core": {
|
"node_modules/@types/express-serve-static-core": {
|
||||||
"version": "4.19.0",
|
"version": "4.19.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz",
|
||||||
"integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
|
"integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@ -173,9 +232,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.7",
|
"version": "20.14.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
||||||
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
"integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
@ -213,11 +272,23 @@
|
|||||||
"@types/send": "*"
|
"@types/send": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/@types/ssh2": {
|
||||||
"version": "1.1.1",
|
"version": "1.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.1.tgz",
|
||||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
"integrity": "sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==",
|
||||||
"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",
|
||||||
@ -232,9 +303,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.11.3",
|
"version": "8.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -244,10 +315,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn-walk": {
|
"node_modules/acorn-walk": {
|
||||||
"version": "8.3.2",
|
"version": "8.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz",
|
||||||
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
|
"integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.11.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
@ -298,6 +372,14 @@
|
|||||||
"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",
|
||||||
@ -312,6 +394,14 @@
|
|||||||
"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",
|
||||||
@ -358,12 +448,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@ -375,6 +465,7 @@
|
|||||||
"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"
|
||||||
},
|
},
|
||||||
@ -382,6 +473,15 @@
|
|||||||
"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",
|
||||||
@ -423,14 +523,6 @@
|
|||||||
"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",
|
||||||
@ -495,6 +587,11 @@
|
|||||||
"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",
|
||||||
@ -527,28 +624,6 @@
|
|||||||
"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",
|
||||||
@ -593,6 +668,20 @@
|
|||||||
"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",
|
||||||
@ -676,56 +765,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/e2b": {
|
"node_modules/e2b": {
|
||||||
"version": "0.16.1",
|
"version": "0.16.2-beta.47",
|
||||||
"resolved": "https://registry.npmjs.org/e2b/-/e2b-0.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/e2b/-/e2b-0.16.2-beta.47.tgz",
|
||||||
"integrity": "sha512-2L1R/REEB+EezD4Q4MmcXXNATjvCYov2lv/69+PY6V95+wl1PZblIMTYAe7USxX6P6sqANxNs+kXqZr6RvXkSw==",
|
"integrity": "sha512-tMPDYLMD+8+JyLPrsWft3NHBhK5YKOFOXzKMwpOKR5KvXOkd1silkArDwplmBUzN/eG/uRzWdtHZs9mHUQ5b9g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isomorphic-ws": "^5.0.0",
|
"@bufbuild/protobuf": "^1.10.0",
|
||||||
"normalize-path": "^3.0.0",
|
"@connectrpc/connect": "^1.4.0",
|
||||||
"openapi-typescript-fetch": "^1.1.3",
|
"@connectrpc/connect-web": "^1.4.0",
|
||||||
"path-browserify": "^1.0.1",
|
"compare-versions": "^6.1.0",
|
||||||
"platform": "^1.3.6",
|
"openapi-fetch": "^0.9.7",
|
||||||
"ws": "^8.15.1"
|
"platform": "^1.3.6"
|
||||||
},
|
},
|
||||||
"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": {
|
||||||
@ -747,9 +799,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io": {
|
"node_modules/engine.io": {
|
||||||
"version": "6.5.4",
|
"version": "6.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
|
||||||
"integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==",
|
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cookie": "^0.4.1",
|
"@types/cookie": "^0.4.1",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@ -760,16 +812,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.11.0"
|
"ws": "~8.17.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.2.0"
|
"node": ">=10.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io-parser": {
|
"node_modules/engine.io-parser": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||||
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
|
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
@ -783,9 +835,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io/node_modules/debug": {
|
"node_modules/engine.io/node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@ -803,6 +855,26 @@
|
|||||||
"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",
|
||||||
@ -885,9 +957,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
@ -1001,12 +1073,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-flag": {
|
"node_modules/has-flag": {
|
||||||
"version": "3.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-property-descriptors": {
|
"node_modules/has-property-descriptors": {
|
||||||
@ -1148,31 +1219,11 @@
|
|||||||
"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",
|
||||||
@ -1247,6 +1298,12 @@
|
|||||||
"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",
|
||||||
@ -1260,6 +1317,7 @@
|
|||||||
"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",
|
||||||
@ -1267,9 +1325,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nodemon": {
|
"node_modules/nodemon": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
|
||||||
"integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==",
|
"integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^3.5.2",
|
"chokidar": "^3.5.2",
|
||||||
@ -1295,9 +1353,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nodemon/node_modules/debug": {
|
"node_modules/nodemon/node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
@ -1311,31 +1369,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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/nopt": {
|
"node_modules/nodemon/node_modules/supports-color": {
|
||||||
"version": "1.0.10",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abbrev": "1"
|
"has-flag": "^3.0.0"
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"nopt": "bin/nopt.js"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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"
|
||||||
}
|
}
|
||||||
@ -1349,9 +1414,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.13.1",
|
"version": "1.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
||||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@ -1367,15 +1435,19 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openapi-typescript-fetch": {
|
"node_modules/openapi-fetch": {
|
||||||
"version": "1.1.3",
|
"version": "0.9.8",
|
||||||
"resolved": "https://registry.npmjs.org/openapi-typescript-fetch/-/openapi-typescript-fetch-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.9.8.tgz",
|
||||||
"integrity": "sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==",
|
"integrity": "sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==",
|
||||||
"engines": {
|
"dependencies": {
|
||||||
"node": ">= 12.0.0",
|
"openapi-typescript-helpers": "^0.0.8"
|
||||||
"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",
|
||||||
@ -1384,11 +1456,6 @@
|
|||||||
"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",
|
||||||
@ -1528,13 +1595,10 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.0",
|
"version": "7.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
},
|
},
|
||||||
@ -1630,6 +1694,41 @@
|
|||||||
"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",
|
||||||
@ -1660,18 +1759,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-adapter": {
|
"node_modules/socket.io-adapter": {
|
||||||
"version": "2.5.4",
|
"version": "2.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||||
"integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==",
|
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "~4.3.4",
|
"debug": "~4.3.4",
|
||||||
"ws": "~8.11.0"
|
"ws": "~8.17.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-adapter/node_modules/debug": {
|
"node_modules/socket.io-adapter/node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@ -1689,6 +1788,26 @@
|
|||||||
"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",
|
||||||
@ -1702,9 +1821,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-parser/node_modules/debug": {
|
"node_modules/socket.io-parser/node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@ -1723,9 +1842,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.4",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@ -1748,6 +1867,23 @@
|
|||||||
"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",
|
||||||
@ -1781,15 +1917,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/supports-color": {
|
"node_modules/supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "8.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-flag": "^3.0.0"
|
"has-flag": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
@ -1813,13 +1951,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/touch": {
|
"node_modules/touch": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"nopt": "~1.0.10"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"nodetouch": "bin/nodetouch.js"
|
"nodetouch": "bin/nodetouch.js"
|
||||||
}
|
}
|
||||||
@ -1876,9 +2011,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
|
||||||
|
},
|
||||||
|
"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",
|
||||||
@ -1893,9 +2033,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.5",
|
"version": "5.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@ -1925,9 +2065,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/utf-8-validate": {
|
"node_modules/utf-8-validate": {
|
||||||
"version": "5.0.10",
|
"version": "6.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz",
|
||||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
"integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@ -1976,26 +2116,6 @@
|
|||||||
"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",
|
||||||
@ -2004,12 +2124,6 @@
|
|||||||
"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",
|
||||||
@ -2045,9 +2159,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zod": {
|
"node_modules/zod": {
|
||||||
"version": "3.22.4",
|
"version": "3.23.8",
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||||
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
|
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,19 @@
|
|||||||
"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.1",
|
"e2b": "^0.16.2-beta.47",
|
||||||
"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"
|
||||||
|
37
backend/server/src/DokkuClient.ts
Normal file
37
backend/server/src/DokkuClient.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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 };
|
90
backend/server/src/SSHSocketClient.ts
Normal file
90
backend/server/src/SSHSocketClient.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
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()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
82
backend/server/src/SecureGitClient.ts
Normal file
82
backend/server/src/SecureGitClient.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
backend/server/src/Terminal.ts
Normal file
67
backend/server/src/Terminal.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
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();
|
@ -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.includes(".");
|
const isFile = i === parts.length - 1 && part.length;
|
||||||
const existing = current.children.find((child) => child.name === part);
|
const existing = current.children.find((child) => child.name === part);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
32
backend/storage/package-lock.json
generated
32
backend/storage/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"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": {
|
||||||
@ -894,6 +895,21 @@
|
|||||||
"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",
|
||||||
@ -1766,12 +1782,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-limit": {
|
"node_modules/p-limit": {
|
||||||
"version": "5.0.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz",
|
||||||
"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
|
"integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yocto-queue": "^1.0.0"
|
"yocto-queue": "^1.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@ -2970,10 +2985,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/yocto-queue": {
|
"node_modules/yocto-queue": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
|
||||||
"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
|
"integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.20"
|
"node": ">=12.20"
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"wrangler": "^3.0.0"
|
"wrangler": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"p-limit": "^6.1.0",
|
||||||
"zod": "^3.23.4"
|
"zod": "^3.23.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import startercode from "./startercode"
|
import pLimit from 'p-limit';
|
||||||
|
|
||||||
export interface Env {
|
export interface Env {
|
||||||
R2: R2Bucket
|
R2: R2Bucket
|
||||||
|
Templates: R2Bucket
|
||||||
KEY: string
|
KEY: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,19 +138,26 @@ 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.enum(["react", "node"]),
|
type: z.string(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const body = await request.json()
|
const body = await request.json()
|
||||||
const { sandboxId, type } = initSchema.parse(body)
|
const { sandboxId, type } = initSchema.parse(body)
|
||||||
|
|
||||||
console.log(startercode[type])
|
console.log(`Copying template: ${type}`);
|
||||||
|
|
||||||
await Promise.all(
|
// List all objects under the directory
|
||||||
startercode[type].map(async (file) => {
|
const { objects } = await env.Templates.list({ prefix: type });
|
||||||
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 {
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
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
|
|
@ -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_PORT=4000
|
NEXT_PUBLIC_SERVER_URL=http://localhost: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.
|
||||||
|
@ -6,6 +6,7 @@ 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
|
||||||
|
|
||||||
@ -63,14 +64,6 @@ 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
|
||||||
@ -94,20 +87,21 @@ 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>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ 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",
|
||||||
@ -13,7 +15,7 @@ export const metadata: Metadata = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}>) {
|
}>) {
|
||||||
@ -27,7 +29,11 @@ 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>
|
||||||
|
13
frontend/app/providers.js
Normal file
13
frontend/app/providers.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"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>
|
||||||
|
}
|
@ -49,11 +49,9 @@ export default function Dashboard({
|
|||||||
const q = searchParams.get("q")
|
const q = searchParams.get("q")
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => { // update the dashboard to show a new project
|
||||||
if (!sandboxes) {
|
|
||||||
router.refresh()
|
router.refresh()
|
||||||
}
|
}, [])
|
||||||
}, [sandboxes])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -36,45 +36,7 @@ import { createSandbox } from "@/lib/actions"
|
|||||||
import { useRouter } from "next/navigation"
|
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"
|
||||||
|
import { projectTemplates } from "@/lib/data"
|
||||||
type TOptions = "react" | "node" | "python" | "more"
|
|
||||||
|
|
||||||
const data: {
|
|
||||||
id: TOptions
|
|
||||||
name: string
|
|
||||||
icon: string
|
|
||||||
description: string
|
|
||||||
disabled: boolean
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
id: "react",
|
|
||||||
name: "React",
|
|
||||||
icon: "/project-icons/react.svg",
|
|
||||||
description: "A JavaScript library for building user interfaces",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "node",
|
|
||||||
name: "Node",
|
|
||||||
icon: "/project-icons/node.svg",
|
|
||||||
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "python",
|
|
||||||
name: "Python",
|
|
||||||
icon: "/project-icons/python.svg",
|
|
||||||
description: "A high-level, general-purpose language, coming soon",
|
|
||||||
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({
|
||||||
name: z
|
name: z
|
||||||
@ -95,7 +57,7 @@ export default function NewProjectModal({
|
|||||||
open: boolean
|
open: boolean
|
||||||
setOpen: (open: boolean) => void
|
setOpen: (open: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
const [selected, setSelected] = useState<TOptions>("react")
|
const [selected, setSelected] = useState("reactjs")
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@ -126,12 +88,12 @@ export default function NewProjectModal({
|
|||||||
if (!loading) setOpen(open)
|
if (!loading) setOpen(open)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogContent>
|
<DialogContent className="max-h-[95vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Create A Sandbox</DialogTitle>
|
<DialogTitle>Create A Sandbox</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="grid grid-cols-2 w-full gap-2 mt-2">
|
<div className="grid grid-cols-2 w-full gap-2 mt-2">
|
||||||
{data.map((item) => (
|
{projectTemplates.map((item) => (
|
||||||
<button
|
<button
|
||||||
disabled={item.disabled || loading}
|
disabled={item.disabled || loading}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
|
@ -8,6 +8,7 @@ import { Clock, Globe, Lock } from "lucide-react"
|
|||||||
import { Sandbox } from "@/lib/types"
|
import { Sandbox } from "@/lib/types"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
|
import { projectTemplates } from "@/lib/data"
|
||||||
|
|
||||||
export default function ProjectCard({
|
export default function ProjectCard({
|
||||||
children,
|
children,
|
||||||
@ -43,7 +44,9 @@ export default function ProjectCard({
|
|||||||
setDate(`${Math.floor(diffInMinutes / 1440)}d ago`)
|
setDate(`${Math.floor(diffInMinutes / 1440)}d ago`)
|
||||||
}
|
}
|
||||||
}, [sandbox])
|
}, [sandbox])
|
||||||
|
const projectIcon =
|
||||||
|
projectTemplates.find((p) => p.id === sandbox.type)?.icon ??
|
||||||
|
"/project-icons/node.svg"
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@ -65,16 +68,7 @@ export default function ProjectCard({
|
|||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
<div className="space-x-2 flex items-center justify-start w-full z-10">
|
<div className="space-x-2 flex items-center justify-start w-full z-10">
|
||||||
<Image
|
<Image alt="" src={projectIcon} width={20} height={20} />
|
||||||
alt=""
|
|
||||||
src={
|
|
||||||
sandbox.type === "react"
|
|
||||||
? "/project-icons/react.svg"
|
|
||||||
: "/project-icons/node.svg"
|
|
||||||
}
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
<div className="font-medium static whitespace-nowrap w-full text-ellipsis overflow-hidden">
|
<div className="font-medium static whitespace-nowrap w-full text-ellipsis overflow-hidden">
|
||||||
{sandbox.name}
|
{sandbox.name}
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 = {
|
const colors: { [key: string]: number[][] } = {
|
||||||
react: [
|
react: [
|
||||||
[71, 207, 237],
|
[71, 207, 237],
|
||||||
[30, 126, 148],
|
[30, 126, 148],
|
||||||
|
36
frontend/components/editor/AIChat/ChatInput.tsx
Normal file
36
frontend/components/editor/AIChat/ChatInput.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Button } from '../../ui/button';
|
||||||
|
import { Send, StopCircle } from 'lucide-react';
|
||||||
|
|
||||||
|
interface ChatInputProps {
|
||||||
|
input: string;
|
||||||
|
setInput: (input: string) => void;
|
||||||
|
isGenerating: boolean;
|
||||||
|
handleSend: () => void;
|
||||||
|
handleStopGeneration: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ChatInput({ input, setInput, isGenerating, handleSend, handleStopGeneration }: ChatInputProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex space-x-2 min-w-0">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={input}
|
||||||
|
onChange={(e) => setInput(e.target.value)}
|
||||||
|
onKeyPress={(e) => e.key === 'Enter' && !isGenerating && handleSend()}
|
||||||
|
className="flex-grow p-2 border rounded-lg min-w-0 bg-input"
|
||||||
|
placeholder="Type your message..."
|
||||||
|
disabled={isGenerating}
|
||||||
|
/>
|
||||||
|
{isGenerating ? (
|
||||||
|
<Button onClick={handleStopGeneration} variant="destructive" size="icon" className="h-10 w-10">
|
||||||
|
<StopCircle className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={handleSend} disabled={isGenerating} size="icon" className="h-10 w-10">
|
||||||
|
<Send className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
201
frontend/components/editor/AIChat/ChatMessage.tsx
Normal file
201
frontend/components/editor/AIChat/ChatMessage.tsx
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Button } from '../../ui/button';
|
||||||
|
import { ChevronUp, ChevronDown, Copy, Check, CornerUpLeft } from 'lucide-react';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
|
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import { copyToClipboard, stringifyContent } from './lib/chatUtils';
|
||||||
|
|
||||||
|
interface MessageProps {
|
||||||
|
message: {
|
||||||
|
role: 'user' | 'assistant';
|
||||||
|
content: string;
|
||||||
|
context?: string;
|
||||||
|
};
|
||||||
|
setContext: (context: string | null) => void;
|
||||||
|
setIsContextExpanded: (isExpanded: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ChatMessage({ message, setContext, setIsContextExpanded }: MessageProps) {
|
||||||
|
const [expandedMessageIndex, setExpandedMessageIndex] = useState<number | null>(null);
|
||||||
|
const [copiedText, setCopiedText] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const renderCopyButton = (text: any) => (
|
||||||
|
<Button
|
||||||
|
onClick={() => copyToClipboard(stringifyContent(text), setCopiedText)}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="p-1 h-6"
|
||||||
|
>
|
||||||
|
{copiedText === stringifyContent(text) ? (
|
||||||
|
<Check className="w-4 h-4 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<Copy className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const askAboutCode = (code: any) => {
|
||||||
|
const contextString = stringifyContent(code);
|
||||||
|
setContext(`Regarding this code:\n${contextString}`);
|
||||||
|
setIsContextExpanded(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderMarkdownElement = (props: any) => {
|
||||||
|
const { node, children } = props;
|
||||||
|
const content = stringifyContent(children);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative group">
|
||||||
|
<div className="absolute top-0 right-0 flex opacity-0 group-hover:opacity-30 transition-opacity">
|
||||||
|
{renderCopyButton(content)}
|
||||||
|
<Button
|
||||||
|
onClick={() => askAboutCode(content)}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="p-1 h-6"
|
||||||
|
>
|
||||||
|
<CornerUpLeft className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{React.createElement(node.tagName, {
|
||||||
|
...props,
|
||||||
|
className: `${props.className || ''} hover:bg-transparent rounded p-1 transition-colors`
|
||||||
|
}, children)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-left relative">
|
||||||
|
<div className={`relative p-2 rounded-lg ${
|
||||||
|
message.role === 'user'
|
||||||
|
? 'bg-[#262626] text-white'
|
||||||
|
: 'bg-transparent text-white'
|
||||||
|
} max-w-full`}>
|
||||||
|
{message.role === 'user' && (
|
||||||
|
<div className="absolute top-0 right-0 flex opacity-0 group-hover:opacity-30 transition-opacity">
|
||||||
|
{renderCopyButton(message.content)}
|
||||||
|
<Button
|
||||||
|
onClick={() => askAboutCode(message.content)}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="p-1 h-6"
|
||||||
|
>
|
||||||
|
<CornerUpLeft className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{message.context && (
|
||||||
|
<div className="mb-2 bg-input rounded-lg">
|
||||||
|
<div
|
||||||
|
className="flex justify-between items-center cursor-pointer"
|
||||||
|
onClick={() => setExpandedMessageIndex(expandedMessageIndex === 0 ? null : 0)}
|
||||||
|
>
|
||||||
|
<span className="text-sm text-gray-300">
|
||||||
|
Context
|
||||||
|
</span>
|
||||||
|
{expandedMessageIndex === 0 ? (
|
||||||
|
<ChevronUp size={16} />
|
||||||
|
) : (
|
||||||
|
<ChevronDown size={16} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{expandedMessageIndex === 0 && (
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute top-0 right-0 flex p-1">
|
||||||
|
{renderCopyButton(message.context.replace(/^Regarding this code:\n/, ''))}
|
||||||
|
</div>
|
||||||
|
{(() => {
|
||||||
|
const code = message.context.replace(/^Regarding this code:\n/, '');
|
||||||
|
const match = /language-(\w+)/.exec(code);
|
||||||
|
const language = match ? match[1] : 'typescript';
|
||||||
|
return (
|
||||||
|
<div className="pt-6">
|
||||||
|
<textarea
|
||||||
|
value={code}
|
||||||
|
onChange={(e) => {
|
||||||
|
const updatedContext = `Regarding this code:\n${e.target.value}`;
|
||||||
|
setContext(updatedContext);
|
||||||
|
}}
|
||||||
|
className="w-full p-2 bg-[#1e1e1e] text-white font-mono text-sm rounded"
|
||||||
|
rows={code.split('\n').length}
|
||||||
|
style={{
|
||||||
|
resize: 'vertical',
|
||||||
|
minHeight: '100px',
|
||||||
|
maxHeight: '400px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{message.role === 'assistant' ? (
|
||||||
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
components={{
|
||||||
|
code({node, className, children, ...props}) {
|
||||||
|
const match = /language-(\w+)/.exec(className || '');
|
||||||
|
return match ? (
|
||||||
|
<div className="relative border border-input rounded-md my-4">
|
||||||
|
<div className="absolute top-0 left-0 px-2 py-1 text-xs font-semibold text-gray-200 bg-#1e1e1e rounded-tl">
|
||||||
|
{match[1]}
|
||||||
|
</div>
|
||||||
|
<div className="absolute top-0 right-0 flex">
|
||||||
|
{renderCopyButton(children)}
|
||||||
|
<Button
|
||||||
|
onClick={() => askAboutCode(children)}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="p-1 h-6"
|
||||||
|
>
|
||||||
|
<CornerUpLeft className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="pt-6">
|
||||||
|
<SyntaxHighlighter
|
||||||
|
style={vscDarkPlus as any}
|
||||||
|
language={match[1]}
|
||||||
|
PreTag="div"
|
||||||
|
customStyle={{
|
||||||
|
margin: 0,
|
||||||
|
padding: '0.5rem',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{stringifyContent(children)}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<code className={className} {...props}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
p: renderMarkdownElement,
|
||||||
|
h1: renderMarkdownElement,
|
||||||
|
h2: renderMarkdownElement,
|
||||||
|
h3: renderMarkdownElement,
|
||||||
|
h4: renderMarkdownElement,
|
||||||
|
h5: renderMarkdownElement,
|
||||||
|
h6: renderMarkdownElement,
|
||||||
|
ul: (props) => <ul className="list-disc pl-6 mb-4 space-y-2">{props.children}</ul>,
|
||||||
|
ol: (props) => <ol className="list-decimal pl-6 mb-4 space-y-2">{props.children}</ol>,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message.content}
|
||||||
|
</ReactMarkdown>
|
||||||
|
) : (
|
||||||
|
<div className="whitespace-pre-wrap group">
|
||||||
|
{message.content}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
48
frontend/components/editor/AIChat/ContextDisplay.tsx
Normal file
48
frontend/components/editor/AIChat/ContextDisplay.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ChevronUp, ChevronDown, X } from 'lucide-react';
|
||||||
|
|
||||||
|
interface ContextDisplayProps {
|
||||||
|
context: string | null;
|
||||||
|
isContextExpanded: boolean;
|
||||||
|
setIsContextExpanded: (isExpanded: boolean) => void;
|
||||||
|
setContext: (context: string | null) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ContextDisplay({ context, isContextExpanded, setIsContextExpanded, setContext }: ContextDisplayProps) {
|
||||||
|
if (!context) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-2 bg-input p-2 rounded-lg">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div
|
||||||
|
className="flex-grow cursor-pointer"
|
||||||
|
onClick={() => setIsContextExpanded(!isContextExpanded)}
|
||||||
|
>
|
||||||
|
<span className="text-sm text-gray-300">
|
||||||
|
Context
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{isContextExpanded ? (
|
||||||
|
<ChevronUp size={16} className="cursor-pointer" onClick={() => setIsContextExpanded(false)} />
|
||||||
|
) : (
|
||||||
|
<ChevronDown size={16} className="cursor-pointer" onClick={() => setIsContextExpanded(true)} />
|
||||||
|
)}
|
||||||
|
<X
|
||||||
|
size={16}
|
||||||
|
className="ml-2 cursor-pointer text-gray-400 hover:text-gray-200"
|
||||||
|
onClick={() => setContext(null)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{isContextExpanded && (
|
||||||
|
<textarea
|
||||||
|
value={context.replace(/^Regarding this code:\n/, '')}
|
||||||
|
onChange={(e) => setContext(`Regarding this code:\n${e.target.value}`)}
|
||||||
|
className="w-full mt-2 p-2 bg-#1e1e1e text-white rounded"
|
||||||
|
rows={5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
84
frontend/components/editor/AIChat/index.tsx
Normal file
84
frontend/components/editor/AIChat/index.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import LoadingDots from '../../ui/LoadingDots';
|
||||||
|
import ChatMessage from './ChatMessage';
|
||||||
|
import ChatInput from './ChatInput';
|
||||||
|
import ContextDisplay from './ContextDisplay';
|
||||||
|
import { handleSend, handleStopGeneration } from './lib/chatUtils';
|
||||||
|
import { X } from 'lucide-react';
|
||||||
|
|
||||||
|
interface Message {
|
||||||
|
role: 'user' | 'assistant';
|
||||||
|
content: string;
|
||||||
|
context?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AIChat({ activeFileContent, activeFileName, onClose }: { activeFileContent: string, activeFileName: string, onClose: () => void }) {
|
||||||
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
|
const [input, setInput] = useState('');
|
||||||
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
|
const chatContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
|
const [context, setContext] = useState<string | null>(null);
|
||||||
|
const [isContextExpanded, setIsContextExpanded] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
if (chatContainerRef.current) {
|
||||||
|
setTimeout(() => {
|
||||||
|
chatContainerRef.current?.scrollTo({
|
||||||
|
top: chatContainerRef.current.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-screen w-full">
|
||||||
|
<div className="flex justify-between items-center p-2 border-b">
|
||||||
|
<span className="text-muted-foreground/50 font-medium">CHAT</span>
|
||||||
|
<div className="flex items-center h-full">
|
||||||
|
<span className="text-muted-foreground/50 font-medium">{activeFileName}</span>
|
||||||
|
<div className="mx-2 h-full w-px bg-muted-foreground/20"></div>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="text-muted-foreground/50 hover:text-muted-foreground focus:outline-none"
|
||||||
|
aria-label="Close AI Chat"
|
||||||
|
>
|
||||||
|
<X size={18} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ref={chatContainerRef} className="flex-grow overflow-y-auto p-4 space-y-4">
|
||||||
|
{messages.map((message, messageIndex) => (
|
||||||
|
<ChatMessage
|
||||||
|
key={messageIndex}
|
||||||
|
message={message}
|
||||||
|
setContext={setContext}
|
||||||
|
setIsContextExpanded={setIsContextExpanded}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{isLoading && <LoadingDots />}
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border-t mb-14">
|
||||||
|
<ContextDisplay
|
||||||
|
context={context}
|
||||||
|
isContextExpanded={isContextExpanded}
|
||||||
|
setIsContextExpanded={setIsContextExpanded}
|
||||||
|
setContext={setContext}
|
||||||
|
/>
|
||||||
|
<ChatInput
|
||||||
|
input={input}
|
||||||
|
setInput={setInput}
|
||||||
|
isGenerating={isGenerating}
|
||||||
|
handleSend={() => handleSend(input, context, messages, setMessages, setInput, setIsContextExpanded, setIsGenerating, setIsLoading, abortControllerRef, activeFileContent)}
|
||||||
|
handleStopGeneration={() => handleStopGeneration(abortControllerRef)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
162
frontend/components/editor/AIChat/lib/chatUtils.ts
Normal file
162
frontend/components/editor/AIChat/lib/chatUtils.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const stringifyContent = (content: any, seen = new WeakSet()): string => {
|
||||||
|
if (typeof content === 'string') {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
if (content === null) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
if (content === undefined) {
|
||||||
|
return 'undefined';
|
||||||
|
}
|
||||||
|
if (typeof content === 'number' || typeof content === 'boolean') {
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
if (typeof content === 'function') {
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
if (typeof content === 'symbol') {
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
if (typeof content === 'bigint') {
|
||||||
|
return content.toString() + 'n';
|
||||||
|
}
|
||||||
|
if (React.isValidElement(content)) {
|
||||||
|
return React.Children.toArray((content as React.ReactElement).props.children)
|
||||||
|
.map(child => stringifyContent(child, seen))
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
if (Array.isArray(content)) {
|
||||||
|
return '[' + content.map(item => stringifyContent(item, seen)).join(', ') + ']';
|
||||||
|
}
|
||||||
|
if (typeof content === 'object') {
|
||||||
|
if (seen.has(content)) {
|
||||||
|
return '[Circular]';
|
||||||
|
}
|
||||||
|
seen.add(content);
|
||||||
|
try {
|
||||||
|
const pairs = Object.entries(content).map(
|
||||||
|
([key, value]) => `${key}: ${stringifyContent(value, seen)}`
|
||||||
|
);
|
||||||
|
return '{' + pairs.join(', ') + '}';
|
||||||
|
} catch (error) {
|
||||||
|
return Object.prototype.toString.call(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const copyToClipboard = (text: string, setCopiedText: (text: string | null) => void) => {
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
setCopiedText(text);
|
||||||
|
setTimeout(() => setCopiedText(null), 2000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleSend = async (
|
||||||
|
input: string,
|
||||||
|
context: string | null,
|
||||||
|
messages: any[],
|
||||||
|
setMessages: React.Dispatch<React.SetStateAction<any[]>>,
|
||||||
|
setInput: React.Dispatch<React.SetStateAction<string>>,
|
||||||
|
setIsContextExpanded: React.Dispatch<React.SetStateAction<boolean>>,
|
||||||
|
setIsGenerating: React.Dispatch<React.SetStateAction<boolean>>,
|
||||||
|
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>,
|
||||||
|
abortControllerRef: React.MutableRefObject<AbortController | null>,
|
||||||
|
activeFileContent: string
|
||||||
|
) => {
|
||||||
|
if (input.trim() === '' && !context) return;
|
||||||
|
|
||||||
|
const newMessage = {
|
||||||
|
role: 'user' as const,
|
||||||
|
content: input,
|
||||||
|
context: context || undefined
|
||||||
|
};
|
||||||
|
const updatedMessages = [...messages, newMessage];
|
||||||
|
setMessages(updatedMessages);
|
||||||
|
setInput('');
|
||||||
|
setIsContextExpanded(false);
|
||||||
|
setIsGenerating(true);
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
abortControllerRef.current = new AbortController();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const anthropicMessages = updatedMessages.map(msg => ({
|
||||||
|
role: msg.role === 'user' ? 'human' : 'assistant',
|
||||||
|
content: msg.content
|
||||||
|
}));
|
||||||
|
|
||||||
|
const response = await fetch(`${process.env.NEXT_PUBLIC_AI_WORKER_URL}/api`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
messages: anthropicMessages,
|
||||||
|
context: context || undefined,
|
||||||
|
activeFileContent: activeFileContent,
|
||||||
|
}),
|
||||||
|
signal: abortControllerRef.current.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to get AI response');
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body?.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
const assistantMessage = { role: 'assistant' as const, content: '' };
|
||||||
|
setMessages([...updatedMessages, assistantMessage]);
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
let buffer = '';
|
||||||
|
const updateInterval = 100;
|
||||||
|
let lastUpdateTime = Date.now();
|
||||||
|
|
||||||
|
if (reader) {
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
buffer += decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
if (currentTime - lastUpdateTime > updateInterval) {
|
||||||
|
setMessages(prev => {
|
||||||
|
const updatedMessages = [...prev];
|
||||||
|
const lastMessage = updatedMessages[updatedMessages.length - 1];
|
||||||
|
lastMessage.content = buffer;
|
||||||
|
return updatedMessages;
|
||||||
|
});
|
||||||
|
lastUpdateTime = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMessages(prev => {
|
||||||
|
const updatedMessages = [...prev];
|
||||||
|
const lastMessage = updatedMessages[updatedMessages.length - 1];
|
||||||
|
lastMessage.content = buffer;
|
||||||
|
return updatedMessages;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.name === 'AbortError') {
|
||||||
|
console.log('Generation aborted');
|
||||||
|
} else {
|
||||||
|
console.error('Error fetching AI response:', error);
|
||||||
|
const errorMessage = { role: 'assistant' as const, content: 'Sorry, I encountered an error. Please try again.' };
|
||||||
|
setMessages(prev => [...prev, errorMessage]);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsGenerating(false);
|
||||||
|
setIsLoading(false);
|
||||||
|
abortControllerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleStopGeneration = (abortControllerRef: React.MutableRefObject<AbortController | null>) => {
|
||||||
|
if (abortControllerRef.current) {
|
||||||
|
abortControllerRef.current.abort();
|
||||||
|
}
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useCallback, 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 >= 10) {
|
if (user.generations >= 1000) {
|
||||||
toast.error("You reached the maximum # of generations.")
|
toast.error("You reached the maximum # of generations.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -84,6 +84,13 @@ export default function GenerateInput({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
const handleGenerateForm = useCallback(
|
||||||
|
(e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault()
|
||||||
|
handleGenerate({ regenerate: false })
|
||||||
|
},
|
||||||
|
[input, currentPrompt]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (code) {
|
if (code) {
|
||||||
@ -93,9 +100,23 @@ 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">
|
||||||
<div className="flex items-center font-sans space-x-2">
|
<form
|
||||||
|
onSubmit={handleGenerateForm}
|
||||||
|
className="flex items-center font-sans space-x-2"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
style={{
|
style={{
|
||||||
@ -109,8 +130,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 ? (
|
||||||
<>
|
<>
|
||||||
@ -126,13 +147,14 @@ 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>
|
||||||
</div>
|
</form>
|
||||||
{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
78
frontend/components/editor/navbar/deploy.tsx
Normal file
78
frontend/components/editor/navbar/deploy.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
"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>
|
||||||
|
);
|
||||||
|
}
|
@ -11,6 +11,8 @@ 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,
|
||||||
@ -19,15 +21,13 @@ export default function Navbar({
|
|||||||
}: {
|
}: {
|
||||||
userData: User;
|
userData: User;
|
||||||
sandboxData: Sandbox;
|
sandboxData: Sandbox;
|
||||||
shared: {
|
shared: { id: string; name: string }[];
|
||||||
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,14 +62,25 @@ 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>
|
||||||
|
73
frontend/components/editor/navbar/run.tsx
Normal file
73
frontend/components/editor/navbar/run.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
"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>
|
||||||
|
);
|
||||||
|
}
|
@ -1,34 +1,38 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChevronLeft,
|
|
||||||
ChevronRight,
|
|
||||||
Globe,
|
|
||||||
Link,
|
Link,
|
||||||
RotateCw,
|
RotateCw,
|
||||||
TerminalSquare,
|
TerminalSquare,
|
||||||
UnfoldVertical,
|
UnfoldVertical,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { useRef, useState } from "react"
|
import { useEffect, useRef, useState, useImperativeHandle, forwardRef } from "react"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
|
|
||||||
export default function PreviewWindow({
|
export default forwardRef(function PreviewWindow({
|
||||||
collapsed,
|
collapsed,
|
||||||
open,
|
open,
|
||||||
|
src
|
||||||
}: {
|
}: {
|
||||||
collapsed: boolean
|
collapsed: boolean
|
||||||
open: () => void
|
open: () => void
|
||||||
}) {
|
src: string
|
||||||
const ref = useRef<HTMLIFrameElement>(null)
|
},
|
||||||
|
ref: React.Ref<{
|
||||||
|
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
|
|
||||||
className={`${
|
|
||||||
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">
|
||||||
@ -38,48 +42,28 @@ export default function PreviewWindow({
|
|||||||
</PreviewButton>
|
</PreviewButton>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* Todo, make this open inspector */}
|
<PreviewButton onClick={open}>
|
||||||
{/* <PreviewButton disabled onClick={() => {}}>
|
<UnfoldVertical className="w-4 h-4" />
|
||||||
<TerminalSquare className="w-4 h-4" />
|
</PreviewButton>
|
||||||
</PreviewButton> */}
|
|
||||||
|
|
||||||
<PreviewButton
|
<PreviewButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(`http://localhost:5173`)
|
navigator.clipboard.writeText(src)
|
||||||
toast.info("Copied preview link to clipboard")
|
toast.info("Copied preview link to clipboard")
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Link className="w-4 h-4" />
|
<Link className="w-4 h-4" />
|
||||||
</PreviewButton>
|
</PreviewButton>
|
||||||
<PreviewButton
|
<PreviewButton onClick={refreshIframe}>
|
||||||
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>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{collapsed ? null : (
|
|
||||||
<div className="w-full grow rounded-md overflow-hidden bg-foreground">
|
|
||||||
<iframe
|
|
||||||
key={iframeKey}
|
|
||||||
ref={ref}
|
|
||||||
width={"100%"}
|
|
||||||
height={"100%"}
|
|
||||||
src={`http://localhost:5173`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
function PreviewButton({
|
function PreviewButton({
|
||||||
children,
|
children,
|
||||||
@ -92,9 +76,8 @@ function PreviewButton({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${disabled ? "pointer-events-none opacity-50" : ""
|
||||||
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`}
|
||||||
} 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}
|
||||||
|
@ -90,9 +90,9 @@ export default function SidebarFile({
|
|||||||
if (!editing && !pendingDelete && !isMoving)
|
if (!editing && !pendingDelete && !isMoving)
|
||||||
selectFile({ ...data, saved: true });
|
selectFile({ ...data, saved: true });
|
||||||
}}
|
}}
|
||||||
// onDoubleClick={() => {
|
onDoubleClick={() => {
|
||||||
// setEditing(true)
|
setEditing(true)
|
||||||
// }}
|
}}
|
||||||
className={`${
|
className={`${
|
||||||
dragging ? "opacity-50 hover:!bg-background" : ""
|
dragging ? "opacity-50 hover:!bg-background" : ""
|
||||||
} data-[state=open]:bg-secondary/50 w-full flex items-center h-7 px-1 hover:bg-secondary rounded-sm cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring`}
|
} data-[state=open]:bg-secondary/50 w-full flex items-center h-7 px-1 hover:bg-secondary rounded-sm cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring`}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
"use client";
|
"use client"
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image"
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react"
|
||||||
import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js";
|
import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js"
|
||||||
import { TFile, TFolder, TTab } from "@/lib/types";
|
import { TFile, TFolder, TTab } from "@/lib/types"
|
||||||
import SidebarFile from "./file";
|
import SidebarFile from "./file"
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
ContextMenuContent,
|
ContextMenuContent,
|
||||||
ContextMenuItem,
|
ContextMenuItem,
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
} from "@/components/ui/context-menu";
|
} from "@/components/ui/context-menu"
|
||||||
import { Loader2, Pencil, Trash2 } from "lucide-react";
|
import { ChevronRight, Loader2, Pencil, Trash2 } from "lucide-react"
|
||||||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { motion, AnimatePresence } from "framer-motion"
|
||||||
|
|
||||||
// Note: Renaming has not been implemented in the backend yet, so UI relating to renaming is commented out
|
// Note: Renaming has not been implemented in the backend yet, so UI relating to renaming is commented out
|
||||||
|
|
||||||
@ -25,27 +27,27 @@ export default function SidebarFolder({
|
|||||||
movingId,
|
movingId,
|
||||||
deletingFolderId,
|
deletingFolderId,
|
||||||
}: {
|
}: {
|
||||||
data: TFolder;
|
data: TFolder
|
||||||
selectFile: (file: TTab) => void;
|
selectFile: (file: TTab) => void
|
||||||
handleRename: (
|
handleRename: (
|
||||||
id: string,
|
id: string,
|
||||||
newName: string,
|
newName: string,
|
||||||
oldName: string,
|
oldName: string,
|
||||||
type: "file" | "folder"
|
type: "file" | "folder"
|
||||||
) => boolean;
|
) => boolean
|
||||||
handleDeleteFile: (file: TFile) => void;
|
handleDeleteFile: (file: TFile) => void
|
||||||
handleDeleteFolder: (folder: TFolder) => void;
|
handleDeleteFolder: (folder: TFolder) => void
|
||||||
movingId: string;
|
movingId: string
|
||||||
deletingFolderId: string;
|
deletingFolderId: string
|
||||||
}) {
|
}) {
|
||||||
const ref = useRef(null); // drop target
|
const ref = useRef(null) // drop target
|
||||||
const [isDraggedOver, setIsDraggedOver] = useState(false);
|
const [isDraggedOver, setIsDraggedOver] = useState(false)
|
||||||
|
|
||||||
const isDeleting =
|
const isDeleting =
|
||||||
deletingFolderId.length > 0 && data.id.startsWith(deletingFolderId);
|
deletingFolderId.length > 0 && data.id.startsWith(deletingFolderId)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = ref.current;
|
const el = ref.current
|
||||||
|
|
||||||
if (el)
|
if (el)
|
||||||
return dropTargetForElements({
|
return dropTargetForElements({
|
||||||
@ -67,17 +69,17 @@ export default function SidebarFolder({
|
|||||||
|
|
||||||
// no dropping while awaiting move
|
// no dropping while awaiting move
|
||||||
canDrop: () => {
|
canDrop: () => {
|
||||||
return !movingId;
|
return !movingId
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
const folder = isOpen
|
const folder = isOpen
|
||||||
? getIconForOpenFolder(data.name)
|
? getIconForOpenFolder(data.name)
|
||||||
: getIconForFolder(data.name);
|
: getIconForFolder(data.name)
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
// const [editing, setEditing] = useState(false);
|
// const [editing, setEditing] = useState(false);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
@ -96,6 +98,12 @@ export default function SidebarFolder({
|
|||||||
isDraggedOver ? "bg-secondary/50 rounded-t-sm" : "rounded-sm"
|
isDraggedOver ? "bg-secondary/50 rounded-t-sm" : "rounded-sm"
|
||||||
} w-full flex items-center h-7 px-1 transition-colors hover:bg-secondary cursor-pointer`}
|
} w-full flex items-center h-7 px-1 transition-colors hover:bg-secondary cursor-pointer`}
|
||||||
>
|
>
|
||||||
|
<ChevronRight
|
||||||
|
className={cn(
|
||||||
|
"min-w-3 min-h-3 mr-1 ml-auto transition-all duration-300",
|
||||||
|
isOpen ? "transform rotate-90" : ""
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Image
|
<Image
|
||||||
src={`/icons/${folder}`}
|
src={`/icons/${folder}`}
|
||||||
alt="Folder icon"
|
alt="Folder icon"
|
||||||
@ -149,48 +157,65 @@ export default function SidebarFolder({
|
|||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
disabled={isDeleting}
|
disabled={isDeleting}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDeleteFolder(data);
|
handleDeleteFolder(data)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash2 className="w-4 h-4 mr-2" />
|
<Trash2 className="w-4 h-4 mr-2" />
|
||||||
Delete
|
Delete
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
{isOpen ? (
|
<AnimatePresence>
|
||||||
<div
|
{isOpen ? (
|
||||||
className={`flex w-full items-stretch ${
|
<motion.div
|
||||||
isDraggedOver ? "rounded-b-sm bg-secondary/50" : ""
|
className="overflow-y-hidden"
|
||||||
}`}
|
initial={{
|
||||||
>
|
height: 0,
|
||||||
<div className="w-[1px] bg-border mx-2 h-full"></div>
|
opacity: 0,
|
||||||
<div className="flex flex-col grow">
|
}}
|
||||||
{data.children.map((child) =>
|
animate={{
|
||||||
child.type === "file" ? (
|
height: "auto",
|
||||||
<SidebarFile
|
opacity: 1,
|
||||||
key={child.id}
|
}}
|
||||||
data={child}
|
exit={{
|
||||||
selectFile={selectFile}
|
height: 0,
|
||||||
handleRename={handleRename}
|
opacity: 0,
|
||||||
handleDeleteFile={handleDeleteFile}
|
}}
|
||||||
movingId={movingId}
|
>
|
||||||
deletingFolderId={deletingFolderId}
|
<div
|
||||||
/>
|
className={cn(
|
||||||
) : (
|
isDraggedOver ? "rounded-b-sm bg-secondary/50" : ""
|
||||||
<SidebarFolder
|
)}
|
||||||
key={child.id}
|
>
|
||||||
data={child}
|
<div className="flex flex-col grow ml-2 pl-2 border-l border-border">
|
||||||
selectFile={selectFile}
|
{data.children.map((child) =>
|
||||||
handleRename={handleRename}
|
child.type === "file" ? (
|
||||||
handleDeleteFile={handleDeleteFile}
|
<SidebarFile
|
||||||
handleDeleteFolder={handleDeleteFolder}
|
key={child.id}
|
||||||
movingId={movingId}
|
data={child}
|
||||||
deletingFolderId={deletingFolderId}
|
selectFile={selectFile}
|
||||||
/>
|
handleRename={handleRename}
|
||||||
)
|
handleDeleteFile={handleDeleteFile}
|
||||||
)}
|
movingId={movingId}
|
||||||
</div>
|
deletingFolderId={deletingFolderId}
|
||||||
</div>
|
/>
|
||||||
) : null}
|
) : (
|
||||||
|
<SidebarFolder
|
||||||
|
key={child.id}
|
||||||
|
data={child}
|
||||||
|
selectFile={selectFile}
|
||||||
|
handleRename={handleRename}
|
||||||
|
handleDeleteFile={handleDeleteFile}
|
||||||
|
handleDeleteFolder={handleDeleteFolder}
|
||||||
|
movingId={movingId}
|
||||||
|
deletingFolderId={deletingFolderId}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
) : null}
|
||||||
|
</AnimatePresence>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,8 @@ import {
|
|||||||
FilePlus,
|
FilePlus,
|
||||||
FolderPlus,
|
FolderPlus,
|
||||||
Loader2,
|
Loader2,
|
||||||
MonitorPlay,
|
|
||||||
Search,
|
|
||||||
Sparkles,
|
Sparkles,
|
||||||
|
MessageSquareMore,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import SidebarFile from "./file";
|
import SidebarFile from "./file";
|
||||||
import SidebarFolder from "./folder";
|
import SidebarFolder from "./folder";
|
||||||
@ -14,13 +13,12 @@ import { Sandbox, TFile, TFolder, TTab } from "@/lib/types";
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import New from "./new";
|
import New from "./new";
|
||||||
import { Socket } from "socket.io-client";
|
import { Socket } from "socket.io-client";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
dropTargetForElements,
|
dropTargetForElements,
|
||||||
monitorForElements,
|
monitorForElements,
|
||||||
} from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
} from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
||||||
import Button from "@/components/ui/customButton";
|
|
||||||
|
|
||||||
export default function Sidebar({
|
export default function Sidebar({
|
||||||
sandboxData,
|
sandboxData,
|
||||||
@ -32,8 +30,6 @@ export default function Sidebar({
|
|||||||
socket,
|
socket,
|
||||||
setFiles,
|
setFiles,
|
||||||
addNew,
|
addNew,
|
||||||
ai,
|
|
||||||
setAi,
|
|
||||||
deletingFolderId,
|
deletingFolderId,
|
||||||
}: {
|
}: {
|
||||||
sandboxData: Sandbox;
|
sandboxData: Sandbox;
|
||||||
@ -50,8 +46,6 @@ 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
|
||||||
@ -109,9 +103,9 @@ export default function Sidebar({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-56 select-none flex flex-col text-sm items-start justify-between p-2">
|
<div className="h-full w-56 select-none flex flex-col text-sm">
|
||||||
<div className="w-full flex flex-col items-start">
|
<div className="flex-grow overflow-auto p-2 pb-[84px]">
|
||||||
<div className="flex w-full items-center justify-between h-8 mb-1 ">
|
<div className="flex w-full items-center justify-between h-8 mb-1">
|
||||||
<div className="text-muted-foreground">Explorer</div>
|
<div className="text-muted-foreground">Explorer</div>
|
||||||
<div className="flex space-x-1">
|
<div className="flex space-x-1">
|
||||||
<button
|
<button
|
||||||
@ -185,24 +179,25 @@ export default function Sidebar({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full space-y-4">
|
<div className="fixed bottom-0 w-48 flex flex-col p-2 bg-background">
|
||||||
<div className="flex items-center justify-between w-full">
|
<Button variant="ghost" className="w-full justify-start text-sm text-muted-foreground font-normal h-8 px-2 mb-2" disabled aria-disabled="true" style={{ opacity: 1}}>
|
||||||
<div className="flex items-center">
|
<Sparkles className="h-4 w-4 mr-2 text-indigo-500 opacity-70" />
|
||||||
<Sparkles
|
Copilot
|
||||||
className={`h-4 w-4 mr-2 ${
|
<div className="ml-auto">
|
||||||
ai ? "text-indigo-500" : "text-muted-foreground"
|
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground">
|
||||||
}`}
|
<span className="text-xs">⌘</span>G
|
||||||
/>
|
</kbd>
|
||||||
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>
|
</div>
|
||||||
<Switch checked={ai} onCheckedChange={setAi} />
|
</Button>
|
||||||
</div>
|
<Button variant="ghost" className="w-full justify-start text-sm text-muted-foreground font-normal h-8 px-2 mb-2" disabled aria-disabled="true" style={{ opacity: 1 }}>
|
||||||
{/* <Button className="w-full">
|
<MessageSquareMore className="h-4 w-4 mr-2 text-indigo-500 opacity-70" />
|
||||||
<MonitorPlay className="w-4 h-4 mr-2" /> Run
|
AI Chat
|
||||||
</Button> */}
|
<div className="ml-auto">
|
||||||
|
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground">
|
||||||
|
<span className="text-xs">⌘</span>L
|
||||||
|
</kbd>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,35 +2,45 @@
|
|||||||
|
|
||||||
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 { useState } from "react";
|
import { useTerminal } from "@/context/TerminalContext";
|
||||||
|
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">
|
||||||
@ -39,18 +49,7 @@ export default function Terminals({
|
|||||||
key={term.id}
|
key={term.id}
|
||||||
creating={creatingTerminal}
|
creating={creatingTerminal}
|
||||||
onClick={() => setActiveTerminalId(term.id)}
|
onClick={() => setActiveTerminalId(term.id)}
|
||||||
onClose={() =>
|
onClose={() => closeTerminal(term.id)}
|
||||||
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" />
|
||||||
@ -59,18 +58,7 @@ export default function Terminals({
|
|||||||
))}
|
))}
|
||||||
<Button
|
<Button
|
||||||
disabled={creatingTerminal}
|
disabled={creatingTerminal}
|
||||||
onClick={() => {
|
onClick={handleCreateTerminal}
|
||||||
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`}
|
||||||
|
@ -55,7 +55,6 @@ 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);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -74,6 +73,20 @@ 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
|
||||||
|
32
frontend/components/ui/LoadingDots.tsx
Normal file
32
frontend/components/ui/LoadingDots.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const LoadingDots: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<span className="loading-dots">
|
||||||
|
<span className="dot">.</span>
|
||||||
|
<span className="dot">.</span>
|
||||||
|
<span className="dot">.</span>
|
||||||
|
<style jsx>{`
|
||||||
|
.loading-dots {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.dot {
|
||||||
|
opacity: 0;
|
||||||
|
animation: showHideDot 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.dot:nth-child(1) { animation-delay: 0s; }
|
||||||
|
.dot:nth-child(2) { animation-delay: 0.5s; }
|
||||||
|
.dot:nth-child(3) { animation-delay: 1s; }
|
||||||
|
@keyframes showHideDot {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
50% { opacity: 1; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingDots;
|
||||||
|
|
@ -22,6 +22,7 @@ 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",
|
||||||
|
33
frontend/components/ui/popover.tsx
Normal file
33
frontend/components/ui/popover.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"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 }
|
@ -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}/10
|
AI Usage: {userData.generations}/1000
|
||||||
</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) / 10}%`,
|
width: `${(userData.generations * 100) / 1000}%`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
34
frontend/context/PreviewContext.tsx
Normal file
34
frontend/context/PreviewContext.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
"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;
|
||||||
|
};
|
63
frontend/context/SocketContext.tsx
Normal file
63
frontend/context/SocketContext.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"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;
|
||||||
|
};
|
95
frontend/context/TerminalContext.tsx
Normal file
95
frontend/context/TerminalContext.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"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;
|
||||||
|
};
|
36
frontend/lib/data/index.ts
Normal file
36
frontend/lib/data/index.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export const projectTemplates: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
description: string
|
||||||
|
disabled: boolean
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
id: "reactjs",
|
||||||
|
name: "React",
|
||||||
|
icon: "/project-icons/react.svg",
|
||||||
|
description: "A JavaScript library for building user interfaces",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "vanillajs",
|
||||||
|
name: "HTML/JS",
|
||||||
|
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",
|
||||||
|
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "streamlit",
|
||||||
|
name: "Streamlit",
|
||||||
|
icon: "/project-icons/python.svg",
|
||||||
|
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
]
|
295
frontend/lib/file-extension-to-language.json
Normal file
295
frontend/lib/file-extension-to-language.json
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
{
|
||||||
|
"_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"
|
||||||
|
}
|
@ -8,6 +8,7 @@ export const createTerminal = ({
|
|||||||
setTerminals,
|
setTerminals,
|
||||||
setActiveTerminalId,
|
setActiveTerminalId,
|
||||||
setCreatingTerminal,
|
setCreatingTerminal,
|
||||||
|
command,
|
||||||
socket,
|
socket,
|
||||||
}: {
|
}: {
|
||||||
setTerminals: React.Dispatch<React.SetStateAction<{
|
setTerminals: React.Dispatch<React.SetStateAction<{
|
||||||
@ -16,6 +17,7 @@ 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;
|
||||||
|
|
||||||
}) => {
|
}) => {
|
||||||
@ -29,6 +31,7 @@ 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);
|
||||||
};
|
};
|
||||||
|
99
frontend/lib/tsconfig.ts
Normal file
99
frontend/lib/tsconfig.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import * as monaco from "monaco-editor"
|
||||||
|
|
||||||
|
export function parseTSConfigToMonacoOptions(
|
||||||
|
tsconfig: any
|
||||||
|
): monaco.languages.typescript.CompilerOptions {
|
||||||
|
const compilerOptions: monaco.languages.typescript.CompilerOptions = {}
|
||||||
|
|
||||||
|
// Map tsconfig options to Monaco CompilerOptions
|
||||||
|
if (tsconfig.strict) compilerOptions.strict = tsconfig.strict
|
||||||
|
if (tsconfig.target) compilerOptions.target = mapScriptTarget(tsconfig.target)
|
||||||
|
if (tsconfig.module) compilerOptions.module = mapModule(tsconfig.module)
|
||||||
|
if (tsconfig.lib) compilerOptions.lib = tsconfig.lib
|
||||||
|
if (tsconfig.allowJs) compilerOptions.allowJs = tsconfig.allowJs
|
||||||
|
if (tsconfig.checkJs) compilerOptions.checkJs = tsconfig.checkJs
|
||||||
|
if (tsconfig.jsx) compilerOptions.jsx = mapJSX(tsconfig.jsx)
|
||||||
|
if (tsconfig.declaration) compilerOptions.declaration = tsconfig.declaration
|
||||||
|
if (tsconfig.declarationMap)
|
||||||
|
compilerOptions.declarationMap = tsconfig.declarationMap
|
||||||
|
if (tsconfig.sourceMap) compilerOptions.sourceMap = tsconfig.sourceMap
|
||||||
|
if (tsconfig.outFile) compilerOptions.outFile = tsconfig.outFile
|
||||||
|
if (tsconfig.outDir) compilerOptions.outDir = tsconfig.outDir
|
||||||
|
if (tsconfig.removeComments)
|
||||||
|
compilerOptions.removeComments = tsconfig.removeComments
|
||||||
|
if (tsconfig.noEmit) compilerOptions.noEmit = tsconfig.noEmit
|
||||||
|
if (tsconfig.noEmitOnError)
|
||||||
|
compilerOptions.noEmitOnError = tsconfig.noEmitOnError
|
||||||
|
|
||||||
|
return compilerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapScriptTarget(
|
||||||
|
target: string
|
||||||
|
): monaco.languages.typescript.ScriptTarget {
|
||||||
|
const targetMap: { [key: string]: monaco.languages.typescript.ScriptTarget } =
|
||||||
|
{
|
||||||
|
es3: monaco.languages.typescript.ScriptTarget.ES3,
|
||||||
|
es5: monaco.languages.typescript.ScriptTarget.ES5,
|
||||||
|
es6: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
es2015: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
es2016: monaco.languages.typescript.ScriptTarget.ES2016,
|
||||||
|
es2017: monaco.languages.typescript.ScriptTarget.ES2017,
|
||||||
|
es2018: monaco.languages.typescript.ScriptTarget.ES2018,
|
||||||
|
es2019: monaco.languages.typescript.ScriptTarget.ES2019,
|
||||||
|
es2020: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||||
|
esnext: monaco.languages.typescript.ScriptTarget.ESNext,
|
||||||
|
}
|
||||||
|
if (typeof target !== "string") {
|
||||||
|
return monaco.languages.typescript.ScriptTarget.Latest
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
targetMap[target?.toLowerCase()] ||
|
||||||
|
monaco.languages.typescript.ScriptTarget.Latest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapModule(module: string): monaco.languages.typescript.ModuleKind {
|
||||||
|
const moduleMap: { [key: string]: monaco.languages.typescript.ModuleKind } = {
|
||||||
|
none: monaco.languages.typescript.ModuleKind.None,
|
||||||
|
commonjs: monaco.languages.typescript.ModuleKind.CommonJS,
|
||||||
|
amd: monaco.languages.typescript.ModuleKind.AMD,
|
||||||
|
umd: monaco.languages.typescript.ModuleKind.UMD,
|
||||||
|
system: monaco.languages.typescript.ModuleKind.System,
|
||||||
|
es6: monaco.languages.typescript.ModuleKind.ES2015,
|
||||||
|
es2015: monaco.languages.typescript.ModuleKind.ES2015,
|
||||||
|
esnext: monaco.languages.typescript.ModuleKind.ESNext,
|
||||||
|
}
|
||||||
|
if (typeof module !== "string") {
|
||||||
|
return monaco.languages.typescript.ModuleKind.ESNext
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
moduleMap[module.toLowerCase()] ||
|
||||||
|
monaco.languages.typescript.ModuleKind.ESNext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapJSX(jsx: string): monaco.languages.typescript.JsxEmit {
|
||||||
|
const jsxMap: { [key: string]: monaco.languages.typescript.JsxEmit } = {
|
||||||
|
preserve: monaco.languages.typescript.JsxEmit.Preserve,
|
||||||
|
react: monaco.languages.typescript.JsxEmit.React,
|
||||||
|
"react-native": monaco.languages.typescript.JsxEmit.ReactNative,
|
||||||
|
}
|
||||||
|
return jsxMap[jsx.toLowerCase()] || monaco.languages.typescript.JsxEmit.React
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage:
|
||||||
|
const tsconfigJSON = {
|
||||||
|
compilerOptions: {
|
||||||
|
strict: true,
|
||||||
|
target: "ES2020",
|
||||||
|
module: "ESNext",
|
||||||
|
lib: ["DOM", "ES2020"],
|
||||||
|
jsx: "react",
|
||||||
|
sourceMap: true,
|
||||||
|
outDir: "./dist",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const monacoOptions = parseTSConfigToMonacoOptions(tsconfigJSON.compilerOptions)
|
||||||
|
console.log(monacoOptions)
|
@ -12,7 +12,7 @@ export type User = {
|
|||||||
export type Sandbox = {
|
export type Sandbox = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: "react" | "node";
|
type: string;
|
||||||
visibility: "public" | "private";
|
visibility: "public" | "private";
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
@ -2,18 +2,19 @@ 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 ending = file.split(".").pop()
|
const extension = 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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,12 +63,38 @@ export function addNew(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function debounce<T extends (...args: any[]) => void>(func: T, wait: number): T {
|
export function debounce<T extends (...args: any[]) => void>(
|
||||||
let timeout: NodeJS.Timeout | null = null;
|
func: T,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deep merge utility function
|
||||||
|
export const deepMerge = (target: any, source: any) => {
|
||||||
|
const output = { ...target }
|
||||||
|
if (isObject(target) && isObject(source)) {
|
||||||
|
Object.keys(source).forEach((key) => {
|
||||||
|
if (isObject(source[key])) {
|
||||||
|
if (!(key in target)) {
|
||||||
|
Object.assign(output, { [key]: source[key] })
|
||||||
|
} else {
|
||||||
|
output[key] = deepMerge(target[key], source[key])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Object.assign(output, { [key]: source[key] })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
const isObject = (item: any) => {
|
||||||
|
return item && typeof item === "object" && !Array.isArray(item)
|
||||||
}
|
}
|
2456
frontend/package-lock.json
generated
2456
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
|||||||
"@atlaskit/pragmatic-drag-and-drop": "^1.1.7",
|
"@atlaskit/pragmatic-drag-and-drop": "^1.1.7",
|
||||||
"@clerk/nextjs": "^4.29.12",
|
"@clerk/nextjs": "^4.29.12",
|
||||||
"@clerk/themes": "^1.7.12",
|
"@clerk/themes": "^1.7.12",
|
||||||
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
"@liveblocks/client": "^1.12.0",
|
"@liveblocks/client": "^1.12.0",
|
||||||
"@liveblocks/node": "^1.12.0",
|
"@liveblocks/node": "^1.12.0",
|
||||||
@ -25,10 +26,13 @@
|
|||||||
"@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",
|
||||||
"@react-three/fiber": "^8.16.6",
|
"@react-three/fiber": "^8.16.6",
|
||||||
|
"@uiw/codemirror-theme-vscode": "^4.23.5",
|
||||||
|
"@uiw/react-codemirror": "^4.23.5",
|
||||||
"@vercel/analytics": "^1.2.2",
|
"@vercel/analytics": "^1.2.2",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
@ -41,10 +45,14 @@
|
|||||||
"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",
|
||||||
|
"react-markdown": "^9.0.1",
|
||||||
"react-resizable-panels": "^2.0.16",
|
"react-resizable-panels": "^2.0.16",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
|
"remark-gfm": "^4.0.0",
|
||||||
"socket.io-client": "^4.7.5",
|
"socket.io-client": "^4.7.5",
|
||||||
"sonner": "^1.4.41",
|
"sonner": "^1.4.41",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
@ -57,9 +65,11 @@
|
|||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/estree": "^1.0.6",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/three": "^0.164.0",
|
"@types/three": "^0.164.0",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
3
frontend/react-syntax-highlighter.d.ts
vendored
Normal file
3
frontend/react-syntax-highlighter.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
declare module 'react-syntax-highlighter';
|
||||||
|
declare module 'react-syntax-highlighter/dist/esm/styles/prism';
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"types": ["node"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
630
package-lock.json
generated
Normal file
630
package-lock.json
generated
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-popover": "^1.1.1"
|
||||||
|
}
|
||||||
|
}
|
47
tests/index.ts
Normal file
47
tests/index.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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
Normal file
310
tests/package-lock.json
generated
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
tests/package.json
Normal file
21
tests/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
13
tests/tsconfig.json
Normal file
13
tests/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"outDir": "./dist"
|
||||||
|
},
|
||||||
|
"include": ["index.ts"]
|
||||||
|
}
|
Reference in New Issue
Block a user