@facetlayer/prism-framework 0.4.0 → 0.4.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.
- package/README.md +176 -8
- package/dist/Errors.d.ts +38 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Metrics.d.ts +5 -0
- package/dist/Metrics.d.ts.map +1 -0
- package/dist/RequestContext.d.ts +17 -0
- package/dist/RequestContext.d.ts.map +1 -0
- package/dist/ServiceDefinition.d.ts +16 -0
- package/dist/ServiceDefinition.d.ts.map +1 -0
- package/dist/app/PrismApp.d.ts +31 -0
- package/dist/app/PrismApp.d.ts.map +1 -0
- package/dist/app/callEndpoint.d.ts +13 -0
- package/dist/app/callEndpoint.d.ts.map +1 -0
- package/dist/app/validateApp.d.ts +20 -0
- package/dist/app/validateApp.d.ts.map +1 -0
- package/dist/authorization/AuthSource.d.ts +8 -0
- package/dist/authorization/AuthSource.d.ts.map +1 -0
- package/dist/authorization/Authorization.d.ts +24 -0
- package/dist/authorization/Authorization.d.ts.map +1 -0
- package/dist/authorization/Resource.d.ts +5 -0
- package/dist/authorization/Resource.d.ts.map +1 -0
- package/dist/authorization/index.d.ts +5 -0
- package/dist/authorization/index.d.ts.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/databases/DatabaseInitializationOptions.d.ts +9 -0
- package/dist/databases/DatabaseInitializationOptions.d.ts.map +1 -0
- package/dist/databases/DatabaseSetup.d.ts +3 -0
- package/dist/databases/DatabaseSetup.d.ts.map +1 -0
- package/dist/endpoints/createEndpoint.d.ts +4 -0
- package/dist/endpoints/createEndpoint.d.ts.map +1 -0
- package/dist/endpoints/getEffectiveOperationId.d.ts +19 -0
- package/dist/endpoints/getEffectiveOperationId.d.ts.map +1 -0
- package/dist/env/Env.d.ts +2 -0
- package/dist/env/Env.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1364 -0
- package/dist/launch/launchConfig.d.ts +18 -0
- package/dist/launch/launchConfig.d.ts.map +1 -0
- package/dist/logging/index.d.ts +9 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/sse/ConnectionManager.d.ts +23 -0
- package/dist/sse/ConnectionManager.d.ts.map +1 -0
- package/dist/stdin/StdinServer.d.ts +38 -0
- package/dist/stdin/StdinServer.d.ts.map +1 -0
- package/dist/web/EndpointListing.d.ts +3 -0
- package/dist/web/EndpointListing.d.ts.map +1 -0
- package/dist/web/ExpressAppSetup.d.ts +18 -0
- package/dist/web/ExpressAppSetup.d.ts.map +1 -0
- package/dist/web/ExpressEndpointSetup.d.ts +31 -0
- package/dist/web/ExpressEndpointSetup.d.ts.map +1 -0
- package/dist/web/SseResponse.d.ts +15 -0
- package/dist/web/SseResponse.d.ts.map +1 -0
- package/dist/web/ViteIntegration.d.ts +19 -0
- package/dist/web/ViteIntegration.d.ts.map +1 -0
- package/dist/web/corsMiddleware.d.ts +14 -0
- package/dist/web/corsMiddleware.d.ts.map +1 -0
- package/dist/web/localhostOnlyMiddleware.d.ts +3 -0
- package/dist/web/localhostOnlyMiddleware.d.ts.map +1 -0
- package/dist/web/openapi/OpenAPI.d.ts +37 -0
- package/dist/web/openapi/OpenAPI.d.ts.map +1 -0
- package/dist/web/openapi/validateServicesForOpenapi.d.ts +32 -0
- package/dist/web/openapi/validateServicesForOpenapi.d.ts.map +1 -0
- package/dist/web/requestContextMiddleware.d.ts +3 -0
- package/dist/web/requestContextMiddleware.d.ts.map +1 -0
- package/docs/authorization.md +281 -0
- package/docs/cors-setup.md +172 -0
- package/docs/creating-services.md +220 -0
- package/docs/database-setup.md +134 -0
- package/docs/endpoint-tools.md +1 -11
- package/docs/env-files.md +12 -1
- package/docs/error-handling.md +70 -0
- package/docs/getting-started.md +22 -12
- package/docs/launch-configuration.md +223 -0
- package/docs/overview.md +62 -0
- package/docs/server-setup.md +144 -0
- package/docs/source-directory-organization.md +115 -0
- package/docs/stdin-protocol.md +176 -0
- package/package.json +42 -9
- package/src/Errors.ts +120 -0
- package/src/Metrics.ts +53 -0
- package/src/RequestContext.ts +36 -0
- package/src/ServiceDefinition.ts +35 -0
- package/src/__tests__/Authorization.test.ts +350 -0
- package/src/__tests__/Errors.test.ts +378 -0
- package/src/__tests__/ListEndpoints.test.ts +98 -0
- package/src/__tests__/PrismApp.test.ts +274 -0
- package/src/__tests__/RequestContext.test.ts +295 -0
- package/src/__tests__/SseResponse.test.ts +189 -0
- package/src/__tests__/StdinServer.test.ts +304 -0
- package/src/__tests__/corsMiddleware.test.ts +293 -0
- package/src/__tests__/createEndpoint.test.ts +412 -0
- package/src/__tests__/validateApp.test.ts +206 -0
- package/src/app/PrismApp.ts +117 -0
- package/src/app/callEndpoint.ts +55 -0
- package/src/app/validateApp.ts +78 -0
- package/src/authorization/AuthSource.ts +14 -0
- package/src/authorization/Authorization.ts +78 -0
- package/src/authorization/Resource.ts +8 -0
- package/src/authorization/index.ts +4 -0
- package/src/databases/DatabaseInitializationOptions.ts +9 -0
- package/src/databases/DatabaseSetup.ts +19 -0
- package/src/endpoints/createEndpoint.ts +39 -0
- package/src/endpoints/getEffectiveOperationId.ts +90 -0
- package/src/env/Env.ts +23 -0
- package/src/index.ts +78 -0
- package/src/launch/launchConfig.ts +59 -0
- package/src/list-endpoints-command.ts +1 -1
- package/src/logging/index.ts +25 -0
- package/src/sse/ConnectionManager.ts +79 -0
- package/src/stdin/StdinServer.ts +129 -0
- package/src/web/EndpointListing.ts +166 -0
- package/src/web/ExpressAppSetup.ts +125 -0
- package/src/web/ExpressEndpointSetup.ts +178 -0
- package/src/web/SseResponse.ts +78 -0
- package/src/web/ViteIntegration.ts +72 -0
- package/src/web/__tests__/OpenAPI.invalidZodSchemas.test.ts +250 -0
- package/src/web/corsMiddleware.ts +63 -0
- package/src/web/localhostOnlyMiddleware.ts +19 -0
- package/src/web/openapi/OpenAPI.ts +248 -0
- package/src/web/openapi/validateServicesForOpenapi.ts +76 -0
- package/src/web/requestContextMiddleware.ts +25 -0
- package/.claude/settings.local.json +0 -20
- package/CHANGELOG +0 -28
- package/CLAUDE.md +0 -44
- package/build.mts +0 -8
- package/test/call-command.test.ts +0 -96
- package/test/generate-api-clients.test.ts +0 -33
- package/test/generate-api-clients.test.ts.disabled +0 -75
- package/tsconfig.json +0 -21
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: launch-configuration
|
|
3
|
+
description: How to configure Prism Framework for different execution contexts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Launch Configuration
|
|
7
|
+
|
|
8
|
+
The launch configuration system is a crucial feature that allows the same code to work in both backend (Express.js) and desktop (Electron) contexts.
|
|
9
|
+
|
|
10
|
+
## Why Launch Configuration?
|
|
11
|
+
|
|
12
|
+
Different execution contexts need different configurations:
|
|
13
|
+
- **Backend server**: Database files on disk, specific logging configuration
|
|
14
|
+
- **Electron desktop app**: Database files in user data directory, different SQLite loader
|
|
15
|
+
|
|
16
|
+
The `setLaunchConfig()` function centralizes this configuration and must be called **before** any services access databases or logging.
|
|
17
|
+
|
|
18
|
+
## Basic Setup
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { setLaunchConfig } from '@facetlayer/prism-framework';
|
|
22
|
+
|
|
23
|
+
setLaunchConfig({
|
|
24
|
+
logging: {
|
|
25
|
+
databaseFilename: '/path/to/logs.db',
|
|
26
|
+
enableConsoleLogging: true,
|
|
27
|
+
loadDatabase: await loadBetterSqlite(),
|
|
28
|
+
},
|
|
29
|
+
database: {
|
|
30
|
+
user: {
|
|
31
|
+
migrationBehavior: 'safe-upgrades',
|
|
32
|
+
databasePath: '/path/to/databases',
|
|
33
|
+
services: ALL_SERVICES,
|
|
34
|
+
loadDatabase: await loadBetterSqlite(),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration Structure
|
|
41
|
+
|
|
42
|
+
### Logging Configuration
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
interface LoggingSettings {
|
|
46
|
+
databaseFilename: string; // Path to logging database
|
|
47
|
+
enableConsoleLogging: boolean; // Also log to console
|
|
48
|
+
loadDatabase: LoadDatabaseFn; // Database loader function
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Database Configuration
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
interface DatabaseInitializationOptions {
|
|
56
|
+
migrationBehavior: MigrationBehavior; // How to handle schema changes
|
|
57
|
+
databasePath: string; // Directory for database files
|
|
58
|
+
services: ServiceDefinition[]; // Services to include schemas from
|
|
59
|
+
loadDatabase: LoadDatabaseFn; // Database loader function
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Migration Behavior
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
type MigrationBehavior =
|
|
67
|
+
| 'safe-upgrades' // Only allow adding columns/tables
|
|
68
|
+
| 'rebuild' // Drop and recreate on mismatch
|
|
69
|
+
| 'error-on-mismatch'; // Throw error on schema mismatch
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Backend Server Example
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// main.ts (backend server)
|
|
76
|
+
import { setLaunchConfig, startServer, App } from '@facetlayer/prism-framework';
|
|
77
|
+
import { loadBetterSqlite } from '@facetlayer/sqlite-wrapper';
|
|
78
|
+
import path from 'path';
|
|
79
|
+
import fs from 'fs';
|
|
80
|
+
|
|
81
|
+
async function main() {
|
|
82
|
+
const databasePath = process.env.SQLITE_DATABASE_PATH || './databases';
|
|
83
|
+
|
|
84
|
+
// Ensure directory exists
|
|
85
|
+
if (!fs.existsSync(databasePath)) {
|
|
86
|
+
fs.mkdirSync(databasePath, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Configure for backend
|
|
90
|
+
setLaunchConfig({
|
|
91
|
+
logging: {
|
|
92
|
+
databaseFilename: path.join(databasePath, 'logs.db'),
|
|
93
|
+
enableConsoleLogging: true,
|
|
94
|
+
loadDatabase: await loadBetterSqlite(),
|
|
95
|
+
},
|
|
96
|
+
database: {
|
|
97
|
+
user: {
|
|
98
|
+
migrationBehavior: 'safe-upgrades',
|
|
99
|
+
databasePath,
|
|
100
|
+
services: ALL_SERVICES,
|
|
101
|
+
loadDatabase: await loadBetterSqlite(),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Start server (see server-setup doc for full startServer options)
|
|
107
|
+
const app = new App({ services: ALL_SERVICES });
|
|
108
|
+
await startServer({ app, port: parseInt(process.env.PRISM_API_PORT!, 10) });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main().catch(console.error);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Electron Desktop App Example
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// main.ts (Electron main process)
|
|
118
|
+
import { app } from 'electron';
|
|
119
|
+
import { setLaunchConfig } from '@facetlayer/prism-framework';
|
|
120
|
+
import { getSqliteLoader } from './database-helper';
|
|
121
|
+
import path from 'path';
|
|
122
|
+
|
|
123
|
+
async function initializeApp() {
|
|
124
|
+
await app.whenReady();
|
|
125
|
+
|
|
126
|
+
const userDataPath = app.getPath('userData');
|
|
127
|
+
const databasePath = path.join(userDataPath, 'databases');
|
|
128
|
+
|
|
129
|
+
// Get Electron-compatible SQLite loader
|
|
130
|
+
const loadDatabase = await getSqliteLoader();
|
|
131
|
+
|
|
132
|
+
// Configure for Electron
|
|
133
|
+
setLaunchConfig({
|
|
134
|
+
logging: {
|
|
135
|
+
databaseFilename: path.join(databasePath, 'logs.db'),
|
|
136
|
+
enableConsoleLogging: true,
|
|
137
|
+
loadDatabase,
|
|
138
|
+
},
|
|
139
|
+
database: {
|
|
140
|
+
'desktop-app': {
|
|
141
|
+
migrationBehavior: 'safe-upgrades',
|
|
142
|
+
databasePath,
|
|
143
|
+
services: ALL_SERVICES,
|
|
144
|
+
loadDatabase,
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Continue with Electron app initialization...
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Accessing Configuration
|
|
154
|
+
|
|
155
|
+
Services and framework code can access the configuration:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import {
|
|
159
|
+
getLaunchConfig,
|
|
160
|
+
getDatabaseConfig,
|
|
161
|
+
getLoggingConfig
|
|
162
|
+
} from '@facetlayer/prism-framework';
|
|
163
|
+
|
|
164
|
+
// Get full config
|
|
165
|
+
const config = getLaunchConfig();
|
|
166
|
+
|
|
167
|
+
// Get database config for a specific database
|
|
168
|
+
const userDbConfig = getDatabaseConfig('user');
|
|
169
|
+
|
|
170
|
+
// Get logging config
|
|
171
|
+
const loggingConfig = getLoggingConfig();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Multiple Databases
|
|
175
|
+
|
|
176
|
+
You can configure multiple databases:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
setLaunchConfig({
|
|
180
|
+
logging: { /* ... */ },
|
|
181
|
+
database: {
|
|
182
|
+
user: {
|
|
183
|
+
migrationBehavior: 'safe-upgrades',
|
|
184
|
+
databasePath: '/path/to/databases',
|
|
185
|
+
services: ALL_SERVICES.filter(s => s.databases?.user),
|
|
186
|
+
loadDatabase: await loadBetterSqlite(),
|
|
187
|
+
},
|
|
188
|
+
project: {
|
|
189
|
+
migrationBehavior: 'safe-upgrades',
|
|
190
|
+
databasePath: '/path/to/databases',
|
|
191
|
+
services: ALL_SERVICES.filter(s => s.databases?.project),
|
|
192
|
+
loadDatabase: await loadBetterSqlite(),
|
|
193
|
+
},
|
|
194
|
+
'desktop-app': {
|
|
195
|
+
migrationBehavior: 'rebuild',
|
|
196
|
+
databasePath: '/path/to/databases',
|
|
197
|
+
services: ALL_SERVICES.filter(s => s.databases?.['desktop-app']),
|
|
198
|
+
loadDatabase: await loadBetterSqlite(),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Database Statements Collection
|
|
205
|
+
|
|
206
|
+
The framework automatically collects SQL statements from all services:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { getStatementsForDatabase } from '@facetlayer/prism-framework';
|
|
210
|
+
|
|
211
|
+
const statements = getStatementsForDatabase('user', ALL_SERVICES);
|
|
212
|
+
// Returns all SQL statements from services that define databases.user
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
This is used internally when initializing databases with `@facetlayer/sqlite-wrapper`.
|
|
216
|
+
|
|
217
|
+
## Best Practices
|
|
218
|
+
|
|
219
|
+
1. **Call setLaunchConfig early** - Before any database or logging operations
|
|
220
|
+
2. **Call it only once** - The function throws if called multiple times
|
|
221
|
+
3. **Use environment variables** - Make paths configurable
|
|
222
|
+
4. **Ensure directories exist** - Create database directories before setting config
|
|
223
|
+
5. **Use appropriate migration behavior** - `safe-upgrades` for production, `rebuild` for development
|
package/docs/overview.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: overview
|
|
3
|
+
description: Introduction to Prism Framework and its core concepts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prism Framework Overview
|
|
7
|
+
|
|
8
|
+
Prism Framework is a TypeScript framework for building web-based SaaS applications and desktop Electron apps. It provides a unified approach to creating applications that can run in both backend (Express.js) and desktop (Electron) contexts.
|
|
9
|
+
|
|
10
|
+
## Key Features
|
|
11
|
+
|
|
12
|
+
1. **Service-Based Architecture** - Organize your application into self-contained services
|
|
13
|
+
2. **Type-Safe Endpoints** - Define endpoints with Zod schemas for request/response validation
|
|
14
|
+
3. **Launch Configuration** - Single configuration system that works for both web and desktop
|
|
15
|
+
4. **Database Management** - Integration with `@facetlayer/sqlite-wrapper` for database operations
|
|
16
|
+
5. **Request Context** - AsyncLocalStorage-based request context tracking
|
|
17
|
+
6. **Authorization** - Built-in authorization system with resources and auth sources
|
|
18
|
+
7. **Metrics** - Prometheus metrics integration
|
|
19
|
+
8. **SSE Support** - Server-Sent Events for real-time communication
|
|
20
|
+
9. **Error Handling** - Comprehensive HTTP error classes
|
|
21
|
+
|
|
22
|
+
## Core Concepts
|
|
23
|
+
|
|
24
|
+
### Services
|
|
25
|
+
|
|
26
|
+
A service is a self-contained module that can include API endpoints, middleware, database schemas, and background jobs. Services are the building blocks of a Prism application.
|
|
27
|
+
|
|
28
|
+
See the `creating-services` doc for the full `ServiceDefinition` interface and examples.
|
|
29
|
+
|
|
30
|
+
### Launch Configuration
|
|
31
|
+
|
|
32
|
+
The launch configuration system allows the same code to work in different contexts (backend server, Electron desktop app). Call `setLaunchConfig()` early in your app to configure logging and database settings.
|
|
33
|
+
|
|
34
|
+
See the `launch-configuration` doc for setup details and examples.
|
|
35
|
+
|
|
36
|
+
### Request Context
|
|
37
|
+
|
|
38
|
+
Every request has an associated context (via AsyncLocalStorage) that flows through all async operations. Access it with `getCurrentRequestContext()` to get request ID, auth info, and more.
|
|
39
|
+
|
|
40
|
+
See the `authorization` doc for how auth integrates with request context.
|
|
41
|
+
|
|
42
|
+
### Error Handling
|
|
43
|
+
|
|
44
|
+
The framework provides built-in HTTP error classes (`BadRequestError`, `NotFoundError`, `ForbiddenError`, etc.) that automatically map to the correct status codes.
|
|
45
|
+
|
|
46
|
+
See the `error-handling` doc for available error classes and usage patterns.
|
|
47
|
+
|
|
48
|
+
## Project Structure
|
|
49
|
+
|
|
50
|
+
See the `source-directory-organization` doc for the recommended directory layout and conventions.
|
|
51
|
+
|
|
52
|
+
## Getting Started
|
|
53
|
+
|
|
54
|
+
1. Install the framework (requires **Zod v4** — Zod v3 is not compatible):
|
|
55
|
+
```bash
|
|
56
|
+
pnpm add @facetlayer/prism-framework zod@^4
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
2. Set up environment variables (see `env-files` doc)
|
|
60
|
+
3. Create your first service (see `creating-services` doc)
|
|
61
|
+
4. Set up the launch configuration (see `launch-configuration` doc)
|
|
62
|
+
5. Start the server (see `server-setup` doc)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: server-setup
|
|
3
|
+
description: How to set up and start an Express.js server using Prism Framework
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Server Setup
|
|
7
|
+
|
|
8
|
+
This guide explains how to set up and start an Express.js server using Prism Framework.
|
|
9
|
+
|
|
10
|
+
## Quick Outline
|
|
11
|
+
|
|
12
|
+
Brief summary of the steps to setup a Prism server:
|
|
13
|
+
|
|
14
|
+
- Use the `@facetlayer/prism-framework` library
|
|
15
|
+
- Create an instance of `App` and use `startServer`
|
|
16
|
+
- API endpoints are automatically mounted at `/api/`
|
|
17
|
+
- Optionally serve web files (HTML/JS/CSS) from the same server
|
|
18
|
+
- Use the env var `PRISM_API_PORT` as the service port.
|
|
19
|
+
|
|
20
|
+
## Server Setup Example
|
|
21
|
+
|
|
22
|
+
### API-only server
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { App, startServer } from '@facetlayer/prism-framework';
|
|
26
|
+
|
|
27
|
+
const app = new App({ services: ALL_SERVICES });
|
|
28
|
+
|
|
29
|
+
await startServer({
|
|
30
|
+
app,
|
|
31
|
+
port: parseInt(process.env.PRISM_API_PORT || '4000', 10),
|
|
32
|
+
openapiConfig: {
|
|
33
|
+
enable: true,
|
|
34
|
+
enableSwagger: true,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
All endpoints are mounted under `/api/`. For example, an endpoint defined with
|
|
40
|
+
`path: '/users'` is accessible at `GET /api/users`.
|
|
41
|
+
|
|
42
|
+
### Unified server with web files
|
|
43
|
+
|
|
44
|
+
To serve both API and web pages from a single process on one port, add the
|
|
45
|
+
`web` config option:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { App, startServer } from '@facetlayer/prism-framework';
|
|
49
|
+
import { join, dirname } from 'path';
|
|
50
|
+
import { fileURLToPath } from 'url';
|
|
51
|
+
|
|
52
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
|
|
54
|
+
const app = new App({ services: ALL_SERVICES });
|
|
55
|
+
|
|
56
|
+
await startServer({
|
|
57
|
+
app,
|
|
58
|
+
port: parseInt(process.env.PRISM_API_PORT || '4000', 10),
|
|
59
|
+
openapiConfig: {
|
|
60
|
+
enable: true,
|
|
61
|
+
enableSwagger: true,
|
|
62
|
+
},
|
|
63
|
+
web: {
|
|
64
|
+
dir: join(__dirname, '..', 'web'),
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
When `web` is configured:
|
|
70
|
+
- API endpoints are served under `/api/` (e.g. `/api/users`, `/api/health`)
|
|
71
|
+
- Web files are served from the specified directory at the root path (`/`)
|
|
72
|
+
- In development: uses Vite dev server middleware if `vite` is installed (for HMR)
|
|
73
|
+
- In production: serves static files from `web/dist/` (or `web/` if no dist folder)
|
|
74
|
+
- SPA fallback: unmatched GET requests serve `index.html`
|
|
75
|
+
|
|
76
|
+
### Available framework endpoints
|
|
77
|
+
|
|
78
|
+
These are automatically available under `/api/`:
|
|
79
|
+
|
|
80
|
+
| Path | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `/api/health` | Health check (localhost only) |
|
|
83
|
+
| `/api/metrics` | Prometheus metrics (localhost only) |
|
|
84
|
+
| `/api/endpoints` | HTML endpoint listing |
|
|
85
|
+
| `/api/endpoints.json` | JSON endpoint listing |
|
|
86
|
+
| `/api/openapi.json` | OpenAPI schema (if enabled) |
|
|
87
|
+
| `/api/swagger` | Swagger UI (if enabled) |
|
|
88
|
+
|
|
89
|
+
## Launching with Candle
|
|
90
|
+
|
|
91
|
+
Use the `candle` process manager to run the server:
|
|
92
|
+
|
|
93
|
+
### Setup
|
|
94
|
+
|
|
95
|
+
Register the service in your `.candle.json`:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"services": [
|
|
100
|
+
{
|
|
101
|
+
"name": "my-app",
|
|
102
|
+
"shell": "node src/main.ts"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Usage
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Start the service
|
|
112
|
+
candle start my-app
|
|
113
|
+
|
|
114
|
+
# Check status
|
|
115
|
+
candle ls
|
|
116
|
+
|
|
117
|
+
# View logs
|
|
118
|
+
candle logs my-app
|
|
119
|
+
|
|
120
|
+
# Restart after changes
|
|
121
|
+
candle restart my-app
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Recommended .env setup
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
PRISM_API_PORT=4000
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Vite Integration
|
|
131
|
+
|
|
132
|
+
To use Vite for frontend development with HMR:
|
|
133
|
+
|
|
134
|
+
1. Install `vite` as a dependency in your project
|
|
135
|
+
2. Place your web files in a `web/` directory with an `index.html`
|
|
136
|
+
3. Pass `web: { dir: './web' }` to `startServer`
|
|
137
|
+
|
|
138
|
+
In development mode, Vite's dev server middleware handles all non-API requests,
|
|
139
|
+
providing hot module replacement. In production, the built static files from
|
|
140
|
+
`web/dist/` are served.
|
|
141
|
+
|
|
142
|
+
## Testing
|
|
143
|
+
|
|
144
|
+
Run `prism list-endpoints` to check that the local server is running and the endpoint listing is working.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: source-directory-organization
|
|
3
|
+
description: Recommended directory structure for organizing Prism API source code
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Source Directory Organization
|
|
7
|
+
|
|
8
|
+
This document describes the recommended directory structure for organizing your Prism API source code. Following this pattern ensures consistency across projects and makes navigation intuitive.
|
|
9
|
+
|
|
10
|
+
## Directory Structure
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
src/
|
|
14
|
+
├── _main/ # Main application bootstrap
|
|
15
|
+
│ ├── api.ts # Entry point - starts the server
|
|
16
|
+
│ └── services.ts # Exports ALL_SERVICES array
|
|
17
|
+
├── <service-name>/ # One folder per service
|
|
18
|
+
│ ├── index.ts # Service definition export
|
|
19
|
+
│ └── ... # Additional service files
|
|
20
|
+
├── <service-name>/
|
|
21
|
+
│ └── index.ts
|
|
22
|
+
└── <shared-resource>/ # Shared resources (databases, utils)
|
|
23
|
+
└── ...
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Key Principles
|
|
27
|
+
|
|
28
|
+
### 1. The `_main` Folder
|
|
29
|
+
|
|
30
|
+
The `_main` folder contains the application entry point and service aggregation. The underscore prefix ensures it sorts to the top of the directory listing.
|
|
31
|
+
|
|
32
|
+
**`_main/api.ts`** - The main entry point. Loads environment variables, creates the App, and starts the server. See the `server-setup` doc for full `startServer` examples and the `env-files` doc for environment configuration.
|
|
33
|
+
|
|
34
|
+
**`_main/services.ts`** - Aggregates all services:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { type ServiceDefinition } from '@facetlayer/prism-framework';
|
|
38
|
+
import { definition as usersDefinition } from '../users/index.ts';
|
|
39
|
+
import { definition as projectsDefinition } from '../projects/index.ts';
|
|
40
|
+
|
|
41
|
+
export const ALL_SERVICES: ServiceDefinition[] = [
|
|
42
|
+
usersDefinition,
|
|
43
|
+
projectsDefinition,
|
|
44
|
+
];
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Service Folders
|
|
48
|
+
|
|
49
|
+
Each service lives in its own top-level folder named after the service. The folder contains an `index.ts` that exports the service definition.
|
|
50
|
+
|
|
51
|
+
**Example: `users/index.ts`**
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { createEndpoint, type ServiceDefinition } from '@facetlayer/prism-framework';
|
|
55
|
+
import { z } from 'zod';
|
|
56
|
+
|
|
57
|
+
const getUserEndpoint = createEndpoint({
|
|
58
|
+
method: 'GET',
|
|
59
|
+
path: '/api/users/:id',
|
|
60
|
+
requestSchema: z.object({ id: z.string() }),
|
|
61
|
+
responseSchema: z.object({ id: z.string(), email: z.string() }),
|
|
62
|
+
handler: async (input) => {
|
|
63
|
+
// Implementation
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export const definition: ServiceDefinition = {
|
|
68
|
+
name: 'users',
|
|
69
|
+
endpoints: [getUserEndpoint],
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. No `services` Directory
|
|
74
|
+
|
|
75
|
+
Services should NOT be placed in a `services/` subdirectory. Each service folder exists at the top level of `src/`:
|
|
76
|
+
|
|
77
|
+
**Correct:**
|
|
78
|
+
```
|
|
79
|
+
src/
|
|
80
|
+
├── _main/
|
|
81
|
+
├── users/
|
|
82
|
+
├── projects/
|
|
83
|
+
└── billing/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Incorrect:**
|
|
87
|
+
```
|
|
88
|
+
src/
|
|
89
|
+
├── index.ts
|
|
90
|
+
└── services/
|
|
91
|
+
├── users.ts
|
|
92
|
+
├── projects.ts
|
|
93
|
+
└── billing.ts
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Shared Resources
|
|
97
|
+
|
|
98
|
+
Non-service folders (databases, utilities) can also exist at the top level:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
src/
|
|
102
|
+
├── _main/
|
|
103
|
+
├── users/
|
|
104
|
+
├── projects/
|
|
105
|
+
└── user-database/ # Shared database module
|
|
106
|
+
└── db.ts
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Benefits
|
|
110
|
+
|
|
111
|
+
1. **Discoverability** - The `_main` folder clearly identifies the entry point
|
|
112
|
+
2. **Modularity** - Each service is self-contained in its own folder
|
|
113
|
+
3. **Scalability** - Adding services means adding folders, not modifying existing structure
|
|
114
|
+
4. **Consistency** - All projects follow the same pattern
|
|
115
|
+
5. **Clarity** - The `ALL_SERVICES` array provides a single source of truth for what services exist
|