luca 3.0.0 → 3.0.2
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.
- package/.github/workflows/release.yaml +1 -0
- package/CLAUDE.md +10 -2
- package/README.md +130 -112
- package/assistants/codingAssistant/CORE.md +6 -1
- package/assistants/codingAssistant/hooks.ts +1 -1
- package/assistants/inkbot/hooks.ts +1 -1
- package/assistants/inkbot/tools.ts +1 -1
- package/bun.lock +220 -322
- package/commands/audit-docs.ts +2 -2
- package/commands/build-bootstrap.ts +2 -3
- package/commands/build-python-bridge.ts +2 -3
- package/commands/build-scaffolds.ts +2 -3
- package/commands/bundle-consumer-project.ts +521 -0
- package/commands/generate-api-docs.ts +2 -2
- package/commands/inkbot.ts +2 -2
- package/commands/release.ts +2 -2
- package/commands/try-all-challenges.ts +3 -3
- package/commands/try-challenge.ts +3 -3
- package/dist/agi/container.server.d.ts +2 -2
- package/dist/agi/features/assistant.d.ts +2 -2
- package/dist/agi/features/assistants-manager.d.ts +1 -1
- package/dist/agi/features/autonomous-assistant.d.ts +1 -1
- package/dist/agi/features/browser-use.d.ts +1 -1
- package/dist/agi/features/claude-code.d.ts +1 -1
- package/dist/agi/features/conversation-history.d.ts +2 -2
- package/dist/agi/features/conversation.d.ts +1 -1
- package/dist/agi/features/docs-reader.d.ts +1 -1
- package/dist/agi/features/file-tools.d.ts +1 -1
- package/dist/agi/features/luca-coder.d.ts +1 -1
- package/dist/agi/features/openai-codex.d.ts +1 -1
- package/dist/agi/features/skills-library.d.ts +1 -1
- package/dist/clients/civitai/index.d.ts +4 -4
- package/dist/clients/client-template.d.ts +4 -4
- package/dist/clients/comfyui/index.d.ts +2 -2
- package/dist/clients/elevenlabs/index.d.ts +2 -2
- package/dist/clients/openai/index.d.ts +2 -2
- package/dist/clients/supabase/index.d.ts +3 -3
- package/dist/command.d.ts +1 -1
- package/dist/node/container.d.ts +1 -1
- package/dist/node/features/helpers.d.ts +3 -3
- package/dist/node/features/semantic-search.d.ts +1 -1
- package/dist/node/features/vm.d.ts +3 -3
- package/dist/node.d.ts +1 -1
- package/dist/scaffolds/generated.d.ts +1 -1
- package/dist/selector.d.ts +1 -1
- package/index.html +217 -190
- package/luca.console.ts +1 -1
- package/package.json +2 -2
- package/public/index.html +217 -190
- package/public/slides-ai-native.html +1 -1
- package/public/slides-intro.html +2 -2
- package/scripts/examples/ask-luca-expert.ts +1 -1
- package/scripts/examples/assistant-questions.ts +1 -1
- package/scripts/examples/excalidraw-expert.ts +1 -1
- package/scripts/examples/file-manager.ts +1 -1
- package/scripts/examples/ideas.ts +1 -1
- package/scripts/examples/interactive-chat.ts +1 -1
- package/scripts/examples/opening-a-web-browser.ts +1 -1
- package/scripts/examples/telegram-bot.ts +1 -1
- package/scripts/examples/using-assistant-with-mcp.ts +1 -1
- package/scripts/examples/using-claude-code.ts +1 -1
- package/scripts/examples/using-contentdb.ts +2 -2
- package/scripts/examples/using-conversations.ts +1 -1
- package/scripts/examples/using-disk-cache.ts +1 -1
- package/scripts/examples/using-docker-shell.ts +1 -1
- package/scripts/examples/using-elevenlabs.ts +1 -1
- package/scripts/examples/using-google-calendar.ts +1 -1
- package/scripts/examples/using-google-docs.ts +1 -1
- package/scripts/examples/using-google-drive.ts +1 -1
- package/scripts/examples/using-google-sheets.ts +1 -1
- package/scripts/examples/using-nlp.ts +1 -1
- package/scripts/examples/using-ollama.ts +1 -1
- package/scripts/examples/using-postgres.ts +1 -1
- package/scripts/examples/using-runpod.ts +1 -1
- package/scripts/examples/using-tts.ts +1 -1
- package/scripts/scaffold.ts +5 -5
- package/scripts/scratch.ts +1 -1
- package/scripts/test-assistant-hooks.ts +1 -1
- package/scripts/test-docs-reader.ts +1 -1
- package/src/agi/container.server.ts +6 -2
- package/src/agi/features/agent-memory.ts +25 -25
- package/src/agi/features/assistant.ts +34 -5
- package/src/agi/features/assistants-manager.ts +122 -6
- package/src/agi/features/autonomous-assistant.ts +1 -1
- package/src/agi/features/browser-use.ts +20 -1
- package/src/agi/features/claude-code.ts +51 -5
- package/src/agi/features/coding-tools.ts +1 -1
- package/src/agi/features/conversation-history.ts +181 -4
- package/src/agi/features/conversation.ts +186 -15
- package/src/agi/features/docs-reader.ts +2 -2
- package/src/agi/features/file-tools.ts +49 -2
- package/src/agi/features/luca-coder.ts +7 -5
- package/src/agi/features/mcp-bridge.ts +532 -0
- package/src/agi/features/openai-codex.ts +2 -2
- package/src/agi/features/skills-library.ts +131 -52
- package/src/agi/lib/token-counter.ts +80 -0
- package/src/bootstrap/generated.ts +56 -57
- package/src/browser.ts +1 -1
- package/src/cli/build-info.ts +2 -2
- package/src/cli/cli.ts +2 -2
- package/src/clients/civitai/index.ts +5 -5
- package/src/clients/client-template.ts +4 -4
- package/src/clients/comfyui/index.ts +4 -4
- package/src/clients/elevenlabs/index.ts +4 -4
- package/src/clients/openai/index.ts +7 -7
- package/src/clients/supabase/index.ts +4 -4
- package/src/clients/voicebox/index.ts +4 -4
- package/src/command.ts +2 -1
- package/src/commands/chat.ts +1 -0
- package/src/commands/eval.ts +2 -56
- package/src/commands/introspect.ts +1 -1
- package/src/commands/prompt.ts +41 -9
- package/src/container-describer.ts +8 -1
- package/src/container.ts +13 -0
- package/src/entity.ts +2 -2
- package/src/helper.ts +1 -1
- package/src/introspection/generated.agi.ts +28563 -27571
- package/src/introspection/generated.node.ts +20281 -20194
- package/src/introspection/generated.web.ts +605 -584
- package/src/introspection/scan.ts +11 -6
- package/src/node/container.ts +1 -1
- package/src/node/features/content-db.ts +39 -2
- package/src/node/features/display-result.ts +57 -0
- package/src/node/features/helpers.ts +42 -15
- package/src/node/features/python.ts +25 -19
- package/src/node/features/repl.ts +1 -1
- package/src/node/features/secure-shell.ts +11 -17
- package/src/node/features/semantic-search.ts +2 -2
- package/src/node/features/transpiler.ts +2 -3
- package/src/node/features/ui.ts +5 -0
- package/src/node/features/vm.ts +3 -3
- package/src/node.ts +3 -3
- package/src/python/generated.ts +0 -1
- package/src/scaffolds/generated.ts +82 -83
- package/src/selector.ts +1 -1
- package/src/servers/express.ts +1 -1
- package/src/web/features/helpers.ts +22 -0
- package/tsconfig.json +12 -12
- package/docs/CLI.md +0 -335
- package/docs/CNAME +0 -1
- package/docs/README.md +0 -60
- package/docs/TABLE-OF-CONTENTS.md +0 -183
- package/docs/apis/clients/elevenlabs.md +0 -308
- package/docs/apis/clients/graph.md +0 -107
- package/docs/apis/clients/openai.md +0 -429
- package/docs/apis/clients/rest.md +0 -161
- package/docs/apis/clients/websocket.md +0 -174
- package/docs/apis/features/agi/assistant.md +0 -625
- package/docs/apis/features/agi/assistants-manager.md +0 -282
- package/docs/apis/features/agi/auto-assistant.md +0 -279
- package/docs/apis/features/agi/browser-use.md +0 -802
- package/docs/apis/features/agi/claude-code.md +0 -884
- package/docs/apis/features/agi/conversation-history.md +0 -364
- package/docs/apis/features/agi/conversation.md +0 -548
- package/docs/apis/features/agi/docs-reader.md +0 -99
- package/docs/apis/features/agi/file-tools.md +0 -163
- package/docs/apis/features/agi/luca-coder.md +0 -407
- package/docs/apis/features/agi/openai-codex.md +0 -396
- package/docs/apis/features/agi/openapi.md +0 -138
- package/docs/apis/features/agi/semantic-search.md +0 -387
- package/docs/apis/features/agi/skills-library.md +0 -239
- package/docs/apis/features/node/container-link.md +0 -192
- package/docs/apis/features/node/content-db.md +0 -450
- package/docs/apis/features/node/disk-cache.md +0 -379
- package/docs/apis/features/node/dns.md +0 -652
- package/docs/apis/features/node/docker.md +0 -706
- package/docs/apis/features/node/downloader.md +0 -81
- package/docs/apis/features/node/esbuild.md +0 -60
- package/docs/apis/features/node/file-manager.md +0 -191
- package/docs/apis/features/node/fs.md +0 -1217
- package/docs/apis/features/node/git.md +0 -371
- package/docs/apis/features/node/google-auth.md +0 -193
- package/docs/apis/features/node/google-calendar.md +0 -202
- package/docs/apis/features/node/google-docs.md +0 -173
- package/docs/apis/features/node/google-drive.md +0 -246
- package/docs/apis/features/node/google-mail.md +0 -214
- package/docs/apis/features/node/google-sheets.md +0 -194
- package/docs/apis/features/node/grep.md +0 -292
- package/docs/apis/features/node/helpers.md +0 -164
- package/docs/apis/features/node/ink.md +0 -334
- package/docs/apis/features/node/ipc-socket.md +0 -249
- package/docs/apis/features/node/json-tree.md +0 -86
- package/docs/apis/features/node/networking.md +0 -316
- package/docs/apis/features/node/nlp.md +0 -133
- package/docs/apis/features/node/opener.md +0 -97
- package/docs/apis/features/node/os.md +0 -146
- package/docs/apis/features/node/package-finder.md +0 -392
- package/docs/apis/features/node/postgres.md +0 -234
- package/docs/apis/features/node/proc.md +0 -399
- package/docs/apis/features/node/process-manager.md +0 -305
- package/docs/apis/features/node/python.md +0 -604
- package/docs/apis/features/node/redis.md +0 -380
- package/docs/apis/features/node/repl.md +0 -88
- package/docs/apis/features/node/runpod.md +0 -674
- package/docs/apis/features/node/secure-shell.md +0 -176
- package/docs/apis/features/node/semantic-search.md +0 -408
- package/docs/apis/features/node/sqlite.md +0 -233
- package/docs/apis/features/node/telegram.md +0 -279
- package/docs/apis/features/node/transpiler.md +0 -74
- package/docs/apis/features/node/tts.md +0 -133
- package/docs/apis/features/node/ui.md +0 -701
- package/docs/apis/features/node/vault.md +0 -59
- package/docs/apis/features/node/vm.md +0 -75
- package/docs/apis/features/node/yaml-tree.md +0 -85
- package/docs/apis/features/node/yaml.md +0 -176
- package/docs/apis/features/web/asset-loader.md +0 -59
- package/docs/apis/features/web/container-link.md +0 -192
- package/docs/apis/features/web/esbuild.md +0 -54
- package/docs/apis/features/web/helpers.md +0 -164
- package/docs/apis/features/web/network.md +0 -44
- package/docs/apis/features/web/speech.md +0 -69
- package/docs/apis/features/web/vault.md +0 -59
- package/docs/apis/features/web/vm.md +0 -75
- package/docs/apis/features/web/voice.md +0 -84
- package/docs/apis/servers/express.md +0 -171
- package/docs/apis/servers/mcp.md +0 -238
- package/docs/apis/servers/websocket.md +0 -170
- package/docs/bootstrap/CLAUDE.md +0 -101
- package/docs/bootstrap/SKILL.md +0 -341
- package/docs/bootstrap/templates/about-command.ts +0 -41
- package/docs/bootstrap/templates/docs-models.ts +0 -22
- package/docs/bootstrap/templates/docs-readme.md +0 -43
- package/docs/bootstrap/templates/example-feature.ts +0 -53
- package/docs/bootstrap/templates/health-endpoint.ts +0 -15
- package/docs/bootstrap/templates/luca-cli.ts +0 -30
- package/docs/bootstrap/templates/runme.md +0 -54
- package/docs/challenges/caching-proxy.md +0 -16
- package/docs/challenges/content-db-round-trip.md +0 -14
- package/docs/challenges/custom-command.md +0 -9
- package/docs/challenges/file-watcher-pipeline.md +0 -11
- package/docs/challenges/grep-audit-report.md +0 -15
- package/docs/challenges/multi-feature-dashboard.md +0 -14
- package/docs/challenges/process-orchestrator.md +0 -17
- package/docs/challenges/rest-api-server-with-client.md +0 -12
- package/docs/challenges/script-runner-with-vm.md +0 -11
- package/docs/challenges/simple-rest-api.md +0 -15
- package/docs/challenges/websocket-serve-and-client.md +0 -11
- package/docs/challenges/yaml-config-system.md +0 -14
- package/docs/command-system-overhaul.md +0 -94
- package/docs/documentation-audit.md +0 -134
- package/docs/examples/assistant/CORE.md +0 -18
- package/docs/examples/assistant/hooks.ts +0 -3
- package/docs/examples/assistant/tools.ts +0 -10
- package/docs/examples/assistant-hooks-reference.ts +0 -171
- package/docs/examples/assistant-with-process-manager.md +0 -84
- package/docs/examples/content-db.md +0 -77
- package/docs/examples/disk-cache.md +0 -83
- package/docs/examples/docker.md +0 -101
- package/docs/examples/downloader.md +0 -70
- package/docs/examples/entity.md +0 -124
- package/docs/examples/esbuild.md +0 -80
- package/docs/examples/feature-as-tool-provider.md +0 -143
- package/docs/examples/file-manager.md +0 -82
- package/docs/examples/fs.md +0 -83
- package/docs/examples/git.md +0 -85
- package/docs/examples/google-auth.md +0 -88
- package/docs/examples/google-calendar.md +0 -94
- package/docs/examples/google-docs.md +0 -82
- package/docs/examples/google-drive.md +0 -96
- package/docs/examples/google-sheets.md +0 -95
- package/docs/examples/grep.md +0 -85
- package/docs/examples/ink-blocks.md +0 -75
- package/docs/examples/ink-renderer.md +0 -41
- package/docs/examples/ink.md +0 -103
- package/docs/examples/ipc-socket.md +0 -103
- package/docs/examples/json-tree.md +0 -91
- package/docs/examples/networking.md +0 -58
- package/docs/examples/nlp.md +0 -91
- package/docs/examples/opener.md +0 -78
- package/docs/examples/os.md +0 -72
- package/docs/examples/package-finder.md +0 -89
- package/docs/examples/postgres.md +0 -91
- package/docs/examples/proc.md +0 -81
- package/docs/examples/process-manager.md +0 -79
- package/docs/examples/python.md +0 -132
- package/docs/examples/repl.md +0 -93
- package/docs/examples/runpod.md +0 -119
- package/docs/examples/secure-shell.md +0 -92
- package/docs/examples/sqlite.md +0 -86
- package/docs/examples/structured-output-with-assistants.md +0 -144
- package/docs/examples/telegram.md +0 -77
- package/docs/examples/tts.md +0 -86
- package/docs/examples/ui.md +0 -80
- package/docs/examples/vault.md +0 -70
- package/docs/examples/vm.md +0 -86
- package/docs/examples/websocket-ask-and-reply-example.md +0 -128
- package/docs/examples/yaml-tree.md +0 -93
- package/docs/examples/yaml.md +0 -104
- package/docs/ideas/assistant-factory-pattern.md +0 -142
- package/docs/in-memory-fs.md +0 -4
- package/docs/introspection-audit.md +0 -49
- package/docs/introspection.md +0 -164
- package/docs/mcp/readme.md +0 -162
- package/docs/models.ts +0 -41
- package/docs/philosophy.md +0 -86
- package/docs/principles.md +0 -7
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
- package/docs/prompts/check-for-undocumented-features.md +0 -27
- package/docs/prompts/mcp-test-easy-command.md +0 -27
- package/docs/scaffolds/client.md +0 -149
- package/docs/scaffolds/command.md +0 -120
- package/docs/scaffolds/endpoint.md +0 -171
- package/docs/scaffolds/feature.md +0 -158
- package/docs/scaffolds/selector.md +0 -91
- package/docs/scaffolds/server.md +0 -196
- package/docs/selectors.md +0 -115
- package/docs/sessions/custom-command/attempt-log-2.md +0 -195
- package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
- package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
- package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
- package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
- package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
- package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
- package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
- package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
- package/docs/tutorials/00-bootstrap.md +0 -166
- package/docs/tutorials/01-getting-started.md +0 -106
- package/docs/tutorials/02-container.md +0 -210
- package/docs/tutorials/03-scripts.md +0 -194
- package/docs/tutorials/04-features-overview.md +0 -196
- package/docs/tutorials/05-state-and-events.md +0 -171
- package/docs/tutorials/06-servers.md +0 -157
- package/docs/tutorials/07-endpoints.md +0 -198
- package/docs/tutorials/08-commands.md +0 -252
- package/docs/tutorials/09-clients.md +0 -162
- package/docs/tutorials/10-creating-features.md +0 -203
- package/docs/tutorials/11-contentbase.md +0 -191
- package/docs/tutorials/12-assistants.md +0 -215
- package/docs/tutorials/13-introspection.md +0 -157
- package/docs/tutorials/14-type-system.md +0 -174
- package/docs/tutorials/15-project-patterns.md +0 -222
- package/docs/tutorials/16-google-features.md +0 -534
- package/docs/tutorials/17-tui-blocks.md +0 -530
- package/docs/tutorials/18-semantic-search.md +0 -334
- package/docs/tutorials/19-python-sessions.md +0 -401
- package/docs/tutorials/20-browser-esm.md +0 -234
- package/src/agi/endpoints/ask.ts +0 -60
- package/src/agi/endpoints/conversations/[id].ts +0 -45
- package/src/agi/endpoints/conversations.ts +0 -31
- package/src/agi/endpoints/experts.ts +0 -37
- package/test/assistant-hooks.test.ts +0 -306
- package/test/assistant.test.ts +0 -81
- package/test/bus.test.ts +0 -134
- package/test/clients-servers.test.ts +0 -217
- package/test/command.test.ts +0 -267
- package/test/container-link.test.ts +0 -274
- package/test/conversation.test.ts +0 -220
- package/test/features.test.ts +0 -160
- package/test/fork-and-research.test.ts +0 -450
- package/test/integration.test.ts +0 -787
- package/test/interceptor-chain.test.ts +0 -61
- package/test/node-container.test.ts +0 -121
- package/test/python-session.test.ts +0 -105
- package/test/rate-limit.test.ts +0 -272
- package/test/semantic-search.test.ts +0 -550
- package/test/state.test.ts +0 -121
- package/test/vm-context.test.ts +0 -146
- package/test/vm-loadmodule.test.ts +0 -213
- package/test/websocket-ask.test.ts +0 -101
- package/test-integration/assistant.test.ts +0 -138
- package/test-integration/assistants-manager.test.ts +0 -113
- package/test-integration/claude-code.test.ts +0 -98
- package/test-integration/conversation-history.test.ts +0 -205
- package/test-integration/conversation.test.ts +0 -137
- package/test-integration/elevenlabs.test.ts +0 -55
- package/test-integration/google-services.test.ts +0 -80
- package/test-integration/helpers.ts +0 -89
- package/test-integration/memory.test.ts +0 -204
- package/test-integration/openai-codex.test.ts +0 -93
- package/test-integration/runpod.test.ts +0 -58
- package/test-integration/server-endpoints.test.ts +0 -97
- package/test-integration/telegram.test.ts +0 -46
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Features Overview
|
|
3
|
-
tags: [features, built-in, fs, git, proc, vm, ui, networking, os, diskCache]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Features Overview
|
|
7
|
-
|
|
8
|
-
Features are the core building blocks in Luca. A feature is a thing that emits events, has observable state, and provides an interface for doing something meaningful. The container comes with many built-in features.
|
|
9
|
-
|
|
10
|
-
## Using Features
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
// Auto-enabled features have shortcuts
|
|
14
|
-
container.fs // File system
|
|
15
|
-
container.git // Git operations
|
|
16
|
-
container.proc // Process execution
|
|
17
|
-
container.vm // JavaScript VM
|
|
18
|
-
container.ui // Terminal UI
|
|
19
|
-
container.os // OS info
|
|
20
|
-
container.networking // Port utilities
|
|
21
|
-
|
|
22
|
-
// On-demand features are created through the factory
|
|
23
|
-
const cache = container.feature('diskCache', { path: './.cache' })
|
|
24
|
-
const db = container.feature('contentDb', { rootPath: './docs' })
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Built-In Feature Reference
|
|
28
|
-
|
|
29
|
-
### fs -- File System
|
|
30
|
-
|
|
31
|
-
Read, write, and navigate the file system:
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
const fs = container.fs
|
|
35
|
-
|
|
36
|
-
// Read files (synchronous)
|
|
37
|
-
const content = fs.readFile('./README.md')
|
|
38
|
-
const json = fs.readJson('./package.json')
|
|
39
|
-
|
|
40
|
-
// Write files (async -- creates parent dirs automatically)
|
|
41
|
-
await fs.writeFile('./output.txt', 'Hello')
|
|
42
|
-
|
|
43
|
-
// Check existence
|
|
44
|
-
fs.exists('./path/to/file')
|
|
45
|
-
|
|
46
|
-
// Walk directories -- returns { files: string[], directories: string[] }
|
|
47
|
-
const { files } = fs.walk('./src', { include: ['*.ts'] })
|
|
48
|
-
|
|
49
|
-
// Find files upward (synchronous)
|
|
50
|
-
const configPath = fs.findUp('tsconfig.json')
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### git -- Git Operations
|
|
54
|
-
|
|
55
|
-
Work with git repositories:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
const git = container.git
|
|
59
|
-
|
|
60
|
-
const branch = git.branch // Current branch name (getter)
|
|
61
|
-
const sha = git.sha // Current commit SHA (getter)
|
|
62
|
-
const isRepo = git.isRepo // Whether cwd is a git repo (getter)
|
|
63
|
-
const root = git.repoRoot // Absolute path to repo root (getter)
|
|
64
|
-
const files = await git.lsFiles() // List tracked files
|
|
65
|
-
const recent = await git.getLatestChanges(5) // Recent commits
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### proc -- Process Execution
|
|
69
|
-
|
|
70
|
-
Run external processes:
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
const proc = container.proc
|
|
74
|
-
|
|
75
|
-
// Execute a command synchronously and get output as a string
|
|
76
|
-
const result = proc.exec('ls -la')
|
|
77
|
-
|
|
78
|
-
// Execute with options
|
|
79
|
-
const output = proc.exec('npm test', {
|
|
80
|
-
cwd: '/path/to/project',
|
|
81
|
-
env: { NODE_ENV: 'test' },
|
|
82
|
-
})
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### vm -- JavaScript VM
|
|
86
|
-
|
|
87
|
-
Execute JavaScript in an isolated context:
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
const vm = container.vm
|
|
91
|
-
|
|
92
|
-
const result = await vm.run('1 + 2 + 3') // 6
|
|
93
|
-
|
|
94
|
-
const greeting = await vm.run('`Hello ${name}!`', { name: 'World' })
|
|
95
|
-
// 'Hello World!'
|
|
96
|
-
|
|
97
|
-
// The VM has access to the container context by default
|
|
98
|
-
const files = await vm.run('container.fs.walk("./src")')
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### ui -- Terminal UI
|
|
102
|
-
|
|
103
|
-
Colors, prompts, and formatted output:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const ui = container.ui
|
|
107
|
-
|
|
108
|
-
// Colors
|
|
109
|
-
ui.colors.green('Success!')
|
|
110
|
-
ui.colors.red('Error!')
|
|
111
|
-
ui.colors.yellow('Warning!')
|
|
112
|
-
|
|
113
|
-
// ASCII art
|
|
114
|
-
console.log(ui.asciiArt('My App', 'Standard'))
|
|
115
|
-
|
|
116
|
-
// Colorful ASCII banner with gradient
|
|
117
|
-
console.log(ui.banner('My App', { font: 'Star Wars', colors: ['red', 'white', 'blue'] }))
|
|
118
|
-
|
|
119
|
-
// Render markdown in the terminal
|
|
120
|
-
ui.markdown('# Hello\n\nThis is **bold**')
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### networking -- Port Utilities
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
const net = container.networking
|
|
127
|
-
|
|
128
|
-
// Find an available port (starting from a preferred port)
|
|
129
|
-
const port = await net.findOpenPort(3000)
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### os -- System Info
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const os = container.os
|
|
136
|
-
|
|
137
|
-
os.platform // 'darwin', 'linux', 'win32'
|
|
138
|
-
os.arch // 'x64', 'arm64'
|
|
139
|
-
os.cpuCount // Number of CPU cores
|
|
140
|
-
os.tmpdir // Temp directory path
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### diskCache -- Disk-Based Cache
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
const cache = container.feature('diskCache', { path: './.cache' })
|
|
147
|
-
|
|
148
|
-
await cache.set('key', { data: 'value' })
|
|
149
|
-
const data = await cache.get('key')
|
|
150
|
-
await cache.has('key') // true
|
|
151
|
-
await cache.rm('key') // remove a cached item
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### contentDb -- Markdown as a Database
|
|
155
|
-
|
|
156
|
-
Turn markdown folders into queryable collections. See the dedicated [ContentBase tutorial](./11-contentbase.md).
|
|
157
|
-
|
|
158
|
-
### fileManager -- Batch File Operations
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
const fm = container.feature('fileManager')
|
|
162
|
-
// Batch read, write, copy, move operations
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### grep -- Search File Contents
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
const grep = container.grep
|
|
169
|
-
const results = await grep.search({ pattern: 'TODO', include: '*.ts' })
|
|
170
|
-
// Returns array of { file, line, column, match } objects
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### docker -- Docker Operations
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
const docker = container.feature('docker')
|
|
177
|
-
// Build, run, manage containers
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Discovering Features
|
|
181
|
-
|
|
182
|
-
Don't memorize this list. You can always discover what's available at runtime:
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
// List all registered features
|
|
186
|
-
container.features.available
|
|
187
|
-
|
|
188
|
-
// Get documentation for any feature
|
|
189
|
-
container.features.describe('diskCache')
|
|
190
|
-
|
|
191
|
-
// Get docs for everything
|
|
192
|
-
container.features.describeAll()
|
|
193
|
-
|
|
194
|
-
// Structured introspection data for a feature's full API
|
|
195
|
-
container.feature('fs').introspect()
|
|
196
|
-
```
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: State and Events
|
|
3
|
-
tags: [state, events, observable, reactive, bus, emit, on, once, waitFor]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# State and Events
|
|
7
|
-
|
|
8
|
-
Every container and helper in Luca has observable state and a typed event bus. These are the core primitives for building reactive applications.
|
|
9
|
-
|
|
10
|
-
## Observable State
|
|
11
|
-
|
|
12
|
-
State is a key-value store that notifies observers when values change.
|
|
13
|
-
|
|
14
|
-
### Basic Usage
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
// Every helper has state
|
|
18
|
-
const feature = container.feature('myFeature')
|
|
19
|
-
|
|
20
|
-
feature.state.set('loading', true)
|
|
21
|
-
feature.state.get('loading') // true
|
|
22
|
-
feature.state.current // Snapshot: { loading: true, ... }
|
|
23
|
-
feature.state.version // Number, increments on every change
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Observing Changes
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
// Watch all state changes
|
|
30
|
-
const dispose = feature.state.observe((changeType, key, value) => {
|
|
31
|
-
// changeType: 'add' | 'update' | 'delete'
|
|
32
|
-
console.log(`${key} was ${changeType}d:`, value)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
// Later, stop observing
|
|
36
|
-
dispose()
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Container State
|
|
40
|
-
|
|
41
|
-
The container itself tracks important state:
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
container.state.get('started') // boolean
|
|
45
|
-
container.state.get('enabledFeatures') // string[]
|
|
46
|
-
container.state.get('registries') // string[]
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### State in Custom Features
|
|
50
|
-
|
|
51
|
-
Define your feature's state shape with a Zod schema:
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
const TaskStateSchema = FeatureStateSchema.extend({
|
|
55
|
-
tasks: z.array(z.object({
|
|
56
|
-
id: z.string(),
|
|
57
|
-
title: z.string(),
|
|
58
|
-
done: z.boolean(),
|
|
59
|
-
})).default([]).describe('List of tasks'),
|
|
60
|
-
filter: z.enum(['all', 'active', 'done']).default('all').describe('Current filter'),
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
class TaskManager extends Feature<z.infer<typeof TaskStateSchema>> {
|
|
64
|
-
static override stateSchema = TaskStateSchema
|
|
65
|
-
|
|
66
|
-
addTask(title: string) {
|
|
67
|
-
const tasks = this.state.get('tasks') || []
|
|
68
|
-
const task = { id: crypto.randomUUID(), title, done: false }
|
|
69
|
-
this.state.set('tasks', [...tasks, task])
|
|
70
|
-
this.emit('taskAdded', task)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
get activeTasks() {
|
|
74
|
-
return (this.state.get('tasks') || []).filter(t => !t.done)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Event Bus
|
|
80
|
-
|
|
81
|
-
The event bus enables decoupled communication between components.
|
|
82
|
-
|
|
83
|
-
### Emitting and Listening
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// Listen for an event
|
|
87
|
-
feature.on('taskCompleted', (task) => {
|
|
88
|
-
console.log(`Task "${task.title}" is done!`)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Emit an event
|
|
92
|
-
feature.emit('taskCompleted', { id: '1', title: 'Write docs', done: true })
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### One-Time Listeners
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
feature.once('initialized', () => {
|
|
99
|
-
console.log('Feature is ready (this runs once)')
|
|
100
|
-
})
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Waiting for Events (Promise-Based)
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
// Block until an event fires
|
|
107
|
-
await feature.waitFor('ready')
|
|
108
|
-
console.log('Feature is now ready')
|
|
109
|
-
|
|
110
|
-
// Useful for initialization sequences
|
|
111
|
-
const server = container.server('express', { port: 3000 })
|
|
112
|
-
await server.start()
|
|
113
|
-
console.log('Server is accepting connections on port', server.state.get('port'))
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Container Events
|
|
117
|
-
|
|
118
|
-
The container emits events for lifecycle moments:
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
container.on('featureEnabled', (featureId, feature) => {
|
|
122
|
-
console.log(`Feature ${featureId} was enabled`)
|
|
123
|
-
})
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Patterns
|
|
127
|
-
|
|
128
|
-
### Coordinating Between Features
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
const auth = container.feature('auth')
|
|
132
|
-
const analytics = container.feature('analytics')
|
|
133
|
-
|
|
134
|
-
// Analytics reacts to auth events
|
|
135
|
-
auth.on('userLoggedIn', (user) => {
|
|
136
|
-
analytics.logEvent('login', { userId: user.id })
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
auth.on('userLoggedOut', (user) => {
|
|
140
|
-
analytics.logEvent('logout', { userId: user.id })
|
|
141
|
-
})
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### State-Driven UI Updates
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
const cart = container.feature('cart')
|
|
148
|
-
|
|
149
|
-
cart.state.observe((type, key, value) => {
|
|
150
|
-
if (key === 'items') {
|
|
151
|
-
renderCartBadge(value.length)
|
|
152
|
-
}
|
|
153
|
-
if (key === 'total') {
|
|
154
|
-
renderCartTotal(value)
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Initialization Gates
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
// Wait for multiple features to be ready
|
|
163
|
-
await Promise.all([
|
|
164
|
-
container.feature('db').waitFor('connected'),
|
|
165
|
-
container.feature('cache').waitFor('ready'),
|
|
166
|
-
container.feature('auth').waitFor('initialized'),
|
|
167
|
-
])
|
|
168
|
-
|
|
169
|
-
console.log('All systems ready, starting server...')
|
|
170
|
-
await container.server('express', { port: 3000 }).start()
|
|
171
|
-
```
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Servers
|
|
3
|
-
tags: [servers, express, websocket, start, stop, middleware, static]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Servers
|
|
7
|
-
|
|
8
|
-
Servers are helpers that listen for connections. Luca provides Express and WebSocket servers out of the box.
|
|
9
|
-
|
|
10
|
-
## Express Server
|
|
11
|
-
|
|
12
|
-
### Basic Setup
|
|
13
|
-
|
|
14
|
-
```typescript
|
|
15
|
-
const server = container.server('express', {
|
|
16
|
-
port: 3000,
|
|
17
|
-
cors: true,
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
await server.start()
|
|
21
|
-
console.log('Listening on http://localhost:3000')
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### With Endpoints
|
|
25
|
-
|
|
26
|
-
The most common pattern is file-based endpoints:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
const server = container.server('express', { port: 3000, cors: true })
|
|
30
|
-
|
|
31
|
-
// Auto-discover and mount endpoint files
|
|
32
|
-
await server.useEndpoints('./endpoints')
|
|
33
|
-
|
|
34
|
-
// Generate OpenAPI spec
|
|
35
|
-
server.serveOpenAPISpec({
|
|
36
|
-
title: 'My API',
|
|
37
|
-
version: '1.0.0',
|
|
38
|
-
description: 'An awesome API built with Luca',
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
await server.start()
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Static Files
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
const server = container.server('express', {
|
|
48
|
-
port: 3000,
|
|
49
|
-
static: './public', // Serve files from public/ directory
|
|
50
|
-
})
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Port Auto-Discovery
|
|
54
|
-
|
|
55
|
-
If the requested port is taken, `configure()` can find an open one:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
const server = container.server('express', { port: 3000 })
|
|
59
|
-
await server.configure() // Finds port 3000 or next available
|
|
60
|
-
await server.start()
|
|
61
|
-
console.log(`Listening on port ${server.state.get('port')}`)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Server State
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// After starting, check server state
|
|
68
|
-
await server.start()
|
|
69
|
-
server.state.get('listening') // true
|
|
70
|
-
server.state.get('port') // 3000
|
|
71
|
-
|
|
72
|
-
// Watch for state changes
|
|
73
|
-
server.state.observe((type, key, value) => {
|
|
74
|
-
if (key === 'listening' && value) {
|
|
75
|
-
console.log('Server is now listening')
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Accessing the Express App
|
|
81
|
-
|
|
82
|
-
For custom middleware or routes beyond file-based endpoints:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
const server = container.server('express', { port: 3000 })
|
|
86
|
-
|
|
87
|
-
// Access the underlying express app
|
|
88
|
-
const app = server.app
|
|
89
|
-
|
|
90
|
-
app.use((req, res, next) => {
|
|
91
|
-
console.log(`${req.method} ${req.url}`)
|
|
92
|
-
next()
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
app.get('/custom', (req, res) => {
|
|
96
|
-
res.json({ message: 'Custom route' })
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
await server.start()
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## WebSocket Server
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
const ws = container.server('websocket', { port: 8080 })
|
|
106
|
-
|
|
107
|
-
ws.on('connection', (socket) => {
|
|
108
|
-
console.log('Client connected')
|
|
109
|
-
|
|
110
|
-
socket.on('message', (data) => {
|
|
111
|
-
console.log('Received:', data)
|
|
112
|
-
socket.send(JSON.stringify({ echo: data }))
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
await ws.start()
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Combining Servers
|
|
120
|
-
|
|
121
|
-
Run HTTP and WebSocket together:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
const http = container.server('express', { port: 3000 })
|
|
125
|
-
const ws = container.server('websocket', { port: 8080 })
|
|
126
|
-
|
|
127
|
-
await http.useEndpoints('./endpoints')
|
|
128
|
-
|
|
129
|
-
await Promise.all([
|
|
130
|
-
http.start(),
|
|
131
|
-
ws.start(),
|
|
132
|
-
])
|
|
133
|
-
|
|
134
|
-
console.log('HTTP on :3000, WebSocket on :8080')
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Discovering Servers
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
container.servers.available // ['express', 'websocket']
|
|
141
|
-
container.servers.describe('express')
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## The `luca serve` Command
|
|
145
|
-
|
|
146
|
-
For most projects, you don't need to set up the server manually. The built-in `luca serve` command does it for you:
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
luca serve --port 3000
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
It automatically:
|
|
153
|
-
- Finds your `endpoints/` directory
|
|
154
|
-
- Mounts all endpoint files
|
|
155
|
-
- Serves `public/` as static files
|
|
156
|
-
- Generates the OpenAPI spec
|
|
157
|
-
- Prints all routes
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Writing Endpoints
|
|
3
|
-
tags: [endpoints, routes, api, express, openapi, rest, http, server]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Writing Endpoints
|
|
7
|
-
|
|
8
|
-
Endpoints are file-based HTTP routes. Each file in your `endpoints/` directory becomes an API route. Luca auto-discovers them when you run `luca serve`.
|
|
9
|
-
|
|
10
|
-
## Basic Endpoint
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
// endpoints/health.ts
|
|
14
|
-
export const path = '/health'
|
|
15
|
-
export const description = 'Health check endpoint'
|
|
16
|
-
|
|
17
|
-
export async function get() {
|
|
18
|
-
return { status: 'ok', uptime: process.uptime() }
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
That's it. `luca serve` will mount `GET /health` and include it in the auto-generated OpenAPI spec.
|
|
23
|
-
|
|
24
|
-
## Request Validation with Zod
|
|
25
|
-
|
|
26
|
-
Define schemas for your handlers. Parameters are validated automatically:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
// endpoints/users.ts
|
|
30
|
-
import { z } from 'zod'
|
|
31
|
-
import type { EndpointContext } from '@soederpop/luca'
|
|
32
|
-
|
|
33
|
-
export const path = '/api/users'
|
|
34
|
-
export const description = 'User management'
|
|
35
|
-
export const tags = ['users']
|
|
36
|
-
|
|
37
|
-
// GET /api/users?role=admin&limit=10
|
|
38
|
-
export const getSchema = z.object({
|
|
39
|
-
role: z.string().optional().describe('Filter by role'),
|
|
40
|
-
limit: z.number().default(50).describe('Max results'),
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
export async function get(params: z.infer<typeof getSchema>, ctx: EndpointContext) {
|
|
44
|
-
// params.role and params.limit are validated and typed
|
|
45
|
-
return { users: [], total: 0 }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// POST /api/users
|
|
49
|
-
export const postSchema = z.object({
|
|
50
|
-
name: z.string().describe('Full name'),
|
|
51
|
-
email: z.string().email().describe('Email address'),
|
|
52
|
-
role: z.enum(['user', 'admin']).default('user').describe('User role'),
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
export async function post(params: z.infer<typeof postSchema>, ctx: EndpointContext) {
|
|
56
|
-
// params are validated
|
|
57
|
-
return { user: { id: '1', ...params }, message: 'User created' }
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## URL Parameters
|
|
62
|
-
|
|
63
|
-
Use `:param` in the path or bracket-based file naming:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
// endpoints/users/[id].ts
|
|
67
|
-
import { z } from 'zod'
|
|
68
|
-
import type { EndpointContext } from '@soederpop/luca'
|
|
69
|
-
|
|
70
|
-
export const path = '/api/users/:id'
|
|
71
|
-
export const description = 'Get, update, or delete a specific user'
|
|
72
|
-
export const tags = ['users']
|
|
73
|
-
|
|
74
|
-
export async function get(_params: any, ctx: EndpointContext) {
|
|
75
|
-
const { id } = ctx.params // From the URL
|
|
76
|
-
return { user: { id, name: 'Example' } }
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export const putSchema = z.object({
|
|
80
|
-
name: z.string().optional(),
|
|
81
|
-
email: z.string().email().optional(),
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
export async function put(params: z.infer<typeof putSchema>, ctx: EndpointContext) {
|
|
85
|
-
const { id } = ctx.params
|
|
86
|
-
return { user: { id, ...params }, message: 'Updated' }
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Use `destroy` for DELETE — it's a reserved word in JS
|
|
90
|
-
export async function destroy(_params: any, ctx: EndpointContext) {
|
|
91
|
-
const { id } = ctx.params
|
|
92
|
-
return { message: `User ${id} deleted` }
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## The EndpointContext
|
|
97
|
-
|
|
98
|
-
Every handler receives `(params, ctx)`. The context gives you access to:
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
export async function post(params: any, ctx: EndpointContext) {
|
|
102
|
-
const {
|
|
103
|
-
container, // The Luca container -- access any feature from here
|
|
104
|
-
request, // Express request object
|
|
105
|
-
response, // Express response object
|
|
106
|
-
query, // Parsed query string
|
|
107
|
-
body, // Parsed request body
|
|
108
|
-
params: urlParams, // URL parameters (:id, etc.)
|
|
109
|
-
} = ctx
|
|
110
|
-
|
|
111
|
-
// Use container features
|
|
112
|
-
const data = container.fs.readJson('./data/config.json')
|
|
113
|
-
|
|
114
|
-
return { success: true }
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## Supported HTTP Methods
|
|
119
|
-
|
|
120
|
-
Export any of these handler functions:
|
|
121
|
-
|
|
122
|
-
- `get` -- GET requests
|
|
123
|
-
- `post` -- POST requests
|
|
124
|
-
- `put` -- PUT requests
|
|
125
|
-
- `patch` -- PATCH requests
|
|
126
|
-
- `destroy` -- DELETE requests (preferred — avoids the `delete` reserved word)
|
|
127
|
-
- `delete` -- DELETE requests (also works via `export { del as delete }`)
|
|
128
|
-
|
|
129
|
-
Each can have a corresponding schema export: `getSchema`, `postSchema`, `putSchema`, `patchSchema`, `destroySchema` / `deleteSchema`.
|
|
130
|
-
|
|
131
|
-
## What Gets Exported
|
|
132
|
-
|
|
133
|
-
| Export | Required | Description |
|
|
134
|
-
|--------|----------|-------------|
|
|
135
|
-
| `path` | Yes | The route path (e.g. `/api/users`, `/api/users/:id`) |
|
|
136
|
-
| `description` | No | Human-readable description (used in OpenAPI spec) |
|
|
137
|
-
| `tags` | No | Array of tags for OpenAPI grouping |
|
|
138
|
-
| `get`, `post`, `put`, `patch`, `destroy` | At least one | Handler functions (`destroy` maps to DELETE) |
|
|
139
|
-
| `getSchema`, `postSchema`, `destroySchema`, etc. | No | Zod schemas for request validation |
|
|
140
|
-
|
|
141
|
-
## Starting the Server
|
|
142
|
-
|
|
143
|
-
```bash
|
|
144
|
-
# Default: looks for endpoints/ or src/endpoints/, serves on port 3000
|
|
145
|
-
luca serve
|
|
146
|
-
|
|
147
|
-
# Custom port and directories
|
|
148
|
-
luca serve --port 4000 --endpointsDir src/routes --staticDir public
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
The server automatically:
|
|
152
|
-
- Discovers and mounts all endpoint files
|
|
153
|
-
- Generates an OpenAPI spec at `/openapi.json`
|
|
154
|
-
- Serves static files from `public/` if it exists
|
|
155
|
-
- Enables CORS by default
|
|
156
|
-
- Prints all mounted routes to the console
|
|
157
|
-
|
|
158
|
-
## Programmatic Server Setup
|
|
159
|
-
|
|
160
|
-
You can also set up the server in a script:
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
import container from '@soederpop/luca'
|
|
164
|
-
|
|
165
|
-
const server = container.server('express', { port: 3000, cors: true })
|
|
166
|
-
|
|
167
|
-
await server.useEndpoints('./endpoints')
|
|
168
|
-
|
|
169
|
-
server.serveOpenAPISpec({
|
|
170
|
-
title: 'My API',
|
|
171
|
-
version: '1.0.0',
|
|
172
|
-
description: 'My awesome API',
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
await server.start()
|
|
176
|
-
console.log('Server running on http://localhost:3000')
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Streaming Responses
|
|
180
|
-
|
|
181
|
-
For endpoints that need to stream (e.g. AI responses), you can write directly to the response:
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
export const path = '/api/stream'
|
|
185
|
-
|
|
186
|
-
export async function post(params: any, ctx: EndpointContext) {
|
|
187
|
-
const { response } = ctx
|
|
188
|
-
|
|
189
|
-
response.setHeader('Content-Type', 'text/event-stream')
|
|
190
|
-
response.setHeader('Cache-Control', 'no-cache')
|
|
191
|
-
|
|
192
|
-
for (const chunk of data) {
|
|
193
|
-
response.write(`data: ${JSON.stringify(chunk)}\n\n`)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
response.end()
|
|
197
|
-
}
|
|
198
|
-
```
|