Compare commits
2 Commits
c5672e57bd
...
071f1a02b5
| Author | SHA1 | Date | |
|---|---|---|---|
| 071f1a02b5 | |||
| 7b12dc9a9b |
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
.sandlot/
|
||||||
|
|
||||||
# dependencies (bun install)
|
# dependencies (bun install)
|
||||||
node_modules
|
node_modules
|
||||||
pub/client/index.js
|
pub/client/index.js
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
AppSelectorChevron,
|
AppSelectorChevron,
|
||||||
DashboardContainer,
|
DashboardContainer,
|
||||||
DashboardHeader,
|
DashboardHeader,
|
||||||
|
DashboardInstallCmd,
|
||||||
DashboardTitle,
|
DashboardTitle,
|
||||||
StatusDot,
|
StatusDot,
|
||||||
StatusDotLink,
|
StatusDotLink,
|
||||||
|
|
@ -35,7 +36,9 @@ export function DashboardLanding({ render }: { render: () => void }) {
|
||||||
</AppSelectorChevron>
|
</AppSelectorChevron>
|
||||||
)}
|
)}
|
||||||
</DashboardTitle>
|
</DashboardTitle>
|
||||||
{/*<DashboardSubtitle>Your personal web appliance</DashboardSubtitle>*/}
|
<DashboardInstallCmd>
|
||||||
|
curl -fsSL {location.origin}/install | bash
|
||||||
|
</DashboardInstallCmd>
|
||||||
</DashboardHeader>
|
</DashboardHeader>
|
||||||
|
|
||||||
<StatusDotsRow>
|
<StatusDotsRow>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ export {
|
||||||
ClickableAppName,
|
ClickableAppName,
|
||||||
DashboardContainer,
|
DashboardContainer,
|
||||||
DashboardHeader,
|
DashboardHeader,
|
||||||
|
DashboardInstallCmd,
|
||||||
DashboardSubtitle,
|
DashboardSubtitle,
|
||||||
DashboardTitle,
|
DashboardTitle,
|
||||||
HamburgerButton,
|
HamburgerButton,
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,14 @@ export const DashboardTitle = define('DashboardTitle', {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const DashboardInstallCmd = define('DashboardInstallCmd', {
|
||||||
|
base: 'code',
|
||||||
|
fontSize: 13,
|
||||||
|
opacity: 0.6,
|
||||||
|
userSelect: 'all',
|
||||||
|
cursor: 'text',
|
||||||
|
})
|
||||||
|
|
||||||
export const DashboardSubtitle = define('DashboardSubtitle', {
|
export const DashboardSubtitle = define('DashboardSubtitle', {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme('colors-textMuted'),
|
color: theme('colors-textMuted'),
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import syncRouter from './api/sync'
|
||||||
import systemRouter from './api/system'
|
import systemRouter from './api/system'
|
||||||
import { Hype } from '@because/hype'
|
import { Hype } from '@because/hype'
|
||||||
import { cleanupStalePublishers } from './mdns'
|
import { cleanupStalePublishers } from './mdns'
|
||||||
|
import { extractSubdomain, proxySubdomain, proxyWebSocket, websocket } from './proxy'
|
||||||
import type { Server } from 'bun'
|
import type { Server } from 'bun'
|
||||||
import type { WsData } from './proxy'
|
import type { WsData } from './proxy'
|
||||||
import { extractSubdomain, proxySubdomain, proxyWebSocket, websocket } from './proxy'
|
|
||||||
|
|
||||||
const app = new Hype({ layout: false, logging: !!process.env.DEBUG })
|
const app = new Hype({ layout: false, logging: !!process.env.DEBUG })
|
||||||
|
|
||||||
|
|
@ -59,6 +59,31 @@ app.all('/api/tools/:tool/:path{.+}', async c => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const DIST_DIR = import.meta.dir + '/../../dist'
|
||||||
|
const INSTALL_SCRIPT = await Bun.file(import.meta.dir + '/install.sh').text()
|
||||||
|
|
||||||
|
// Install script: curl -fsSL http://toes.local/install | bash
|
||||||
|
app.get('/install', c => {
|
||||||
|
if (!TOES_URL) return c.text('TOES_URL is not configured', 500)
|
||||||
|
const script = INSTALL_SCRIPT.replace('__TOES_URL__', TOES_URL)
|
||||||
|
return c.text(script, 200, { 'content-type': 'text/plain' })
|
||||||
|
})
|
||||||
|
|
||||||
|
// Serve built CLI binaries from dist/
|
||||||
|
app.get('/dist/:file', async c => {
|
||||||
|
const file = c.req.param('file')
|
||||||
|
if (!file || file.includes('/') || file.includes('..')) {
|
||||||
|
return c.text('Not found', 404)
|
||||||
|
}
|
||||||
|
const bunFile = Bun.file(`${DIST_DIR}/${file}`)
|
||||||
|
if (!(await bunFile.exists())) {
|
||||||
|
return c.text(`Binary "${file}" not found — run cli:build:all on the server`, 404)
|
||||||
|
}
|
||||||
|
return new Response(bunFile, {
|
||||||
|
headers: { 'content-type': 'application/octet-stream' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
cleanupStalePublishers()
|
cleanupStalePublishers()
|
||||||
await initApps()
|
await initApps()
|
||||||
|
|
||||||
|
|
|
||||||
38
src/server/install.sh
Normal file
38
src/server/install.sh
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
|
||||||
|
case "$OS" in
|
||||||
|
darwin) OS=macos ;;
|
||||||
|
linux) OS=linux ;;
|
||||||
|
*) echo "Unsupported OS: $OS" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$ARCH" in
|
||||||
|
x86_64) ARCH=x64 ;;
|
||||||
|
arm64|aarch64) ARCH=arm64 ;;
|
||||||
|
*) echo "Unsupported arch: $ARCH" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
BINARY="toes-${OS}-${ARCH}"
|
||||||
|
URL="__TOES_URL__/dist/${BINARY}"
|
||||||
|
|
||||||
|
if [ -n "$TOES_INSTALL_DIR" ]; then
|
||||||
|
INSTALL_DIR="$TOES_INSTALL_DIR"
|
||||||
|
elif [ -d /usr/local/bin ] && [ -w /usr/local/bin ]; then
|
||||||
|
INSTALL_DIR=/usr/local/bin
|
||||||
|
else
|
||||||
|
INSTALL_DIR="$HOME/.local/bin"
|
||||||
|
fi
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
|
||||||
|
echo "Downloading toes CLI (${OS}/${ARCH})..."
|
||||||
|
curl -fsSL "$URL" -o "$INSTALL_DIR/toes"
|
||||||
|
chmod +x "$INSTALL_DIR/toes"
|
||||||
|
echo "Installed toes to $INSTALL_DIR/toes"
|
||||||
|
|
||||||
|
if ! echo "$PATH" | tr ':' '\n' | grep -qx "$INSTALL_DIR"; then
|
||||||
|
echo "Add $INSTALL_DIR to your PATH to use toes globally"
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue
Block a user