diff --git a/docs/APPS.md b/docs/APPS.md new file mode 100644 index 0000000..851bebf --- /dev/null +++ b/docs/APPS.md @@ -0,0 +1,85 @@ +# Apps + +An app is an HTTP server that runs on its assigned port. + +## minimum requirements + +``` +apps// + / # YYYYMMDD-HHMMSS + package.json + index.tsx + current -> # symlink to active version +``` + +**package.json** must have `scripts.toes`: + +```json +{ + "name": "my-app", + "module": "index.tsx", + "type": "module", + "private": true, + "scripts": { + "toes": "bun run --watch index.tsx" + }, + "toes": { + "icon": "🎨" + }, + "dependencies": { + "@because/hype": "*", + "@because/forge": "*" + } +} +``` + +**index.tsx** must export `app.defaults`: + +```tsx +import { Hype } from '@because/hype' + +const app = new Hype() +app.get('/', c => c.html(

Hello

)) + +export default app.defaults +``` + +## environment + +- `PORT` - your assigned port (3001-3100) +- `APPS_DIR` - path to `/apps` directory + +## health checks + +Toes hits `GET /` every 30 seconds. Return 2xx or get restarted. + +3 failures = restart with exponential backoff (1s, 2s, 4s, 8s, 16s, 32s). + +## lifecycle + +`invalid` -> `stopped` -> `starting` -> `running` -> `stopping` + +Apps auto-restart on crash. `bun install` runs before every start. + +## cli + +```bash +toes new my-app # create from template +toes list # show apps +toes start my-app # start +toes stop my-app # stop +toes restart my-app # restart +toes logs -f my-app # tail logs +toes open my-app # open in browser +``` + +## making a new app + +```bash +toes new my-app --template=spa +``` + +- `ssr` - server-side rendered (default) +- `spa` - single page app (w/ hono/jsx) +- `bare` - minimal + diff --git a/docs/TOOLS.md b/docs/TOOLS.md new file mode 100644 index 0000000..ca9b11f --- /dev/null +++ b/docs/TOOLS.md @@ -0,0 +1,80 @@ +# Tools + +A tool is an app that appears as a tab in the dashboard instead of in the sidebar. + +Tools know which app is selected and render in an iframe over the content area. + +## making an app a tool + +Add `toes.tool` to package.json: + +```json +{ + "toes": { + "tool": true, + "icon": "🔧" + }, + "scripts": { + "toes": "bun run --watch index.tsx" + } +} +``` + +## getting the selected app + +Query param `?app=` tells you which app the user selected: + +```tsx +app.get('/', c => { + const appName = c.req.query('app') + if (!appName) { + return c.html(

No app selected

) + } + // do something with appName +}) +``` + +## accessing app files + +Always go through the `current` symlink: + +```ts +const APPS_DIR = process.env.APPS_DIR ?? '.' +const appPath = join(APPS_DIR, appName, 'current') +``` + +Not `APPS_DIR/appName` directly. + +## talking to the parent + +**Navigate to another tool:** + +```js +window.parent.postMessage({ + type: 'navigate-tool', + tool: 'code', + params: { app: 'my-app', version: '20260130-000000' } +}, '*') +``` + +**Resize your iframe:** + +```js +window.parent.postMessage({ + type: 'resize-iframe', + height: 500 +}, '*') +``` + +## iframe behavior + +- iframes are cached per tool+app combination +- Never recreated once loaded +- State persists across tab switches + +## cli + +```bash +toes list --tools # list tools only +toes list --all # list apps and tools +```