create-theokit 0.4.0-beta.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/cli.js +4 -3
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +8 -4
  4. package/templates/default/.env.example +5 -0
  5. package/templates/default/README.md.tmpl +71 -57
  6. package/templates/default/_gitignore +2 -3
  7. package/templates/default/app/layout.tsx +51 -82
  8. package/templates/default/app/page.tsx +169 -271
  9. package/templates/default/app.ts +29 -0
  10. package/templates/default/package.json.tmpl +9 -23
  11. package/templates/default/public/index.html +70 -0
  12. package/templates/default/server/agents/assistant.agent.ts +46 -0
  13. package/templates/default/server/controllers/tasks.controller.ts +70 -0
  14. package/templates/default/server/filters/http-error.filter.ts +20 -0
  15. package/templates/default/server/guards/auth.guard.ts +47 -0
  16. package/templates/default/server/interceptors/timing.interceptor.ts +14 -0
  17. package/templates/default/server/middleware/logger.middleware.ts +12 -0
  18. package/templates/default/server/store.ts +46 -0
  19. package/templates/default/server/toolboxes/task.tools.ts +58 -0
  20. package/templates/default/tsconfig.json +7 -7
  21. package/LICENSE +0 -201
  22. package/templates/api-only/.nvmrc +0 -1
  23. package/templates/api-only/README.md.tmpl +0 -78
  24. package/templates/api-only/_gitignore +0 -5
  25. package/templates/api-only/app/page.tsx +0 -3
  26. package/templates/api-only/index.html +0 -12
  27. package/templates/api-only/package.json.tmpl +0 -28
  28. package/templates/api-only/public/.gitkeep +0 -0
  29. package/templates/api-only/public/favicon.ico +0 -0
  30. package/templates/api-only/server/routes/health.ts +0 -5
  31. package/templates/api-only/server/routes/users.ts +0 -27
  32. package/templates/api-only/server/routes/webhooks/echo.ts +0 -34
  33. package/templates/api-only/theo.config.ts +0 -3
  34. package/templates/api-only/tsconfig.json +0 -15
  35. package/templates/dashboard/.nvmrc +0 -1
  36. package/templates/dashboard/README.md.tmpl +0 -76
  37. package/templates/dashboard/_gitignore +0 -5
  38. package/templates/dashboard/app/about/page.tsx +0 -3
  39. package/templates/dashboard/app/dashboard/layout.tsx +0 -10
  40. package/templates/dashboard/app/dashboard/page.tsx +0 -3
  41. package/templates/dashboard/app/layout.tsx +0 -14
  42. package/templates/dashboard/app/page.tsx +0 -8
  43. package/templates/dashboard/index.html +0 -12
  44. package/templates/dashboard/package.json.tmpl +0 -28
  45. package/templates/dashboard/public/.gitkeep +0 -0
  46. package/templates/dashboard/public/favicon.ico +0 -0
  47. package/templates/dashboard/server/crons/cleanup-conversations.ts +0 -59
  48. package/templates/dashboard/server/routes/health.ts +0 -5
  49. package/templates/dashboard/theo.config.ts +0 -3
  50. package/templates/dashboard/tsconfig.json +0 -15
  51. package/templates/default/.nvmrc +0 -1
  52. package/templates/default/index.html +0 -12
  53. package/templates/default/public/.gitkeep +0 -0
  54. package/templates/default/public/favicon.ico +0 -0
  55. package/templates/default/server/crons/cleanup-conversations.ts +0 -59
  56. package/templates/default/server/routes/chat.ts +0 -69
  57. package/templates/default/server/routes/health.ts +0 -5
  58. package/templates/default/theo.config.ts +0 -3
  59. package/templates/default/types/jobs.d.ts +0 -25
  60. package/templates/postgres/.env.example +0 -5
  61. package/templates/postgres/.nvmrc +0 -1
  62. package/templates/postgres/README.md.tmpl +0 -83
  63. package/templates/postgres/_gitignore +0 -5
  64. package/templates/postgres/app/layout.tsx +0 -14
  65. package/templates/postgres/app/page.tsx +0 -8
  66. package/templates/postgres/db/index.ts +0 -7
  67. package/templates/postgres/db/schema.ts +0 -8
  68. package/templates/postgres/drizzle.config.ts +0 -10
  69. package/templates/postgres/index.html +0 -12
  70. package/templates/postgres/package.json.tmpl +0 -36
  71. package/templates/postgres/public/.gitkeep +0 -0
  72. package/templates/postgres/public/favicon.ico +0 -0
  73. package/templates/postgres/server/context.ts +0 -5
  74. package/templates/postgres/server/jobs/log-message.ts +0 -26
  75. package/templates/postgres/server/routes/health.ts +0 -5
  76. package/templates/postgres/server/routes/users.ts +0 -22
  77. package/templates/postgres/theo.config.ts +0 -3
  78. package/templates/postgres/tsconfig.json +0 -15
  79. package/templates/saas/.env.example +0 -7
  80. package/templates/saas/.nvmrc +0 -1
  81. package/templates/saas/README.md.tmpl +0 -103
  82. package/templates/saas/_gitignore +0 -5
  83. package/templates/saas/app/layout.tsx +0 -5
  84. package/templates/saas/app/page.tsx +0 -104
  85. package/templates/saas/db/index.ts +0 -6
  86. package/templates/saas/db/schema.ts +0 -20
  87. package/templates/saas/drizzle.config.ts +0 -10
  88. package/templates/saas/index.html +0 -12
  89. package/templates/saas/package.json.tmpl +0 -38
  90. package/templates/saas/public/.gitkeep +0 -0
  91. package/templates/saas/public/favicon.ico +0 -0
  92. package/templates/saas/server/context.ts +0 -37
  93. package/templates/saas/server/routes/agent.ts +0 -49
  94. package/templates/saas/server/routes/billing/stripe-webhook.ts +0 -49
  95. package/templates/saas/server/routes/login.ts +0 -25
  96. package/templates/saas/server/routes/logout.ts +0 -10
  97. package/templates/saas/server/routes/me.ts +0 -10
  98. package/templates/saas/theo.config.ts +0 -5
  99. package/templates/saas/tsconfig.json +0 -15
  100. package/templates/services/agent-node/Dockerfile.tmpl +0 -20
  101. package/templates/services/agent-node/README.md +0 -38
  102. package/templates/services/agent-node/package.json.tmpl +0 -18
  103. package/templates/services/agent-node/src/index.ts +0 -58
  104. package/templates/services/agent-node/tsconfig.json +0 -13
  105. package/templates/services/agent-python/Dockerfile.tmpl +0 -20
  106. package/templates/services/agent-python/README.md +0 -37
  107. package/templates/services/agent-python/main.py +0 -77
  108. package/templates/services/agent-python/pyproject.toml.tmpl +0 -16
@@ -1,34 +0,0 @@
1
- import { defineWebhook } from 'theokit/server'
2
- import { createHmac, timingSafeEqual } from 'node:crypto'
3
- import { z } from 'zod'
4
-
5
- /**
6
- * Echo webhook — demonstrates `defineWebhook` HMAC-SHA256 pattern
7
- * without depending on an external provider (Stripe, GitHub, etc.).
8
- *
9
- * Self-test:
10
- * SECRET=$(openssl rand -base64 32)
11
- * echo -n '{"message":"hi"}' | openssl dgst -sha256 -hmac "$SECRET"
12
- * curl -X POST localhost:3000/api/webhooks/echo \
13
- * -H "x-echo-signature: <hex from above>" \
14
- * -H "Content-Type: application/json" \
15
- * -d '{"message":"hi"}'
16
- */
17
- const ECHO_SECRET = process.env.ECHO_WEBHOOK_SECRET ?? ''
18
-
19
- export const POST = defineWebhook({
20
- verify: ({ rawBody, headers }) => {
21
- if (ECHO_SECRET === '') return false
22
- const sig = headers.get('x-echo-signature') ?? ''
23
- const expected = createHmac('sha256', ECHO_SECRET).update(rawBody).digest('hex')
24
- try {
25
- return timingSafeEqual(Buffer.from(sig, 'utf-8'), Buffer.from(expected, 'utf-8'))
26
- } catch {
27
- return false
28
- }
29
- },
30
- inputSchema: z.object({ message: z.string() }),
31
- handler: async ({ input }) => {
32
- return Response.json({ echoed: input.message, timestamp: new Date().toISOString() })
33
- },
34
- })
@@ -1,3 +0,0 @@
1
- import { defineConfig } from 'theokit'
2
-
3
- export default defineConfig({})
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "noEmit": true,
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "jsx": "react-jsx",
11
- "isolatedModules": true,
12
- "resolveJsonModule": true
13
- },
14
- "include": ["app/**/*.ts", "app/**/*.tsx", "server/**/*.ts"]
15
- }
@@ -1 +0,0 @@
1
- 22.12
@@ -1,76 +0,0 @@
1
- # {{name}}
2
-
3
- TheoKit dashboard project. Build the app your agent lives in — with nested layouts and a sidebar wired from day one.
4
-
5
- > 📚 **Full docs:** https://docs.theokit.dev
6
-
7
- ## Quick start
8
-
9
- ```bash
10
- # 1. Set your provider key (OpenRouter recommended — one key, any model)
11
- echo 'OPENROUTER_API_KEY=sk-or-v1-...' > .env
12
-
13
- # 2. Boot the dev server
14
- npx theokit dev
15
- ```
16
-
17
- Open the printed URL. The default surface is a dashboard shell with sidebar nav + content area, ready to host your agent panels.
18
-
19
- ## Templates
20
-
21
- - **default** — TheoUI chat composer + agent route.
22
- - **dashboard** (this one) — nested layouts + sidebar nav.
23
- - **api-only** — server routes without React.
24
- - **postgres** — Drizzle ORM + migrations.
25
- - **saas** — full app with auth, billing, sessions.
26
-
27
- ## What the framework auto-loads
28
-
29
- - **`.env` → `process.env`**. Edit `.env`; restart the dev server.
30
- - **`.theo/` build output cleanup** on every `theokit build`.
31
- - **Tailwind + `@theokit/ui` styling** auto-configured for the TheoUI surface.
32
-
33
- ## Project structure
34
-
35
- ```
36
- app/ Frontend (file-based routing with nested layouts)
37
- ├── layout.tsx root wrapper — TheoUI provider + theme
38
- ├── page.tsx / — dashboard home
39
- ├── dashboard/
40
- │ ├── layout.tsx /dashboard/* — sidebar shell
41
- │ └── page.tsx /dashboard — primary panel
42
- server/ Backend (explicit routes)
43
- ├── routes/
44
- │ └── health.ts GET /api/health
45
- theo.config.ts Framework config
46
- tailwind.config.ts Tailwind theme tokens
47
- .env Secrets — never committed
48
- ```
49
-
50
- ## Common commands
51
-
52
- | Command | What it does |
53
- |---|---|
54
- | `npx theokit dev` | Dev server with HMR + devtools overlay |
55
- | `npx theokit build` | Production build → `.theo/` |
56
- | `npx theokit start` | Serve the production build |
57
- | `npx theokit check` | Lint for upgrade-readiness |
58
- | `npx theokit routes` | List all routes + actions detected |
59
- | `npm run typecheck` | TypeScript strict check (no emit) |
60
-
61
- ## Add a new panel
62
-
63
- ```bash
64
- mkdir -p app/dashboard/billing
65
- cat > app/dashboard/billing/page.tsx <<'EOF'
66
- export default function BillingPage() {
67
- return <h2>Billing</h2>
68
- }
69
- EOF
70
- ```
71
-
72
- The route appears at `/dashboard/billing` after HMR.
73
-
74
- ## License
75
-
76
- Apply your own. The TheoKit framework is Apache-2.0.
@@ -1,5 +0,0 @@
1
- node_modules
2
- .theo
3
- dist
4
- .env
5
- .env.local
@@ -1,3 +0,0 @@
1
- export default function AboutPage() {
2
- return <h1>About</h1>
3
- }
@@ -1,10 +0,0 @@
1
- import { Outlet } from 'react-router'
2
-
3
- export default function DashboardLayout() {
4
- return (
5
- <div>
6
- <h2>Dashboard Area</h2>
7
- <Outlet />
8
- </div>
9
- )
10
- }
@@ -1,3 +0,0 @@
1
- export default function DashboardPage() {
2
- return <h1>Dashboard</h1>
3
- }
@@ -1,14 +0,0 @@
1
- import { Outlet } from 'react-router'
2
-
3
- export default function RootLayout() {
4
- return (
5
- <div>
6
- <nav>
7
- <a href="/">Home</a> | <a href="/about">About</a> | <a href="/dashboard">Dashboard</a>
8
- </nav>
9
- <main>
10
- <Outlet />
11
- </main>
12
- </div>
13
- )
14
- }
@@ -1,8 +0,0 @@
1
- export default function HomePage() {
2
- return (
3
- <div>
4
- <h1>Welcome to Theo</h1>
5
- <p>Your fullstack TypeScript framework.</p>
6
- </div>
7
- )
8
- }
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Theo App</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/@theo/entry-client"></script>
11
- </body>
12
- </html>
@@ -1,28 +0,0 @@
1
- {
2
- "name": "{{name}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "theokit dev",
8
- "build": "theokit build",
9
- "start": "theokit start",
10
- "typecheck": "tsc --noEmit"
11
- },
12
- "dependencies": {
13
- "theokit": "^0.4.0-beta.0",
14
- "react": "^19.0.0",
15
- "react-dom": "^19.0.0"
16
- },
17
- "devDependencies": {
18
- "@types/node": "^22.10.0",
19
- "typescript": "^5.7.0",
20
- "@types/react": "^19.0.0",
21
- "@types/react-dom": "^19.0.0"
22
- },
23
- "pnpm": {
24
- "onlyBuiltDependencies": [
25
- "esbuild"
26
- ]
27
- }
28
- }
File without changes
@@ -1,59 +0,0 @@
1
- import { defineCron } from 'theokit/server/cron'
2
- import { readdir, stat, rm } from 'node:fs/promises'
3
- import type { Dirent } from 'node:fs'
4
- import { join, resolve } from 'node:path'
5
-
6
- /**
7
- * Daily GC of stale conversation transcripts.
8
- *
9
- * The `@theokit/sdk` Agent persists chat history under
10
- * `.theokit/agents/<agentId>/messages.jsonl`. With no TTL the directory
11
- * grows unbounded — production foot-gun. This cron removes any agent
12
- * directory whose `messages.jsonl` hasn't been touched in 30 days.
13
- */
14
- const MAX_AGE_DAYS = 30
15
- const AGENTS_DIR = '.theokit/agents'
16
-
17
- export default defineCron('cleanup-conversations', {
18
- schedule: '0 4 * * *', // Daily 04:00 UTC
19
- handler: async ({ traceId }) => {
20
- const root = resolve(process.cwd(), AGENTS_DIR)
21
- const cutoff = Date.now() - MAX_AGE_DAYS * 24 * 60 * 60 * 1000
22
- let removed = 0
23
- let kept = 0
24
- let entries: Dirent[]
25
- try {
26
- entries = (await readdir(root, { withFileTypes: true })) as unknown as Dirent[]
27
- } catch {
28
- console.info(JSON.stringify({ msg: 'No agents dir yet — first run', dir: root, traceId }))
29
- return
30
- }
31
- for (const entry of entries) {
32
- if (!entry.isDirectory()) continue
33
- const agentDir = join(root, String(entry.name))
34
- const messagesFile = join(agentDir, 'messages.jsonl')
35
- try {
36
- const s = await stat(messagesFile)
37
- if (s.mtimeMs < cutoff) {
38
- await rm(agentDir, { recursive: true, force: true })
39
- removed++
40
- } else {
41
- kept++
42
- }
43
- } catch {
44
- // messages.jsonl missing → orphan dir, remove
45
- await rm(agentDir, { recursive: true, force: true }).catch(() => {})
46
- removed++
47
- }
48
- }
49
- console.info(
50
- JSON.stringify({
51
- msg: 'cleanup-conversations complete',
52
- removed,
53
- kept,
54
- maxAgeDays: MAX_AGE_DAYS,
55
- traceId,
56
- }),
57
- )
58
- },
59
- })
@@ -1,5 +0,0 @@
1
- import { defineRoute } from 'theokit/server'
2
-
3
- export const GET = defineRoute({
4
- handler: () => ({ ok: true }),
5
- })
@@ -1,3 +0,0 @@
1
- import { defineConfig } from 'theokit'
2
-
3
- export default defineConfig({})
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "noEmit": true,
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "jsx": "react-jsx",
11
- "isolatedModules": true,
12
- "resolveJsonModule": true
13
- },
14
- "include": ["app/**/*.ts", "app/**/*.tsx", "server/**/*.ts"]
15
- }
@@ -1 +0,0 @@
1
- 22.12
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Theo App</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/@theo/entry-client"></script>
11
- </body>
12
- </html>
File without changes
@@ -1,59 +0,0 @@
1
- import { defineCron } from 'theokit/server/cron'
2
- import { readdir, stat, rm } from 'node:fs/promises'
3
- import type { Dirent } from 'node:fs'
4
- import { join, resolve } from 'node:path'
5
-
6
- /**
7
- * Daily GC of stale conversation transcripts.
8
- *
9
- * The `@theokit/sdk` Agent persists chat history under
10
- * `.theokit/agents/<agentId>/messages.jsonl`. With no TTL the directory
11
- * grows unbounded — production foot-gun. This cron removes any agent
12
- * directory whose `messages.jsonl` hasn't been touched in 30 days.
13
- */
14
- const MAX_AGE_DAYS = 30
15
- const AGENTS_DIR = '.theokit/agents'
16
-
17
- export default defineCron('cleanup-conversations', {
18
- schedule: '0 4 * * *', // Daily 04:00 UTC
19
- handler: async ({ traceId }) => {
20
- const root = resolve(process.cwd(), AGENTS_DIR)
21
- const cutoff = Date.now() - MAX_AGE_DAYS * 24 * 60 * 60 * 1000
22
- let removed = 0
23
- let kept = 0
24
- let entries: Dirent[]
25
- try {
26
- entries = (await readdir(root, { withFileTypes: true })) as unknown as Dirent[]
27
- } catch {
28
- console.info(JSON.stringify({ msg: 'No agents dir yet — first run', dir: root, traceId }))
29
- return
30
- }
31
- for (const entry of entries) {
32
- if (!entry.isDirectory()) continue
33
- const agentDir = join(root, String(entry.name))
34
- const messagesFile = join(agentDir, 'messages.jsonl')
35
- try {
36
- const s = await stat(messagesFile)
37
- if (s.mtimeMs < cutoff) {
38
- await rm(agentDir, { recursive: true, force: true })
39
- removed++
40
- } else {
41
- kept++
42
- }
43
- } catch {
44
- // messages.jsonl missing → orphan dir, remove
45
- await rm(agentDir, { recursive: true, force: true }).catch(() => {})
46
- removed++
47
- }
48
- }
49
- console.info(
50
- JSON.stringify({
51
- msg: 'cleanup-conversations complete',
52
- removed,
53
- kept,
54
- maxAgeDays: MAX_AGE_DAYS,
55
- traceId,
56
- }),
57
- )
58
- },
59
- })
@@ -1,69 +0,0 @@
1
- import { z } from 'zod'
2
- import {
3
- defineAgentEndpoint,
4
- defineAgentTool,
5
- streamAgentRun,
6
- createConversationHistory,
7
- type AgentEvent,
8
- } from 'theokit/server'
9
-
10
- /**
11
- * Chat agent endpoint — persistent conversation via createConversationHistory.
12
- *
13
- * Each browser tab gets a stable conversation id cookie on first visit;
14
- * subsequent requests resume the same agent. Conversation turns auto-persist
15
- * in `<cwd>/.theokit/agents/<conversationId>/messages.jsonl` (SDK owns
16
- * storage). Tools: current_time example. Memory facts: opt-in via
17
- * options.memory (off by default).
18
- *
19
- * Provider: OPENROUTER_API_KEY (preferred — gateway to many models) OR
20
- * ANTHROPIC_API_KEY (direct Anthropic).
21
- */
22
-
23
- const currentTime = defineAgentTool({
24
- name: 'current_time',
25
- description: 'Get the current ISO timestamp on the server.',
26
- inputSchema: z.object({}),
27
- handler: () => new Date().toISOString(),
28
- })
29
-
30
- export const POST = defineAgentEndpoint({
31
- async *handler({ body, request, cookieHeaders, signal }): AsyncGenerator<AgentEvent> {
32
- const safeBody =
33
- body !== null && typeof body === 'object' && !Array.isArray(body)
34
- ? (body as { message?: string })
35
- : {}
36
- const { message = '' } = safeBody
37
- // Provider resolution centralizada (Strategy pattern) — theokit/server resolve
38
- // apiKey + baseUrl + provider automático via OPENROUTER_API_KEY / OPENAI_API_KEY /
39
- // ANTHROPIC_API_KEY presente no env. Wire protocol: OpenAI Chat Completions
40
- // (universal — todos os providers implementam essa API). Consumer NÃO tem
41
- // conditionals sobre provider — é responsabilidade do framework.
42
- // Wrap full agent lifecycle in try/catch — provider errors (invalid KEY,
43
- // 401, rate-limit, model-not-found, 5xx) MUST surface as AgentEvent
44
- // 'error' so the client renders an actionable message instead of a
45
- // silent SSE closure. Dogfood chaos Phase 12 validates this contract.
46
- try {
47
- const { agent } = await createConversationHistory({
48
- request,
49
- response: { headers: cookieHeaders },
50
- options: {
51
- // Model id is prefixed with the provider namespace. When using
52
- // OPENROUTER_API_KEY (default), prefixes route to the correct
53
- // upstream — `openai/`, `anthropic/`, `google/`, `meta-llama/`,
54
- // `mistralai/`, `groq/`, etc. See https://openrouter.ai/models.
55
- // Without the prefix the SDK falls back to a stub response.
56
- model: { id: 'openai/gpt-4o-mini' },
57
- tools: [currentTime],
58
- },
59
- })
60
- const run = await agent.send(message, { signal })
61
- yield* streamAgentRun(run)
62
- // Intentionally NO agent.dispose() — the agent stays registered so the
63
- // next request from the same conversation resumes it (continuity).
64
- } catch (err) {
65
- const msg = err instanceof Error ? err.message : String(err)
66
- yield { type: 'error', message: `Agent error: ${msg}` }
67
- }
68
- },
69
- })
@@ -1,5 +0,0 @@
1
- import { defineRoute } from 'theokit/server'
2
-
3
- export const GET = defineRoute({
4
- handler: () => ({ ok: true }),
5
- })
@@ -1,3 +0,0 @@
1
- import { defineConfig } from 'theokit'
2
-
3
- export default defineConfig({})
@@ -1,25 +0,0 @@
1
- /**
2
- * JobRegistry augmentation — REQUIRED for typed `ctx.queue.enqueue` calls.
3
- *
4
- * Without this augmentation, `ctx.queue.enqueue('foo', ...)` errors with:
5
- * "Type 'foo' is not assignable to type 'never'"
6
- *
7
- * This is the canonical TheoKit jobs onboarding bug (EC-110). To add a
8
- * job:
9
- *
10
- * 1. Create `server/jobs/<name>.ts` exporting `defineJob('<name>', ...)`
11
- * 2. Add `'<name>': { ...inputShape }` below
12
- * 3. Use `ctx.queue.enqueue('<name>', { ...input })` from any route handler
13
- *
14
- * See: docs/concepts/jobs.md
15
- */
16
- declare module 'theokit/server' {
17
- interface JobRegistry {
18
- // Add your jobs here. Examples (uncomment and customize):
19
- //
20
- // 'process-document': { documentId: string }
21
- // 'send-email': { to: string; subject: string; body: string }
22
- }
23
- }
24
-
25
- export {}
@@ -1,5 +0,0 @@
1
- # Database connection string
2
- DATABASE_URL=postgresql://user:password@localhost:5432/mydb
3
-
4
- # Session secret (min 32 characters)
5
- # SESSION_SECRET=change-me-to-a-random-string-at-least-32-chars
@@ -1 +0,0 @@
1
- 22.12
@@ -1,83 +0,0 @@
1
- # {{name}}
2
-
3
- TheoKit project with Postgres + Drizzle ORM wired. Schema-first, migration-aware, typed end-to-end.
4
-
5
- > 📚 **Full docs:** https://docs.theokit.dev
6
-
7
- ## Quick start
8
-
9
- ```bash
10
- # 0. Provision Postgres
11
- # Option A — local docker (one-liner):
12
- docker run --name pg -e POSTGRES_PASSWORD=dev -p 5432:5432 -d postgres:16
13
- # Option B — hosted: neon.tech, supabase.com, fly.io
14
-
15
- # 1. Set env
16
- cat > .env <<'EOF'
17
- DATABASE_URL=postgres://postgres:dev@localhost:5432/postgres
18
- OPENROUTER_API_KEY=sk-or-v1-...
19
- EOF
20
-
21
- # 2. Generate + apply migrations
22
- pnpm db:generate
23
- pnpm db:migrate
24
-
25
- # 3. Boot the dev server
26
- npx theokit dev
27
- ```
28
-
29
- Open the printed URL. The default surface includes a sample users API backed by Postgres.
30
-
31
- ## Templates
32
-
33
- - **default** — TheoUI chat composer + agent route.
34
- - **dashboard** — nested layouts + sidebar.
35
- - **api-only** — server routes without React.
36
- - **postgres** (this one) — Drizzle ORM + migrations.
37
- - **saas** — full app with auth, billing, sessions.
38
-
39
- ## What the framework auto-loads
40
-
41
- - **`.env` → `process.env`**. `DATABASE_URL` must be set before `pnpm db:migrate`.
42
- - **`.theo/` build output cleanup** on every `theokit build`.
43
- - **Drizzle schema** under `db/schema.ts` drives migrations + typed query builder.
44
-
45
- ## Project structure
46
-
47
- ```
48
- app/ Frontend
49
- ├── page.tsx / — sample UI
50
- server/
51
- ├── routes/
52
- │ ├── health.ts GET /api/health
53
- │ └── users.ts CRUD /api/users — backed by db.users
54
- db/
55
- ├── schema.ts Drizzle schema (tables + relations)
56
- ├── client.ts Drizzle client (used by routes)
57
- └── migrations/ Generated SQL files (committed)
58
- drizzle.config.ts Drizzle CLI config
59
- theo.config.ts Framework config
60
- .env Secrets — never committed
61
- ```
62
-
63
- ## Common commands
64
-
65
- | Command | What it does |
66
- |---|---|
67
- | `npx theokit dev` | Dev server with HMR |
68
- | `npx theokit build` | Production build |
69
- | `npx theokit start` | Serve production build |
70
- | `pnpm db:generate` | Generate SQL migration from `db/schema.ts` |
71
- | `pnpm db:migrate` | Apply pending migrations to `DATABASE_URL` |
72
- | `pnpm db:studio` | Open Drizzle Studio UI |
73
- | `npm run typecheck` | TypeScript strict check |
74
-
75
- ## Troubleshooting
76
-
77
- - **`pnpm db:migrate` fails with "ECONNREFUSED"** → check `DATABASE_URL` host:port + Postgres is running (`docker ps` or hosted dashboard).
78
- - **`relation "users" does not exist`** → you forgot `pnpm db:migrate`. Run it.
79
- - **Schema change not reflected** → `pnpm db:generate` first, then `pnpm db:migrate`.
80
-
81
- ## License
82
-
83
- Apply your own. The TheoKit framework is Apache-2.0.
@@ -1,5 +0,0 @@
1
- node_modules
2
- .theo
3
- dist
4
- .env
5
- .env.local
@@ -1,14 +0,0 @@
1
- import { Outlet } from 'react-router'
2
-
3
- export default function RootLayout() {
4
- return (
5
- <div>
6
- <nav>
7
- <a href="/">Home</a>
8
- </nav>
9
- <main>
10
- <Outlet />
11
- </main>
12
- </div>
13
- )
14
- }
@@ -1,8 +0,0 @@
1
- export default function Page() {
2
- return (
3
- <div>
4
- <h1>Theo + Postgres</h1>
5
- <p>Full-stack TypeScript with Drizzle ORM</p>
6
- </div>
7
- )
8
- }
@@ -1,7 +0,0 @@
1
- import { drizzle } from 'drizzle-orm/postgres-js'
2
- import postgres from 'postgres'
3
- import * as schema from './schema.js'
4
-
5
- const client = postgres(process.env.DATABASE_URL!)
6
-
7
- export const db = drizzle(client, { schema })
@@ -1,8 +0,0 @@
1
- import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
2
-
3
- export const users = pgTable('users', {
4
- id: uuid('id').primaryKey().defaultRandom(),
5
- name: text('name').notNull(),
6
- email: text('email').notNull().unique(),
7
- createdAt: timestamp('created_at').defaultNow().notNull(),
8
- })