This commit is contained in:
Benjamin Toby 2026-03-14 07:19:46 +01:00
parent 89975d96cb
commit cec584c177
54 changed files with 774 additions and 313 deletions

2
dist/web/BUILD_ID vendored
View File

@ -1 +1 @@
pL7yVdRZyy9CmaZprVEGr Ac6Q3W_cSGiBJUiUxpsfm

View File

@ -5,8 +5,8 @@
"devFiles": [], "devFiles": [],
"ampDevFiles": [], "ampDevFiles": [],
"lowPriorityFiles": [ "lowPriorityFiles": [
"static/pL7yVdRZyy9CmaZprVEGr/_buildManifest.js", "static/Ac6Q3W_cSGiBJUiUxpsfm/_buildManifest.js",
"static/pL7yVdRZyy9CmaZprVEGr/_ssgManifest.js" "static/Ac6Q3W_cSGiBJUiUxpsfm/_ssgManifest.js"
], ],
"rootMainFiles": [], "rootMainFiles": [],
"pages": { "pages": {
@ -15,13 +15,13 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/225-f257bb5bd6014d68.js", "static/chunks/225-f257bb5bd6014d68.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/pages/index-13e31ea96205b999.js" "static/chunks/pages/index-5ce092dbf4b7ea2c.js"
], ],
"/404": [ "/404": [
"static/chunks/webpack-38cee4c0e358b1a3.js", "static/chunks/webpack-38cee4c0e358b1a3.js",
@ -49,13 +49,13 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
"static/chunks/464-c362be69f86d4f17.js", "static/chunks/464-f898cadde407dd9f.js",
"static/chunks/pages/admin-8a0fdb80e9b4248f.js" "static/chunks/pages/admin-8a0fdb80e9b4248f.js"
], ],
"/admin/services": [ "/admin/services": [
@ -63,13 +63,13 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
"static/chunks/464-c362be69f86d4f17.js", "static/chunks/464-f898cadde407dd9f.js",
"static/chunks/pages/admin/services-68efb2b49e62c913.js" "static/chunks/pages/admin/services-68efb2b49e62c913.js"
], ],
"/admin/services/[service_name]": [ "/admin/services/[service_name]": [
@ -77,13 +77,13 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
"static/chunks/464-c362be69f86d4f17.js", "static/chunks/464-f898cadde407dd9f.js",
"static/chunks/pages/admin/services/[service_name]-0049c2898ea64cc0.js" "static/chunks/pages/admin/services/[service_name]-0049c2898ea64cc0.js"
], ],
"/admin/settings": [ "/admin/settings": [
@ -91,9 +91,9 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
@ -104,9 +104,9 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
"static/chunks/pages/admin/users-73e9775838b56d95.js" "static/chunks/pages/admin/users-73e9775838b56d95.js"
@ -116,11 +116,11 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/ff39441c-88f593a46cb65964.js", "static/chunks/ff39441c-88f593a46cb65964.js",
"static/chunks/d848df63-a470d32e7be4bfe3.js", "static/chunks/d848df63-a470d32e7be4bfe3.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/281-dcee0c6401936d5e.js", "static/chunks/281-dcee0c6401936d5e.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
@ -132,9 +132,9 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/910-215ca9612c9e2400.js", "static/chunks/910-215ca9612c9e2400.js",
@ -145,9 +145,9 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/225-f257bb5bd6014d68.js", "static/chunks/225-f257bb5bd6014d68.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
@ -166,9 +166,9 @@
"static/chunks/framework-bfa817c72d812316.js", "static/chunks/framework-bfa817c72d812316.js",
"static/chunks/main-761b7faf59ba862f.js", "static/chunks/main-761b7faf59ba862f.js",
"static/chunks/29107295-2819ba6e51dbf961.js", "static/chunks/29107295-2819ba6e51dbf961.js",
"static/chunks/e5d67320-bf1772fa71739690.js", "static/chunks/e5d67320-ccbab4288ca637ad.js",
"static/chunks/664-e347d64e56042a02.js", "static/chunks/664-e347d64e56042a02.js",
"static/chunks/433-bb8bdacebff9ab53.js", "static/chunks/433-ace0b205fb566ad3.js",
"static/chunks/7-f0121001f735b8fe.js", "static/chunks/7-f0121001f735b8fe.js",
"static/chunks/827-7975edcf8481ec69.js", "static/chunks/827-7975edcf8481ec69.js",
"static/chunks/pages/auth/signup-5c0f6835749e755e.js" "static/chunks/pages/auth/signup-5c0f6835749e755e.js"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"version":4,"routes":{},"dynamicRoutes":{},"preview":{"previewModeId":"e7f3966557a40f1fadee9cd4009715fa","previewModeSigningKey":"582355509a4ba9b2a8bd6be6e8ff008dff1cde8c0c7a0a5fceeceb767af22290","previewModeEncryptionKey":"1b8b16d26cae6f9e2149fff6cb368e117d96a965325b699566871db70e9aa512"},"notFoundRoutes":[]} {"version":4,"routes":{},"dynamicRoutes":{},"preview":{"previewModeId":"41e1091eb1109508c747b622a00635b1","previewModeSigningKey":"f6adb768298c87f60e74ea2b05e5275c23880f86ace11d9370b0851a04a2b51b","previewModeEncryptionKey":"4eff9a582f5e38502da59c29d949bca03ecac20f6a34ba771d525f72da7816a0"},"notFoundRoutes":[]}

View File

@ -1 +1 @@
{"version":3,"pages404":true,"caseSensitive":false,"basePath":"","redirects":[{"source":"/:path+/","destination":"/:path+","internal":true,"statusCode":308,"regex":"^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))/$"}],"headers":[],"dynamicRoutes":[{"page":"/admin/services/[service_name]","regex":"^/admin/services/([^/]+?)(?:/)?$","routeKeys":{"nxtPservice_name":"nxtPservice_name"},"namedRegex":"^/admin/services/(?<nxtPservice_name>[^/]+?)(?:/)?$"},{"page":"/admin/users/[deployment_user_id]","regex":"^/admin/users/([^/]+?)(?:/)?$","routeKeys":{"nxtPdeployment_user_id":"nxtPdeployment_user_id"},"namedRegex":"^/admin/users/(?<nxtPdeployment_user_id>[^/]+?)(?:/)?$"}],"staticRoutes":[{"page":"/","regex":"^/(?:/)?$","routeKeys":{},"namedRegex":"^/(?:/)?$"},{"page":"/404","regex":"^/404(?:/)?$","routeKeys":{},"namedRegex":"^/404(?:/)?$"},{"page":"/admin","regex":"^/admin(?:/)?$","routeKeys":{},"namedRegex":"^/admin(?:/)?$"},{"page":"/admin/services","regex":"^/admin/services(?:/)?$","routeKeys":{},"namedRegex":"^/admin/services(?:/)?$"},{"page":"/admin/settings","regex":"^/admin/settings(?:/)?$","routeKeys":{},"namedRegex":"^/admin/settings(?:/)?$"},{"page":"/admin/users","regex":"^/admin/users(?:/)?$","routeKeys":{},"namedRegex":"^/admin/users(?:/)?$"},{"page":"/admin/users/add-user","regex":"^/admin/users/add\\-user(?:/)?$","routeKeys":{},"namedRegex":"^/admin/users/add\\-user(?:/)?$"},{"page":"/auth/login","regex":"^/auth/login(?:/)?$","routeKeys":{},"namedRegex":"^/auth/login(?:/)?$"},{"page":"/auth/logout","regex":"^/auth/logout(?:/)?$","routeKeys":{},"namedRegex":"^/auth/logout(?:/)?$"},{"page":"/auth/signup","regex":"^/auth/signup(?:/)?$","routeKeys":{},"namedRegex":"^/auth/signup(?:/)?$"}],"dataRoutes":[{"page":"/","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/index.json$"},{"page":"/admin","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin.json$"},{"page":"/admin/services","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/services.json$"},{"page":"/admin/services/[service_name]","routeKeys":{"nxtPservice_name":"nxtPservice_name"},"dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/services/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/services/(?<nxtPservice_name>[^/]+?)\\.json$"},{"page":"/admin/settings","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/settings.json$"},{"page":"/admin/users","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/users.json$"},{"page":"/admin/users/add-user","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/users/add-user.json$"},{"page":"/admin/users/[deployment_user_id]","routeKeys":{"nxtPdeployment_user_id":"nxtPdeployment_user_id"},"dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/users/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/admin/users/(?<nxtPdeployment_user_id>[^/]+?)\\.json$"},{"page":"/auth/login","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/auth/login.json$"},{"page":"/auth/logout","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/auth/logout.json$"},{"page":"/auth/signup","dataRouteRegex":"^/_next/data/pL7yVdRZyy9CmaZprVEGr/auth/signup.json$"}],"rsc":{"header":"RSC","varyHeader":"RSC, Next-Router-State-Tree, Next-Router-Prefetch","prefetchHeader":"Next-Router-Prefetch","didPostponeHeader":"x-nextjs-postponed","contentTypeHeader":"text/x-component","suffix":".rsc","prefetchSuffix":".prefetch.rsc"},"rewrites":[]} {"version":3,"pages404":true,"caseSensitive":false,"basePath":"","redirects":[{"source":"/:path+/","destination":"/:path+","internal":true,"statusCode":308,"regex":"^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))/$"}],"headers":[],"dynamicRoutes":[{"page":"/admin/services/[service_name]","regex":"^/admin/services/([^/]+?)(?:/)?$","routeKeys":{"nxtPservice_name":"nxtPservice_name"},"namedRegex":"^/admin/services/(?<nxtPservice_name>[^/]+?)(?:/)?$"},{"page":"/admin/users/[deployment_user_id]","regex":"^/admin/users/([^/]+?)(?:/)?$","routeKeys":{"nxtPdeployment_user_id":"nxtPdeployment_user_id"},"namedRegex":"^/admin/users/(?<nxtPdeployment_user_id>[^/]+?)(?:/)?$"}],"staticRoutes":[{"page":"/","regex":"^/(?:/)?$","routeKeys":{},"namedRegex":"^/(?:/)?$"},{"page":"/404","regex":"^/404(?:/)?$","routeKeys":{},"namedRegex":"^/404(?:/)?$"},{"page":"/admin","regex":"^/admin(?:/)?$","routeKeys":{},"namedRegex":"^/admin(?:/)?$"},{"page":"/admin/services","regex":"^/admin/services(?:/)?$","routeKeys":{},"namedRegex":"^/admin/services(?:/)?$"},{"page":"/admin/settings","regex":"^/admin/settings(?:/)?$","routeKeys":{},"namedRegex":"^/admin/settings(?:/)?$"},{"page":"/admin/users","regex":"^/admin/users(?:/)?$","routeKeys":{},"namedRegex":"^/admin/users(?:/)?$"},{"page":"/admin/users/add-user","regex":"^/admin/users/add\\-user(?:/)?$","routeKeys":{},"namedRegex":"^/admin/users/add\\-user(?:/)?$"},{"page":"/auth/login","regex":"^/auth/login(?:/)?$","routeKeys":{},"namedRegex":"^/auth/login(?:/)?$"},{"page":"/auth/logout","regex":"^/auth/logout(?:/)?$","routeKeys":{},"namedRegex":"^/auth/logout(?:/)?$"},{"page":"/auth/signup","regex":"^/auth/signup(?:/)?$","routeKeys":{},"namedRegex":"^/auth/signup(?:/)?$"}],"dataRoutes":[{"page":"/","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/index.json$"},{"page":"/admin","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin.json$"},{"page":"/admin/services","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/services.json$"},{"page":"/admin/services/[service_name]","routeKeys":{"nxtPservice_name":"nxtPservice_name"},"dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/services/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/services/(?<nxtPservice_name>[^/]+?)\\.json$"},{"page":"/admin/settings","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/settings.json$"},{"page":"/admin/users","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/users.json$"},{"page":"/admin/users/add-user","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/users/add-user.json$"},{"page":"/admin/users/[deployment_user_id]","routeKeys":{"nxtPdeployment_user_id":"nxtPdeployment_user_id"},"dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/users/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/admin/users/(?<nxtPdeployment_user_id>[^/]+?)\\.json$"},{"page":"/auth/login","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/auth/login.json$"},{"page":"/auth/logout","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/auth/logout.json$"},{"page":"/auth/signup","dataRouteRegex":"^/_next/data/Ac6Q3W_cSGiBJUiUxpsfm/auth/signup.json$"}],"rsc":{"header":"RSC","varyHeader":"RSC, Next-Router-State-Tree, Next-Router-Prefetch","prefetchHeader":"Next-Router-Prefetch","didPostponeHeader":"x-nextjs-postponed","contentTypeHeader":"text/x-component","suffix":".rsc","prefetchSuffix":".prefetch.rsc"},"rewrites":[]}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"version":1,"functions":{"/_app":{},"/admin/settings":{},"/admin/services/[service_name]":{},"/admin":{},"/admin/services":{},"/admin/users/add-user":{},"/admin/users/[deployment_user_id]":{},"/auth/logout":{},"/auth/signup":{},"/":{},"/admin/users":{},"/auth/login":{}}} {"version":1,"functions":{"/_app":{},"/admin/settings":{},"/admin/users/[deployment_user_id]":{},"/admin":{},"/admin/users/add-user":{},"/admin/services/[service_name]":{},"/admin/services":{},"/auth/login":{},"/admin/users":{},"/auth/logout":{},"/":{},"/auth/signup":{}}}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"/_document":"pages/_document.js","/404":"pages/404.html","/api/admin/delete-user":"pages/api/admin/delete-user.js","/api/admin/download-private-ssh-key":"pages/api/admin/download-private-ssh-key.js","/api/admin/edit-user":"pages/api/admin/edit-user.js","/api/admin/settings":"pages/api/admin/settings.js","/api/auth/login":"pages/api/auth/login.js","/api/auth/signup":"pages/api/auth/signup.js","/api/hello":"pages/api/hello.js","/admin/services/[service_name]":"pages/admin/services/[service_name].js","/_app":"pages/_app.js","/_error":"pages/_error.js","/admin/services":"pages/admin/services.js","/admin":"pages/admin.js","/admin/users/add-user":"pages/admin/users/add-user.js","/admin/users/[deployment_user_id]":"pages/admin/users/[deployment_user_id].js","/admin/settings":"pages/admin/settings.js","/admin/users":"pages/admin/users.js","/":"pages/index.js","/auth/logout":"pages/auth/logout.js","/auth/signup":"pages/auth/signup.js","/auth/login":"pages/auth/login.js"} {"/_document":"pages/_document.js","/404":"pages/404.html","/api/admin/download-private-ssh-key":"pages/api/admin/download-private-ssh-key.js","/api/admin/delete-user":"pages/api/admin/delete-user.js","/api/admin/edit-user":"pages/api/admin/edit-user.js","/api/admin/settings":"pages/api/admin/settings.js","/api/auth/login":"pages/api/auth/login.js","/api/hello":"pages/api/hello.js","/api/auth/signup":"pages/api/auth/signup.js","/admin":"pages/admin.js","/_app":"pages/_app.js","/admin/services":"pages/admin/services.js","/admin/services/[service_name]":"pages/admin/services/[service_name].js","/_error":"pages/_error.js","/admin/users/add-user":"pages/admin/users/add-user.js","/admin/users":"pages/admin/users.js","/admin/settings":"pages/admin/settings.js","/admin/users/[deployment_user_id]":"pages/admin/users/[deployment_user_id].js","/":"pages/index.js","/auth/logout":"pages/auth/logout.js","/auth/signup":"pages/auth/signup.js","/auth/login":"pages/auth/login.js"}

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/08e6997802749ec3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/08e6997802749ec3.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-38cee4c0e358b1a3.js" defer=""></script><script src="/_next/static/chunks/framework-bfa817c72d812316.js" defer=""></script><script src="/_next/static/chunks/main-761b7faf59ba862f.js" defer=""></script><script src="/_next/static/chunks/pages/_app-12c3cc69366c709d.js" defer=""></script><script src="/_next/static/chunks/29107295-2819ba6e51dbf961.js" defer=""></script><script src="/_next/static/chunks/664-e347d64e56042a02.js" defer=""></script><script src="/_next/static/chunks/pages/404-8292e1046538596b.js" defer=""></script><script src="/_next/static/pL7yVdRZyy9CmaZprVEGr/_buildManifest.js" defer=""></script><script src="/_next/static/pL7yVdRZyy9CmaZprVEGr/_ssgManifest.js" defer=""></script></head><body class="antialiased"><div id="__next"><main class="flex flex-col items-center twui-main w-screen h-screen overflow-hidden"><section class="flex flex-col items-center px-4 sm:px-10 py-10 twui-section w-full h-full"><div class="flex w-full max-w-container gap-4 justify-between flex-wrap flex-col xl:flex-row items-start xl:items-center twui-container grid-frame grid-cols-1 h-full"><div class="flex flex-col items-start gap-4 twui-stack w-full justify-between h-full grid-cell"><div class="flex flex-col items-start twui-stack gap-0"><div class="flex flex-row gap-2 flex-wrap items-center twui-row"><div class="flex flex-row gap-2 flex-wrap items-center twui-row p-6"><a aria-label="TurboCI home" class="inline-flex items-center gap-3" href="/"><svg viewBox="0 0 48 48" aria-hidden="true" class="h-10 w-10 shrink-0"><defs><linearGradient id="_R_1am_" x1="9" y1="9" x2="31" y2="34" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="#9cf0c0"></stop><stop offset="100%" stop-color="#42d392"></stop></linearGradient><linearGradient id="_R_1amH1_" x1="22" y1="22" x2="36" y2="40" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="#2bc67e"></stop><stop offset="100%" stop-color="#1f8458"></stop></linearGradient></defs><path d="M35 6H23.6c-2 0-3.8 1-4.8 2.7L7.5 28.3c-1.4 2.5.4 5.7 3.2 5.7h9.1c2 0 3.8-1 4.8-2.7l11.2-19.6C39.6 9.2 37.8 6 35 6Z" fill="url(#_R_1am_)"></path><path d="M23.9 24h13.4c2.8 0 4.6 3.1 3.2 5.6l-4.1 7.1c-1 1.7-2.8 2.7-4.8 2.7H18.2c-2.8 0-4.6-3.1-3.2-5.6l4.1-7.1c1-1.7 2.8-2.7 4.8-2.7Z" fill="url(#_R_1amH1_)"></path></svg><span class="font-display text-[1.02rem] font-semibold tracking-tight text-foreground">TurboCI</span></a></div><div class="border-slate-200 dark:border-white/10 border-0 border-l h-full min-h-5 twui-divider twui-divider-vertical border-solid"></div></div><div class="border-slate-200 dark:border-white/10 border-0 border-t w-full twui-divider twui-divider-horizontal border-solid"></div></div><div class="flex flex-col items-center justify-center gap-4 w-full h-full twui-center p-10"><h2 class="text-2xl md:text-3xl mb-4 twui-headings twui-heading twui-h2">Page Not Found!</h2></div><div class="flex flex-col items-start gap-4 twui-stack"><div class="border-slate-200 dark:border-white/10 border-0 border-t w-full twui-divider twui-divider-horizontal border-solid"></div><div class="twui-spacer h-20 w-full"></div></div></div></div></section></main></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"pL7yVdRZyy9CmaZprVEGr","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html> <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/08e6997802749ec3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/08e6997802749ec3.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-38cee4c0e358b1a3.js" defer=""></script><script src="/_next/static/chunks/framework-bfa817c72d812316.js" defer=""></script><script src="/_next/static/chunks/main-761b7faf59ba862f.js" defer=""></script><script src="/_next/static/chunks/pages/_app-12c3cc69366c709d.js" defer=""></script><script src="/_next/static/chunks/29107295-2819ba6e51dbf961.js" defer=""></script><script src="/_next/static/chunks/664-e347d64e56042a02.js" defer=""></script><script src="/_next/static/chunks/pages/404-8292e1046538596b.js" defer=""></script><script src="/_next/static/Ac6Q3W_cSGiBJUiUxpsfm/_buildManifest.js" defer=""></script><script src="/_next/static/Ac6Q3W_cSGiBJUiUxpsfm/_ssgManifest.js" defer=""></script></head><body class="antialiased"><div id="__next"><main class="flex flex-col items-center twui-main w-screen h-screen overflow-hidden"><section class="flex flex-col items-center px-4 sm:px-10 py-10 twui-section w-full h-full"><div class="flex w-full max-w-container gap-4 justify-between flex-wrap flex-col xl:flex-row items-start xl:items-center twui-container grid-frame grid-cols-1 h-full"><div class="flex flex-col items-start gap-4 twui-stack w-full justify-between h-full grid-cell"><div class="flex flex-col items-start twui-stack gap-0"><div class="flex flex-row gap-2 flex-wrap items-center twui-row"><div class="flex flex-row gap-2 flex-wrap items-center twui-row p-6"><a aria-label="TurboCI home" class="inline-flex items-center gap-3" href="/"><svg viewBox="0 0 48 48" aria-hidden="true" class="h-10 w-10 shrink-0"><defs><linearGradient id="_R_1am_" x1="9" y1="9" x2="31" y2="34" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="#9cf0c0"></stop><stop offset="100%" stop-color="#42d392"></stop></linearGradient><linearGradient id="_R_1amH1_" x1="22" y1="22" x2="36" y2="40" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="#2bc67e"></stop><stop offset="100%" stop-color="#1f8458"></stop></linearGradient></defs><path d="M35 6H23.6c-2 0-3.8 1-4.8 2.7L7.5 28.3c-1.4 2.5.4 5.7 3.2 5.7h9.1c2 0 3.8-1 4.8-2.7l11.2-19.6C39.6 9.2 37.8 6 35 6Z" fill="url(#_R_1am_)"></path><path d="M23.9 24h13.4c2.8 0 4.6 3.1 3.2 5.6l-4.1 7.1c-1 1.7-2.8 2.7-4.8 2.7H18.2c-2.8 0-4.6-3.1-3.2-5.6l4.1-7.1c1-1.7 2.8-2.7 4.8-2.7Z" fill="url(#_R_1amH1_)"></path></svg><span class="font-display text-[1.02rem] font-semibold tracking-tight text-foreground">TurboCI</span></a></div><div class="border-slate-200 dark:border-white/10 border-0 border-l h-full min-h-5 twui-divider twui-divider-vertical border-solid"></div></div><div class="border-slate-200 dark:border-white/10 border-0 border-t w-full twui-divider twui-divider-horizontal border-solid"></div></div><div class="flex flex-col items-center justify-center gap-4 w-full h-full twui-center p-10"><h2 class="text-2xl md:text-3xl mb-4 twui-headings twui-heading twui-h2">Page Not Found!</h2></div><div class="flex flex-col items-start gap-4 twui-stack"><div class="border-slate-200 dark:border-white/10 border-0 border-t w-full twui-divider twui-divider-horizontal border-solid"></div><div class="twui-spacer h-20 w-full"></div></div></div></div></section></main></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"Ac6Q3W_cSGiBJUiUxpsfm","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>500: Internal Server Error</title><meta name="next-head-count" content="3"/><link rel="preload" href="/_next/static/css/08e6997802749ec3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/08e6997802749ec3.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-38cee4c0e358b1a3.js" defer=""></script><script src="/_next/static/chunks/framework-bfa817c72d812316.js" defer=""></script><script src="/_next/static/chunks/main-761b7faf59ba862f.js" defer=""></script><script src="/_next/static/chunks/pages/_app-12c3cc69366c709d.js" defer=""></script><script src="/_next/static/chunks/pages/_error-10090a8ee211d5fd.js" defer=""></script><script src="/_next/static/pL7yVdRZyy9CmaZprVEGr/_buildManifest.js" defer=""></script><script src="/_next/static/pL7yVdRZyy9CmaZprVEGr/_ssgManifest.js" defer=""></script></head><body class="antialiased"><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{},"buildId":"pL7yVdRZyy9CmaZprVEGr","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html> <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>500: Internal Server Error</title><meta name="next-head-count" content="3"/><link rel="preload" href="/_next/static/css/08e6997802749ec3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/08e6997802749ec3.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-38cee4c0e358b1a3.js" defer=""></script><script src="/_next/static/chunks/framework-bfa817c72d812316.js" defer=""></script><script src="/_next/static/chunks/main-761b7faf59ba862f.js" defer=""></script><script src="/_next/static/chunks/pages/_app-12c3cc69366c709d.js" defer=""></script><script src="/_next/static/chunks/pages/_error-10090a8ee211d5fd.js" defer=""></script><script src="/_next/static/Ac6Q3W_cSGiBJUiUxpsfm/_buildManifest.js" defer=""></script><script src="/_next/static/Ac6Q3W_cSGiBJUiUxpsfm/_ssgManifest.js" defer=""></script></head><body class="antialiased"><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{},"buildId":"Ac6Q3W_cSGiBJUiUxpsfm","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

View File

@ -1 +1 @@
self.__BUILD_MANIFEST=function(s,a,e,c,t,i,n,d,u){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,e,a,c,u,t,i,"static/chunks/pages/index-13e31ea96205b999.js"],"/404":[s,a,"static/chunks/pages/404-8292e1046538596b.js"],"/_error":["static/chunks/pages/_error-10090a8ee211d5fd.js"],"/admin":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin-8a0fdb80e9b4248f.js"],"/admin/services":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin/services-68efb2b49e62c913.js"],"/admin/services/[service_name]":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin/services/[service_name]-0049c2898ea64cc0.js"],"/admin/settings":[s,e,a,c,t,i,n,"static/chunks/pages/admin/settings-f58d63b2752f72a6.js"],"/admin/users":[s,e,a,c,t,n,"static/chunks/pages/admin/users-73e9775838b56d95.js"],"/admin/users/add-user":[s,e,a,c,t,i,n,"static/chunks/pages/admin/users/add-user-1db7c9ee89830b5b.js"],"/admin/users/[deployment_user_id]":[s,e,"static/chunks/ff39441c-88f593a46cb65964.js","static/chunks/d848df63-a470d32e7be4bfe3.js",a,c,"static/chunks/281-dcee0c6401936d5e.js",t,i,n,"static/chunks/pages/admin/users/[deployment_user_id]-fb1c3c9148c518cd.js"],"/auth/login":[s,e,a,c,u,t,i,"static/chunks/pages/auth/login-3f936f997e58438c.js"],"/auth/logout":[s,a,"static/chunks/pages/auth/logout-c8b207f96be4f684.js"],"/auth/signup":[s,e,a,c,t,i,"static/chunks/pages/auth/signup-5c0f6835749e755e.js"],sortedPages:["/","/404","/_app","/_error","/admin","/admin/services","/admin/services/[service_name]","/admin/settings","/admin/users","/admin/users/add-user","/admin/users/[deployment_user_id]","/auth/login","/auth/logout","/auth/signup"]}}("static/chunks/29107295-2819ba6e51dbf961.js","static/chunks/664-e347d64e56042a02.js","static/chunks/e5d67320-bf1772fa71739690.js","static/chunks/433-bb8bdacebff9ab53.js","static/chunks/7-f0121001f735b8fe.js","static/chunks/827-7975edcf8481ec69.js","static/chunks/910-215ca9612c9e2400.js","static/chunks/464-c362be69f86d4f17.js","static/chunks/225-f257bb5bd6014d68.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); self.__BUILD_MANIFEST=function(s,a,e,c,t,i,n,d,u){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,e,a,c,u,t,i,"static/chunks/pages/index-5ce092dbf4b7ea2c.js"],"/404":[s,a,"static/chunks/pages/404-8292e1046538596b.js"],"/_error":["static/chunks/pages/_error-10090a8ee211d5fd.js"],"/admin":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin-8a0fdb80e9b4248f.js"],"/admin/services":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin/services-68efb2b49e62c913.js"],"/admin/services/[service_name]":[s,e,a,c,t,i,n,d,"static/chunks/pages/admin/services/[service_name]-0049c2898ea64cc0.js"],"/admin/settings":[s,e,a,c,t,i,n,"static/chunks/pages/admin/settings-f58d63b2752f72a6.js"],"/admin/users":[s,e,a,c,t,n,"static/chunks/pages/admin/users-73e9775838b56d95.js"],"/admin/users/add-user":[s,e,a,c,t,i,n,"static/chunks/pages/admin/users/add-user-1db7c9ee89830b5b.js"],"/admin/users/[deployment_user_id]":[s,e,"static/chunks/ff39441c-88f593a46cb65964.js","static/chunks/d848df63-a470d32e7be4bfe3.js",a,c,"static/chunks/281-dcee0c6401936d5e.js",t,i,n,"static/chunks/pages/admin/users/[deployment_user_id]-fb1c3c9148c518cd.js"],"/auth/login":[s,e,a,c,u,t,i,"static/chunks/pages/auth/login-3f936f997e58438c.js"],"/auth/logout":[s,a,"static/chunks/pages/auth/logout-c8b207f96be4f684.js"],"/auth/signup":[s,e,a,c,t,i,"static/chunks/pages/auth/signup-5c0f6835749e755e.js"],sortedPages:["/","/404","/_app","/_error","/admin","/admin/services","/admin/services/[service_name]","/admin/settings","/admin/users","/admin/users/add-user","/admin/users/[deployment_user_id]","/auth/login","/auth/logout","/auth/signup"]}}("static/chunks/29107295-2819ba6e51dbf961.js","static/chunks/664-e347d64e56042a02.js","static/chunks/e5d67320-ccbab4288ca637ad.js","static/chunks/433-ace0b205fb566ad3.js","static/chunks/7-f0121001f735b8fe.js","static/chunks/827-7975edcf8481ec69.js","static/chunks/910-215ca9612c9e2400.js","static/chunks/464-f898cadde407dd9f.js","static/chunks/225-f257bb5bd6014d68.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7
dist/web/trace vendored

File diff suppressed because one or more lines are too long

View File

@ -2,18 +2,15 @@ import { AppContext } from "@/src/pages/_app";
import { import {
NormalizedServerObject, NormalizedServerObject,
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
} from "@/src/types"; } from "@/src/types/turboci";
import ArrowedLink from "@/twui/components/layout/ArrowedLink"; import ArrowedLink from "@/twui/components/layout/ArrowedLink";
import Button from "@/twui/components/layout/Button";
import H2 from "@/twui/components/layout/H2"; import H2 from "@/twui/components/layout/H2";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import Stack from "@/twui/components/layout/Stack"; import Stack from "@/twui/components/layout/Stack";
import { useContext, useEffect, useRef, useState } from "react"; import { useContext, useEffect, useRef, useState } from "react";
import ServiceClusterServer from "../service/(partials)/cluster-server"; import ServiceClusterServer from "../service/(partials)/cluster-server";
import { twMerge } from "tailwind-merge";
import Select from "@/twui/components/form/Select"; import Select from "@/twui/components/form/Select";
import useStatus from "@/twui/components/hooks/useStatus"; import useStatus from "@/twui/components/hooks/useStatus";
import Loading from "@/twui/components/elements/Loading";
import _ from "lodash"; import _ from "lodash";
type Props = { type Props = {

View File

@ -1,5 +1,5 @@
import { Dispatch, Fragment, SetStateAction, useContext, useRef } from "react"; import { Dispatch, Fragment, SetStateAction, useContext, useRef } from "react";
import { ParsedDeploymentServiceConfig } from "@/src/types"; import { ParsedDeploymentServiceConfig } from "@/src/types/turboci";
import Select, { TWUISelectOptionObject } from "@/twui/components/form/Select"; import Select, { TWUISelectOptionObject } from "@/twui/components/form/Select";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import Button from "@/twui/components/layout/Button"; import Button from "@/twui/components/layout/Button";

View File

@ -3,7 +3,7 @@ import { Dispatch, SetStateAction } from "react";
import { import {
NormalizedServerObject, NormalizedServerObject,
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
} from "@/src/types"; } from "@/src/types/turboci";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import ServiceClusterServerLogSelectorSetCustomLog from "./cluster-server-log-selector-set-custom-log"; import ServiceClusterServerLogSelectorSetCustomLog from "./cluster-server-log-selector-set-custom-log";
import ServiceClusterServerLogSelectorSelectLog from "./cluster-server-log-selector-select-log"; import ServiceClusterServerLogSelectorSelectLog from "./cluster-server-log-selector-select-log";

View File

@ -2,8 +2,6 @@ import Stack from "@/twui/components/layout/Stack";
import { RefObject, useContext, useEffect, useRef, useState } from "react"; import { RefObject, useContext, useEffect, useRef, useState } from "react";
import { AppContext } from "@/src/pages/_app"; import { AppContext } from "@/src/pages/_app";
import { import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
ServerTerminalTargets, ServerTerminalTargets,
TtydInfoObject, TtydInfoObject,
WebSocketDataType, WebSocketDataType,
@ -15,6 +13,10 @@ import Center from "@/twui/components/layout/Center";
import TtydIframe from "@/src/components/general/ttyd-iframe"; import TtydIframe from "@/src/components/general/ttyd-iframe";
import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver"; import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver";
import useStatus from "@/twui/components/hooks/useStatus"; import useStatus from "@/twui/components/hooks/useStatus";
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
} from "@/src/types/turboci";
type Props = { type Props = {
service: ParsedDeploymentServiceConfig; service: ParsedDeploymentServiceConfig;

View File

@ -4,8 +4,7 @@ import { AppContext } from "@/src/pages/_app";
import { import {
NormalizedServerObject, NormalizedServerObject,
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
ServerTerminalTargets, } from "@/src/types/turboci";
} from "@/src/types";
import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver"; import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver";
import Center from "@/twui/components/layout/Center"; import Center from "@/twui/components/layout/Center";
import Loading from "@/twui/components/elements/Loading"; import Loading from "@/twui/components/elements/Loading";
@ -14,6 +13,7 @@ import Row from "@/twui/components/layout/Row";
import Button from "@/twui/components/layout/Button"; import Button from "@/twui/components/layout/Button";
import ServiceClusterServerLogSelector from "./cluster-server-log-selector"; import ServiceClusterServerLogSelector from "./cluster-server-log-selector";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { ServerTerminalTargets } from "@/src/types";
type Props = { type Props = {
service: ParsedDeploymentServiceConfig; service: ParsedDeploymentServiceConfig;
@ -51,6 +51,7 @@ export default function ServiceClusterServer({
<Row className="w-full justify-between p-4 -mb-6"> <Row className="w-full justify-between p-4 -mb-6">
<Row> <Row>
<code>{server.private_ip}</code> <code>{server.private_ip}</code>
{server.public_ip ? <code>{server.public_ip}</code> : null}
</Row> </Row>
<Row className=""> <Row className="">

View File

@ -4,7 +4,7 @@ import { AppContext } from "@/src/pages/_app";
import { import {
NormalizedServerObject, NormalizedServerObject,
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
} from "@/src/types"; } from "@/src/types/turboci";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import ServiceClusterServer from "./cluster-server"; import ServiceClusterServer from "./cluster-server";

View File

@ -2,15 +2,9 @@ import Stack from "@/twui/components/layout/Stack";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { AppContext } from "@/src/pages/_app"; import { AppContext } from "@/src/pages/_app";
import ServiceCluster from "../(partials)/cluster"; import ServiceCluster from "../(partials)/cluster";
import { import { ParsedDeploymentServiceConfig } from "@/src/types/turboci";
NormalizedServerObject,
ParsedDeploymentServiceConfig,
} from "@/src/types";
import Button from "@/twui/components/layout/Button";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import { twMerge } from "tailwind-merge";
import Select from "@/twui/components/form/Select"; import Select from "@/twui/components/form/Select";
import ServiceClusterServer from "../(partials)/cluster-server";
import H2 from "@/twui/components/layout/H2"; import H2 from "@/twui/components/layout/H2";
import _ from "lodash"; import _ from "lodash";

View File

@ -1,77 +0,0 @@
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
} from "@/src/types";
import execSSH from "@/src/utils/exec-ssh";
import serviceFlight from "@/src/utils/flight";
import grabTurboCiConfig from "@/src/utils/grab-turboci-config";
export default async function cronCheckServices() {
const config = grabTurboCiConfig();
for (let i = 0; i < config.services.length; i++) {
const service = config.services[i];
if (!service.servers) {
continue;
}
for (let srv = 0; srv < service.servers.length; srv++) {
const server = service.servers[srv];
if (service.healthcheck) {
const test = await healthcheck({ server, service });
if (!test) {
console.log(
`Server ${server.private_ip} down. Restarting ...`,
);
const MAX_RETRIES = 5;
let retries = 0;
while (retries < MAX_RETRIES) {
console.log(`Retryig #${retries + 1} ...`);
await serviceFlight({
deployment: config,
servers: [server],
service,
});
await Bun.sleep(4000);
const retest = await healthcheck({ server, service });
if (retest) {
break;
} else {
retries++;
}
}
}
}
}
}
}
async function healthcheck({
server,
service,
}: {
service: ParsedDeploymentServiceConfig;
server: NormalizedServerObject;
}) {
if (!service.healthcheck?.cmd || !server.private_ip) {
return false;
}
const res = await execSSH({
cmd: service.healthcheck.cmd,
ip: server.private_ip,
});
const test = Boolean(res?.match(service.healthcheck.test));
return test;
}

View File

@ -0,0 +1,38 @@
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
TCIGlobalConfig,
} from "@/src/types/turboci";
import execSSH from "@/src/utils/exec-ssh";
import serviceFlight from "@/src/utils/flight";
type Params = {
service: ParsedDeploymentServiceConfig;
config: TCIGlobalConfig;
};
export default async function cronCheckServicesGit({
config,
service,
}: Params) {
if (service.git) {
const service_git_array = Array.isArray(service.git)
? service.git
: [service.git];
for (let i = 0; i < service_git_array.length; i++) {
const service_git = service_git_array[i];
if (!service_git.keep_updated) {
continue;
}
const work_dir = service_git.work_dir || "/turboci/app";
let cmd = ``;
cmd += `set -e\n`;
cmd += `\n`;
}
}
}

View File

@ -0,0 +1,71 @@
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
TCIGlobalConfig,
} from "@/src/types/turboci";
import execSSH from "@/src/utils/exec-ssh";
import serviceFlight from "@/src/utils/flight";
type Params = {
service: ParsedDeploymentServiceConfig;
server: NormalizedServerObject;
config: TCIGlobalConfig;
};
export default async function cronCheckServicesHealtcheck({
config,
server,
service,
}: Params) {
if (service.healthcheck) {
const test = await healthcheck({ server, service });
if (!test) {
console.log(`Server ${server.private_ip} down. Restarting ...`);
const MAX_RETRIES = 5;
let retries = 0;
while (retries < MAX_RETRIES) {
console.log(`Retryig #${retries + 1} ...`);
await serviceFlight({
deployment: config,
servers: [server],
service,
});
await Bun.sleep(4000);
const retest = await healthcheck({ server, service });
if (retest) {
break;
} else {
retries++;
}
}
}
}
}
async function healthcheck({
server,
service,
}: {
service: ParsedDeploymentServiceConfig;
server: NormalizedServerObject;
}) {
if (!service.healthcheck?.cmd || !server.private_ip) {
return false;
}
const res = await execSSH({
cmd: service.healthcheck.cmd,
ip: server.private_ip,
});
const test = Boolean(res?.match(service.healthcheck.test));
return test;
}

View File

@ -0,0 +1,22 @@
import grabTurboCiConfig from "@/src/utils/grab-turboci-config";
import cronCheckServicesHealtcheck from "./healthcheck";
import serviceGitCheck from "../../utils/service-git-check";
export default async function cronCheckServices() {
const config = grabTurboCiConfig();
for (let i = 0; i < config.services.length; i++) {
const service = config.services[i];
if (!service.servers) {
continue;
}
await serviceGitCheck({ deployment: config, service });
for (let srv = 0; srv < service.servers.length; srv++) {
const server = service.servers[srv];
await cronCheckServicesHealtcheck({ config, server, service });
}
}
}

View File

@ -0,0 +1,112 @@
import {
ParsedDeploymentServiceConfig,
ResponseObject,
TCIGlobalConfig,
} from "@/src/types/turboci";
import bunGrabBulkSyncScripts from "@/src/utils/bun-grab-bulk-sync-script";
import serviceFlight from "@/src/utils/flight";
import grabGitRepoName from "@/src/utils/grab-git-repo-name";
import relayExecSSH from "@/src/utils/relay-exec-ssh";
import turboCIPkgrabDirNames from "@/src/utils/turboci-pkg-grab-dir-names";
import _ from "lodash";
import path from "path";
const { relayServerRsyncDir } = turboCIPkgrabDirNames();
type Params = {
service: ParsedDeploymentServiceConfig;
deployment: TCIGlobalConfig;
};
export default async function serviceGitCheck(
params: Params,
): Promise<ResponseObject> {
const { service, deployment } = params;
if (!service.git || !service.servers?.[0]) {
return { success: true };
}
const servers_private_ips = service.servers
.map((srv) => srv.private_ip)
.filter((ip) => Boolean(ip)) as string[];
const git_array = Array.isArray(service.git) ? service.git : [service.git];
for (let i = 0; i < git_array.length; i++) {
const service_git = git_array[i];
if (!service_git) continue;
const git_url = service_git.repo_url;
const repo_name = grabGitRepoName({ git_url });
if (!repo_name) continue;
const relay_dst = path.join(
relayServerRsyncDir,
service.service_name,
"git",
repo_name,
);
let git_pull_cmd = ``;
git_pull_cmd += `cd ${relay_dst}\n`;
git_pull_cmd += `git pull\n`;
const git_pull_check = await relayExecSSH({
cmd: git_pull_cmd,
log_error: true,
});
if (git_pull_check?.match(/Already up to date./i)) {
continue;
}
let cmd = ``;
const src = relay_dst + "/";
const dst = (service_git.work_dir || "/turboci/app") + "/";
const sync_cmd = await relayExecSSH({
cmd: bunGrabBulkSyncScripts({
dst,
src,
private_server_ips: servers_private_ips,
parrallel: true,
relay_ignore: [".git"],
}),
bun: true,
return_cmd_only: true,
});
cmd += `${sync_cmd}\n`;
cmd += `echo "Git Setup Success!"\n`;
const res = await relayExecSSH({
cmd,
log_error: true,
debug: true,
});
if (!res?.match(/Git Setup Success/)) {
console.error(
`\`${service.service_name}\` service git prep failed!`,
);
continue;
}
await serviceFlight({
deployment,
servers: service.servers,
service,
});
}
return {
success: true,
};
}

View File

@ -2,13 +2,11 @@ import {
NSQLITE_TURBOCI_ADMIN_USERS_PORTS, NSQLITE_TURBOCI_ADMIN_USERS_PORTS,
NSQLiteTables, NSQLiteTables,
} from "@/src/db/types"; } from "@/src/db/types";
import { PrivateServerTtydParadigms, TtydInfoObject, User } from "@/src/types";
import { import {
NormalizedServerObject, NormalizedServerObject,
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
PrivateServerTtydParadigms, } from "@/src/types/turboci";
TtydInfoObject,
User,
} from "@/src/types";
import grabDirNames from "@/src/utils/grab-dir-names"; import grabDirNames from "@/src/utils/grab-dir-names";
import getNextAvailablePort from "@/src/utils/grab-next-available-port"; import getNextAvailablePort from "@/src/utils/grab-next-available-port";
import grabSSHPrefix from "@/src/utils/grab-ssh-prefix"; import grabSSHPrefix from "@/src/utils/grab-ssh-prefix";

View File

@ -4,178 +4,16 @@ import useAppInit from "../hooks/use-app-init";
import { ServerWebSocket } from "bun"; import { ServerWebSocket } from "bun";
import { ChildProcess } from "child_process"; import { ChildProcess } from "child_process";
import { NSQLITE_TURBOCI_ADMIN_USERS } from "../db/types"; import { NSQLITE_TURBOCI_ADMIN_USERS } from "../db/types";
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
TCIGlobalConfig,
} from "./turboci";
export type User = DATASQUIREL_LoggedInUser & { export type User = DATASQUIREL_LoggedInUser & {
super_admin?: boolean; super_admin?: boolean;
}; };
export const CloudProviders = [
{
title: "Hetzner",
value: "hetzner",
},
{
title: "Amazon Web Services",
value: "aws",
},
{
title: "Google Cloud Platform",
value: "gcp",
},
{
title: "Microsoft Azure",
value: "azure",
},
] as const;
export type ParsedDeploymentServiceConfig = TCIConfigServiceConfig & {
service_name: string;
parent_service_name?: string;
servers?: NormalizedServerObject[];
};
export type NormalizedServerObject = {
public_ip?: string;
private_ip?: string;
};
export type TCIConfig = {
deployment_name: string;
duplicate_deployment_name?: string;
description?: string;
location?: string;
availability_zone?: string;
provider: (typeof CloudProviders)[number]["value"];
services: TCIConfigService;
env?: { [k: string]: string };
env_file?: string;
pre_deployment?: TCIRunObj;
};
export type TCIGlobalConfig = Omit<TCIConfig, "services"> & {
services: ParsedDeploymentServiceConfig[];
relay_server_ip?: string;
};
export type TCIConfigService = {
[k: string]: TCIConfigServiceConfig;
};
export const TCIServiceTypes = [
{
title: "Default Service",
value: "default",
},
{
title: "Docker",
value: "docker",
},
{
title: "Load Balancer",
value: "load_balancer",
},
] as const;
export const TCIServiceOS = [
{
title: "Debian 12 Bookworm",
value: "debian_12",
},
{
title: "Debian 13 Buster",
value: "debian_13",
},
{
title: "Ubuntu 23.0.4",
value: "ubuntu_23_0_4",
},
] as const;
export const TCIServiceDependecyTypes = [
{
title: "Debian APT",
value: "apt",
},
{
title: "Turbo CI",
value: "turboci",
},
] as const;
export type TCIConfigServiceConfig = {
type?: (typeof TCIServiceTypes)[number]["value"];
os?: string;
server_type?: string;
enable_public_ip?: boolean;
instances?: number;
clusters?: number;
dir_mappings?: TCIConfigServiceConfigDirMApping[];
dependencies?: {
[k in (typeof TCIServiceDependecyTypes)[number]["value"]]?: string[];
};
env?: { [k: string]: string };
env_file?: string;
target_services?: TCIConfigServiceConfigLBTarget[];
run?: TCIConfigServiceConfigRun;
ssl?: TCIConfigServiceSSL;
duplicate_service_name?: string;
healthcheck?: TCIConfigServiceHealthcheck;
/**
* Commoands to Run on first run
*/
init?: string[];
logs?: TCIConfigServiceConfigLog[];
};
export type TCIConfigServiceConfigLog =
| string
| {
cmd: string;
};
export type TCIConfigServiceHealthcheck = {
cmd: string;
test: string;
};
export type TCIConfigServiceDomain = {
domain_name: string;
};
export type TCIConfigServiceSSL = {
email: string;
};
export type TCIConfigServiceConfigLBTarget = {
service_name: string;
port: number;
weight?: number;
backup?: boolean;
domains?: (string | TCIConfigServiceDomain)[];
};
export type TCIConfigServiceConfigRun = {
preflight?: TCIRunObj;
start?: TCIRunObj;
postflight?: TCIRunObj;
work_dir?: string;
};
export type TCIRunObj = {
cmds?: string[];
work_dir?: string;
file?: string;
};
export type TCIConfigServiceConfigDirMApping = {
src: string;
dst: string;
ignore_file?: string;
ignore_patterns?: string[];
use_gitignore?: boolean;
relay_ignore?: string[];
};
export type ServiceScriptObject = { export type ServiceScriptObject = {
sh: string; sh: string;
service_name: string; service_name: string;

363
src/types/turboci.ts Normal file
View File

@ -0,0 +1,363 @@
import type { ExecSyncOptions } from "child_process";
export const TCICommands = [
{
name: "up",
description: "Deploy Stack",
},
{
name: "down",
description: "Destroy Stack",
},
] as const;
export interface PackageJson {
name?: string;
version?: string;
description?: string;
bin?: Record<string, string>;
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
[key: string]: any;
}
export const CloudProviders = [
{
title: "Hetzner",
value: "hetzner",
},
{
title: "Amazon Web Services",
value: "aws",
},
{
title: "Google Cloud Platform",
value: "gcp",
},
{
title: "Microsoft Azure",
value: "azure",
},
] as const;
export type GrabConfigReturn = {
deployments: TCIGlobalConfig[];
envs?: string[];
};
export type TCIConfig =
| TCIConfigDeployment[]
| {
deployments: TCIConfigDeployment[];
envs?: string[];
};
export type TCIConfigDeployment = {
deployment_name: string;
duplicate_deployment_name?: string;
description?: string;
location?: string;
availability_zone?: string;
provider: (typeof CloudProviders)[number]["value"];
services: TCIConfigService;
env?: { [k: string]: string };
env_file?: string;
pre_deployment?: TCIRunObj;
relay_server_options?: TCIConfigRelayServerOptions;
};
export type TCIConfigRelayServerOptions = {
server_type?: string;
};
export type TCIGlobalConfig = Omit<TCIConfigDeployment, "services"> & {
services: ParsedDeploymentServiceConfig[];
relay_server_ip?: string;
};
export type TCIConfigService = {
[k: string]: TCIConfigServiceConfig;
};
export const TCIServiceTypes = [
{
title: "Default Service",
value: "default",
},
{
title: "Docker",
value: "docker",
},
{
title: "Load Balancer",
value: "load_balancer",
},
] as const;
export const TCIServiceOS = [
{
title: "Debian 12 Bookworm",
value: "debian_12",
},
{
title: "Debian 13 Buster",
value: "debian_13",
},
{
title: "Ubuntu 23.0.4",
value: "ubuntu_23_0_4",
},
] as const;
export const TCIServiceDependecyTypes = [
{
title: "Debian APT",
value: "apt",
},
{
title: "Turbo CI",
value: "turboci",
},
] as const;
export const TCIGitParadigms = [
{
title: "Github",
value: "github",
},
{
title: "Gitlab",
value: "gitlab",
},
{
title: "Gitea",
value: "gitea",
},
] as const;
export const TCIContainerRegistryParadigms = [
{
title: "Docker Hub",
value: "dockerhub",
},
{
title: "Github Container Registry",
value: "ghcr",
},
] as const;
export type TCIConfigServiceConfig = {
type?: (typeof TCIServiceTypes)[number]["value"];
os?: string;
server_type?: string;
enable_public_ip?: boolean;
instances?: number;
clusters?: number;
dir_mappings?: TCIConfigServiceConfigDirMApping[];
dependencies?: {
[k in (typeof TCIServiceDependecyTypes)[number]["value"]]?: string[];
};
env?: { [k: string]: string };
env_file?: string;
target_services?: TCIConfigServiceConfigLBTarget[];
run?: TCIConfigServiceConfigRun;
ssl?: TCIConfigServiceSSL;
duplicate_service_name?: string;
healthcheck?: TCIConfigServiceHealthcheck;
/**
* Commoands to Run on first run
*/
init?: string[];
logs?: TCIConfigServiceConfigLog[];
git?: TCIConfigServiceConfigGit | TCIConfigServiceConfigGit[];
};
export type TCIConfigServiceConfigGit = {
paradigm?: (typeof TCIGitParadigms)[number]["value"];
repo_url: string;
branch?: string;
/**
* Directory in target servers where the repo should
* live. Defaults to `/app`
*/
work_dir?: string;
public_repo?: boolean;
username?: string;
api_key?: string;
/**
* If true, this will continuosly pull from the git source
* and rerun the flight commands
*/
keep_updated?: boolean;
};
export type TCIConfigServiceConfigDocker = {
container_registry_paradigm?: (typeof TCIContainerRegistryParadigms)[number]["value"];
container_registry_url?: string;
compose?: { [k: string]: any };
/**
* Location of the dockerfile in the target servers
*/
docker_file_path?: { [k: string]: any };
/**
* Directory in target servers which is the docker
* reference for files like `docker-compose.yaml` or
* `Dockerfile`.
*/
work_dir?: string;
};
export type TCIConfigServiceConfigLog =
| string
| {
cmd: string;
};
export type TCIConfigServiceHealthcheck = {
cmd: string;
test: string;
};
export type TCIConfigServiceDomain = {
domain_name: string;
};
export type TCIConfigServiceSSL = {
email: string;
};
export type TCIConfigServiceConfigLBTarget = {
service_name: string;
port: number;
weight?: number;
backup?: boolean;
domains?: (string | TCIConfigServiceDomain)[];
};
export type TCIConfigServiceConfigRun = {
preflight?: TCIRunObj;
start?: TCIRunObj;
postflight?: TCIRunObj;
work_dir?: string;
};
export type TCIRunObj = {
cmds?: string[];
work_dir?: string;
file?: string;
};
export type TCIConfigServiceConfigDirMApping = {
src: string;
dst: string;
ignore_file?: string;
ignore_patterns?: string[];
use_gitignore?: boolean;
relay_ignore?: string[];
};
export type TCICommandOptions = {
file?: string;
};
export type TCIOptions = {
config?: TCIConfig;
};
export const TurboCIPreferedOS = ["debian", "ubuntu"] as const;
export const TurboCIOsPreferenceRegexp = new RegExp(
`${TurboCIPreferedOS.join("|")}`,
`i`,
);
export type SSHRelayServerReturn = {
ip: string;
private_ip: string;
};
export type NormalizedServerObject = {
public_ip?: string;
private_ip?: string;
};
export type SyncRemoteDirsParams = {
ip?: string;
ips?: string[];
user?: string;
src: string;
dst: string;
ignore_path?: string;
ignore_patterns?: string[];
use_gitignore?: boolean;
delete?: boolean;
debug?: boolean;
use_relay_server?: boolean;
deployment?: Omit<TCIConfigDeployment, "services">;
options?: ExecSyncOptions;
service?: TCIConfigServiceConfig;
service_name?: string;
relay_ignore?: string[];
};
export type DefaultPrepParams = {
service: ParsedDeploymentServiceConfig;
deployment: TCIGlobalConfig;
servers: NormalizedServerObject[];
};
export type ServiceScriptObject = {
sh: string;
service_name: string;
deployment_name: string;
work_dir?: string;
};
export type ParsedDeploymentServiceConfig = TCIConfigServiceConfig & {
service_name: string;
parent_service_name?: string;
servers?: NormalizedServerObject[];
};
export type DefaultDeploymentParams = {
service: ParsedDeploymentServiceConfig;
deployment: TCIGlobalConfig;
};
export type CommanderDefaultOptions = {
skip?: string[];
target?: string[];
};
export type TurbociControlServer = NormalizedServerObject & {
service_name?: "__relay" | (string & {});
deployment_name?: string;
};
export type TurbociControlReturn = {
servers?: TurbociControlServer[];
};
export const TurboCIDependencies = [
{
package_name: "bun",
},
{
package_name: "node",
},
{
package_name: "docker",
},
] as const;
export type DeploymentAndServicesToUpdate = {
deployment: TCIGlobalConfig;
services: ParsedDeploymentServiceConfig[];
skipped_services: ParsedDeploymentServiceConfig[];
};
export type ResponseObject = {
success: boolean;
msg?: string;
};

View File

@ -0,0 +1,86 @@
import { statSync } from "fs";
import _ from "lodash";
import path from "path";
import turboCIPkgrabDirNames from "./turboci-pkg-grab-dir-names";
import { AppData } from "../data/app-data";
type Params = {
private_server_ips: string[];
parrallel?: boolean;
/**
* Source on the relay server
*/
src: string;
/**
* Destination on private servers
*/
dst: string;
relay_ignore?: string[];
};
export default function bunGrabBulkSyncScripts({
private_server_ips,
parrallel,
src,
dst,
relay_ignore,
}: Params) {
const { relayServerSshPrivateKeyFile } = turboCIPkgrabDirNames();
// const srcStats = statSync(src);
// const isSrcFile = srcStats.isFile();
const dst_dir = src.match(/\.{1,5}$/)
? path.dirname(dst)
: path.normalize(dst);
let bunCmd = "";
bunCmd += `import _ from "lodash";\n`;
bunCmd += `import { execSync } from "child_process";\n`;
bunCmd += `\n`;
bunCmd += `const SSH_KEY = "${relayServerSshPrivateKeyFile}";\n`;
bunCmd += `const SSH_OPTS = \`-i \${SSH_KEY} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -C -c aes128-ctr\`;\n`;
bunCmd += `const REMOTE_HOSTS = [${private_server_ips
.map((h) => `"${h.replace(/\"/g, "")}"`)
.join(", ")}];\n`;
bunCmd += `const DEFAULT_SSH_USER = "root";\n`;
bunCmd += `const BATCH_SIZE = ${AppData["private_server_batch_exec_size"]};\n`;
bunCmd += `\n`;
bunCmd += `async function run(host: string) {\n`;
bunCmd += ` let execCmd = \`ssh \${SSH_OPTS} \${DEFAULT_SSH_USER}@\${host} mkdir -p ${dst_dir}\`;\n`;
bunCmd += ` execCmd += \` && rsync -avz -e 'ssh \${SSH_OPTS}' --delete\`;\n`;
if (relay_ignore) {
bunCmd += relay_ignore
.map((patt) => ` execCmd += \` --exclude='${patt}'\`;\n`)
.join("");
}
bunCmd += ` execCmd += \` ${src} \${DEFAULT_SSH_USER}@\${host}:${dst}\`;\n`;
bunCmd += ` try {\n`;
bunCmd += ` execSync(execCmd);\n`;
bunCmd += ` console.log("Sync Success!");\n`;
bunCmd += ` } catch (error) {\n`;
bunCmd += ` process.exit(1);\n`;
bunCmd += ` }\n`;
bunCmd += `}\n`;
bunCmd += `\n`;
if (parrallel) {
bunCmd += `const first_host = REMOTE_HOSTS.splice(0,1)[0];\n`;
bunCmd += `await run(first_host)\n`;
bunCmd += `\n`;
bunCmd += `const chunks = _.chunk(REMOTE_HOSTS, BATCH_SIZE);\n`;
bunCmd += `for (let i = 0; i < chunks.length; i++) {\n`;
bunCmd += ` const chunk = chunks[i];\n`;
bunCmd += ` const runChunk = await Promise.all(chunk.map(h => run(h)));\n`;
bunCmd += `}\n`;
} else {
bunCmd += `for (let i = 0; i < REMOTE_HOSTS.length; i++) {\n`;
bunCmd += ` const host = REMOTE_HOSTS[i];\n`;
bunCmd += ` const runHost = await run(host);\n`;
bunCmd += `}\n`;
}
return bunCmd;
}

View File

@ -6,7 +6,7 @@ import {
ParsedDeploymentServiceConfig, ParsedDeploymentServiceConfig,
ServiceScriptObject, ServiceScriptObject,
TCIGlobalConfig, TCIGlobalConfig,
} from "../types"; } from "@/src/types/turboci";
import { AppNames } from "./app-names"; import { AppNames } from "./app-names";
import grabSHEnvs from "./grab-sh-env"; import grabSHEnvs from "./grab-sh-env";
import bunGrabPrivateIPsBulkScripts from "./bun-grab-private-ips-bulk-scripts"; import bunGrabPrivateIPsBulkScripts from "./bun-grab-private-ips-bulk-scripts";

View File

@ -0,0 +1,12 @@
export default function grabGitRepoName({
git_url,
}: {
git_url: string;
}): string | undefined {
const git_arr = git_url.split("/");
const repo_name = git_arr.pop()?.replace(/\.git$/, "");
const repo_user_name = git_arr.pop();
return `${repo_user_name}/${repo_name}`;
}

View File

@ -1,6 +1,9 @@
import _ from "lodash"; import _ from "lodash";
import path from "path"; import path from "path";
import { ParsedDeploymentServiceConfig, TCIGlobalConfig } from "../types"; import {
ParsedDeploymentServiceConfig,
TCIGlobalConfig,
} from "@/src/types/turboci";
import parseEnv from "./parse-env"; import parseEnv from "./parse-env";
type Params = { type Params = {

View File

@ -1,6 +1,6 @@
import fs from "fs"; import fs from "fs";
import grabDirNames from "./grab-dir-names"; import grabDirNames from "./grab-dir-names";
import { TCIGlobalConfig } from "@/src/types"; import { TCIGlobalConfig } from "@/src/types/turboci";
export default function grabTurboCiConfig() { export default function grabTurboCiConfig() {
const { TURBOCI_CONFIG_JSON_FILE } = grabDirNames(); const { TURBOCI_CONFIG_JSON_FILE } = grabDirNames();