create-filament 1.0.0

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 (34) hide show
  1. package/README.md +417 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +937 -0
  4. package/package.json +38 -0
  5. package/templates/api/src/config/app.ts +17 -0
  6. package/templates/api/src/handlers/errors.ts +32 -0
  7. package/templates/api/src/handlers/finalizers.ts +27 -0
  8. package/templates/api/src/handlers/transforms.ts +18 -0
  9. package/templates/api/src/index.ts +45 -0
  10. package/templates/api/src/meta/defaults.ts +28 -0
  11. package/templates/api/src/meta/index.ts +50 -0
  12. package/templates/api/src/middleware/index.ts +36 -0
  13. package/templates/api/src/routes/index.ts +26 -0
  14. package/templates/api/tests/integration/example.test.ts +20 -0
  15. package/templates/full/src/config/app.ts +17 -0
  16. package/templates/full/src/handlers/errors.ts +32 -0
  17. package/templates/full/src/handlers/finalizers.ts +27 -0
  18. package/templates/full/src/handlers/transforms.ts +18 -0
  19. package/templates/full/src/index.ts +45 -0
  20. package/templates/full/src/meta/defaults.ts +28 -0
  21. package/templates/full/src/meta/index.ts +31 -0
  22. package/templates/full/src/middleware/index.ts +36 -0
  23. package/templates/full/src/routes/index.ts +26 -0
  24. package/templates/full/tests/integration/example.test.ts +20 -0
  25. package/templates/minimal/src/config/app.ts +17 -0
  26. package/templates/minimal/src/handlers/errors.ts +32 -0
  27. package/templates/minimal/src/handlers/finalizers.ts +27 -0
  28. package/templates/minimal/src/handlers/transforms.ts +18 -0
  29. package/templates/minimal/src/index.ts +45 -0
  30. package/templates/minimal/src/meta/defaults.ts +28 -0
  31. package/templates/minimal/src/meta/index.ts +31 -0
  32. package/templates/minimal/src/middleware/index.ts +36 -0
  33. package/templates/minimal/src/routes/index.ts +26 -0
  34. package/templates/minimal/tests/integration/example.test.ts +20 -0
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "create-filament",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a new Filament application",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-filament": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "filament",
20
+ "scaffold",
21
+ "typescript",
22
+ "api",
23
+ "framework"
24
+ ],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "dependencies": {
28
+ "prompts": "^2.4.2",
29
+ "chalk": "^5.3.0",
30
+ "ora": "^8.0.1"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@types/prompts": "^2.4.9",
35
+ "typescript": "^5.0.0",
36
+ "test-battery": "^3.2.1"
37
+ }
38
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Application configuration
3
+ */
4
+
5
+ export const config = {
6
+ port: parseInt(process.env.PORT || '3000', 10),
7
+ nodeEnv: process.env.NODE_ENV || 'development',
8
+ logLevel: process.env.LOG_LEVEL || 'info',
9
+ };
10
+
11
+ /**
12
+ * Validate required environment variables
13
+ */
14
+ export function validateConfig() {
15
+ // Add validation for required env vars here
16
+ return true;
17
+ }
@@ -0,0 +1,32 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ });
8
+
9
+ /**
10
+ * Register error handlers
11
+ */
12
+ export function registerErrorHandlers(app: Application<AppMeta>) {
13
+ app.onError(async (err, req, res) => {
14
+ const level = req.endpointMeta.logging.level;
15
+
16
+ if (level === 'debug' || level === 'error') {
17
+ logger.error({
18
+ error: err.message,
19
+ stack: err.stack,
20
+ method: req.method,
21
+ path: req.path,
22
+ });
23
+ }
24
+
25
+ if (!res.headersSent) {
26
+ res.status(500).json({
27
+ error: 'Internal Server Error',
28
+ message: process.env.NODE_ENV === 'development' ? err.message : undefined,
29
+ });
30
+ }
31
+ });
32
+ }
@@ -0,0 +1,27 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ });
8
+
9
+ /**
10
+ * Register finalizers (always run)
11
+ */
12
+ export function registerFinalizers(app: Application<AppMeta>) {
13
+ app.onFinalize(async (req, res) => {
14
+ const duration = Date.now() - (req._startTime || Date.now());
15
+ const level = req.endpointMeta.logging.level;
16
+
17
+ if (level === 'debug' || level === 'info') {
18
+ logger.info({
19
+ method: req.method,
20
+ path: req.path,
21
+ status: res.statusCode,
22
+ duration,
23
+ event: 'request.complete',
24
+ });
25
+ }
26
+ });
27
+ }
@@ -0,0 +1,18 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+
4
+ /**
5
+ * Register response transformers
6
+ */
7
+ export function registerTransformers(app: Application<AppMeta>) {
8
+ // Add custom headers based on tags
9
+ app.onTransform(async (req, res) => {
10
+ const tags = req.endpointMeta.tags;
11
+
12
+ if (tags.includes('api')) {
13
+ res.setHeader('X-API-Version', '1.0');
14
+ }
15
+
16
+ // Add more transformations here
17
+ });
18
+ }
@@ -0,0 +1,45 @@
1
+ import { createApp } from 'filamentjs';
2
+ import { defaultMeta } from './meta/defaults.js';
3
+ import { config, validateConfig } from './config/app.js';
4
+ import { registerMiddleware } from './middleware/index.js';
5
+ import { registerRoutes } from './routes/index.js';
6
+ import { registerErrorHandlers } from './handlers/errors.js';
7
+ import { registerTransformers } from './handlers/transforms.js';
8
+ import { registerFinalizers } from './handlers/finalizers.js';
9
+
10
+ // Validate configuration
11
+ validateConfig();
12
+
13
+ // Create Filament application
14
+ const app = createApp(defaultMeta);
15
+
16
+ // Register middleware
17
+ registerMiddleware(app);
18
+
19
+ // Register routes
20
+ registerRoutes(app);
21
+
22
+ // Register post-request handlers
23
+ registerErrorHandlers(app);
24
+ registerTransformers(app);
25
+ registerFinalizers(app);
26
+
27
+ // Graceful shutdown
28
+ process.on('SIGTERM', async () => {
29
+ console.log('SIGTERM received, shutting down gracefully...');
30
+ await app.close();
31
+ process.exit(0);
32
+ });
33
+
34
+ process.on('SIGINT', async () => {
35
+ console.log('SIGINT received, shutting down gracefully...');
36
+ await app.close();
37
+ process.exit(0);
38
+ });
39
+
40
+ // Start server
41
+ app.listen(config.port, () => {
42
+ console.log(`🔥 Filament server running on http://localhost:${config.port}`);
43
+ console.log(` Environment: ${config.nodeEnv}`);
44
+ console.log(` Log level: ${config.logLevel}`);
45
+ });
@@ -0,0 +1,28 @@
1
+ import { AppMeta } from './index.js';
2
+
3
+ /**
4
+ * Default metadata for all endpoints
5
+ *
6
+ * Individual endpoints can override these values with Partial<AppMeta>
7
+ */
8
+ export const defaultMeta: AppMeta = {
9
+ requiresAuth: false,
10
+ rateLimit: 100,
11
+ logging: {
12
+ level: 'info',
13
+ },
14
+ tags: [],
15
+ };
16
+
17
+ /**
18
+ * Common metadata presets for convenience
19
+ */
20
+ export const PUBLIC: Partial<AppMeta> = {
21
+ requiresAuth: false,
22
+ rateLimit: 100,
23
+ };
24
+
25
+ export const AUTHENTICATED: Partial<AppMeta> = {
26
+ requiresAuth: true,
27
+ rateLimit: 50,
28
+ };
@@ -0,0 +1,50 @@
1
+ import { FrameworkMeta } from 'filamentjs';
2
+
3
+ /**
4
+ * Application metadata interface
5
+ *
6
+ * Extend this interface to add your own metadata properties.
7
+ * Middleware can inspect req.endpointMeta to make decisions.
8
+ */
9
+ export interface AppMeta extends FrameworkMeta {
10
+ /**
11
+ * Whether this endpoint requires authentication
12
+ */
13
+ requiresAuth: boolean;
14
+
15
+ /**
16
+ * Required role for this endpoint
17
+ */
18
+ role?: 'admin' | 'user';
19
+
20
+ /**
21
+ * Whether this endpoint requires a session
22
+ */
23
+ requiresSession: boolean;
24
+
25
+ /**
26
+ * Rate limit for this endpoint (requests per minute)
27
+ */
28
+ rateLimit: number;
29
+
30
+ /**
31
+ * Logging configuration
32
+ */
33
+ logging: {
34
+ level: 'debug' | 'info' | 'warn' | 'error';
35
+ };
36
+
37
+ /**
38
+ * Tags for categorizing endpoints
39
+ */
40
+ tags: string[];
41
+
42
+ /**
43
+ * OpenAPI documentation
44
+ */
45
+ openapi?: {
46
+ summary: string;
47
+ description?: string;
48
+ tags?: string[];
49
+ };
50
+ }
@@ -0,0 +1,36 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ transport: {
8
+ target: 'pino-pretty',
9
+ options: {
10
+ colorize: true,
11
+ },
12
+ },
13
+ });
14
+
15
+ /**
16
+ * Register all middleware
17
+ */
18
+ export function registerMiddleware(app: Application<AppMeta>) {
19
+ // Request logging middleware
20
+ app.use(async (req, res, next) => {
21
+ const level = req.endpointMeta.logging.level;
22
+
23
+ if (level === 'debug' || level === 'info') {
24
+ logger.info({
25
+ method: req.method,
26
+ path: req.path,
27
+ event: 'request.start',
28
+ });
29
+ }
30
+
31
+ await next();
32
+ });
33
+
34
+ // Add more middleware here
35
+ // Example: Authentication, rate limiting, etc.
36
+ }
@@ -0,0 +1,26 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import { PUBLIC } from '../meta/defaults.js';
4
+
5
+ /**
6
+ * Register all routes
7
+ */
8
+ export function registerRoutes(app: Application<AppMeta>) {
9
+ // Health check endpoint
10
+ app.get('/health', PUBLIC, async (req, res) => {
11
+ res.json({
12
+ status: 'healthy',
13
+ timestamp: new Date().toISOString(),
14
+ });
15
+ });
16
+
17
+ // Example endpoint
18
+ app.get('/', PUBLIC, async (req, res) => {
19
+ res.json({
20
+ message: 'Welcome to your Filament API',
21
+ endpoints: {
22
+ health: 'GET /health',
23
+ },
24
+ });
25
+ });
26
+ }
@@ -0,0 +1,20 @@
1
+ import { suite, it, before, after } from 'node:test';
2
+ import { TestBattery } from 'test-battery';
3
+
4
+ suite('Example Test', () => {
5
+ before(() => {
6
+ // Setup code here
7
+ });
8
+
9
+ after(() => {
10
+ // Cleanup code here
11
+ });
12
+
13
+ TestBattery.test('should pass', (battery) => {
14
+ battery.test('1 + 1 = 2').value(1 + 1).value(2).equal;
15
+ });
16
+
17
+ TestBattery.test('should work with async', async (battery) => {
18
+ battery.test('result = 42').value(Promise.resolve(42)).value(42).equal;
19
+ });
20
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Application configuration
3
+ */
4
+
5
+ export const config = {
6
+ port: parseInt(process.env.PORT || '3000', 10),
7
+ nodeEnv: process.env.NODE_ENV || 'development',
8
+ logLevel: process.env.LOG_LEVEL || 'info',
9
+ };
10
+
11
+ /**
12
+ * Validate required environment variables
13
+ */
14
+ export function validateConfig() {
15
+ // Add validation for required env vars here
16
+ return true;
17
+ }
@@ -0,0 +1,32 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ });
8
+
9
+ /**
10
+ * Register error handlers
11
+ */
12
+ export function registerErrorHandlers(app: Application<AppMeta>) {
13
+ app.onError(async (err, req, res) => {
14
+ const level = req.endpointMeta.logging.level;
15
+
16
+ if (level === 'debug' || level === 'error') {
17
+ logger.error({
18
+ error: err.message,
19
+ stack: err.stack,
20
+ method: req.method,
21
+ path: req.path,
22
+ });
23
+ }
24
+
25
+ if (!res.headersSent) {
26
+ res.status(500).json({
27
+ error: 'Internal Server Error',
28
+ message: process.env.NODE_ENV === 'development' ? err.message : undefined,
29
+ });
30
+ }
31
+ });
32
+ }
@@ -0,0 +1,27 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ });
8
+
9
+ /**
10
+ * Register finalizers (always run)
11
+ */
12
+ export function registerFinalizers(app: Application<AppMeta>) {
13
+ app.onFinalize(async (req, res) => {
14
+ const duration = Date.now() - (req._startTime || Date.now());
15
+ const level = req.endpointMeta.logging.level;
16
+
17
+ if (level === 'debug' || level === 'info') {
18
+ logger.info({
19
+ method: req.method,
20
+ path: req.path,
21
+ status: res.statusCode,
22
+ duration,
23
+ event: 'request.complete',
24
+ });
25
+ }
26
+ });
27
+ }
@@ -0,0 +1,18 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+
4
+ /**
5
+ * Register response transformers
6
+ */
7
+ export function registerTransformers(app: Application<AppMeta>) {
8
+ // Add custom headers based on tags
9
+ app.onTransform(async (req, res) => {
10
+ const tags = req.endpointMeta.tags;
11
+
12
+ if (tags.includes('api')) {
13
+ res.setHeader('X-API-Version', '1.0');
14
+ }
15
+
16
+ // Add more transformations here
17
+ });
18
+ }
@@ -0,0 +1,45 @@
1
+ import { createApp } from 'filamentjs';
2
+ import { defaultMeta } from './meta/defaults.js';
3
+ import { config, validateConfig } from './config/app.js';
4
+ import { registerMiddleware } from './middleware/index.js';
5
+ import { registerRoutes } from './routes/index.js';
6
+ import { registerErrorHandlers } from './handlers/errors.js';
7
+ import { registerTransformers } from './handlers/transforms.js';
8
+ import { registerFinalizers } from './handlers/finalizers.js';
9
+
10
+ // Validate configuration
11
+ validateConfig();
12
+
13
+ // Create Filament application
14
+ const app = createApp(defaultMeta);
15
+
16
+ // Register middleware
17
+ registerMiddleware(app);
18
+
19
+ // Register routes
20
+ registerRoutes(app);
21
+
22
+ // Register post-request handlers
23
+ registerErrorHandlers(app);
24
+ registerTransformers(app);
25
+ registerFinalizers(app);
26
+
27
+ // Graceful shutdown
28
+ process.on('SIGTERM', async () => {
29
+ console.log('SIGTERM received, shutting down gracefully...');
30
+ await app.close();
31
+ process.exit(0);
32
+ });
33
+
34
+ process.on('SIGINT', async () => {
35
+ console.log('SIGINT received, shutting down gracefully...');
36
+ await app.close();
37
+ process.exit(0);
38
+ });
39
+
40
+ // Start server
41
+ app.listen(config.port, () => {
42
+ console.log(`🔥 Filament server running on http://localhost:${config.port}`);
43
+ console.log(` Environment: ${config.nodeEnv}`);
44
+ console.log(` Log level: ${config.logLevel}`);
45
+ });
@@ -0,0 +1,28 @@
1
+ import { AppMeta } from './index.js';
2
+
3
+ /**
4
+ * Default metadata for all endpoints
5
+ *
6
+ * Individual endpoints can override these values with Partial<AppMeta>
7
+ */
8
+ export const defaultMeta: AppMeta = {
9
+ requiresAuth: false,
10
+ rateLimit: 100,
11
+ logging: {
12
+ level: 'info',
13
+ },
14
+ tags: [],
15
+ };
16
+
17
+ /**
18
+ * Common metadata presets for convenience
19
+ */
20
+ export const PUBLIC: Partial<AppMeta> = {
21
+ requiresAuth: false,
22
+ rateLimit: 100,
23
+ };
24
+
25
+ export const AUTHENTICATED: Partial<AppMeta> = {
26
+ requiresAuth: true,
27
+ rateLimit: 50,
28
+ };
@@ -0,0 +1,31 @@
1
+ import { FrameworkMeta } from 'filamentjs';
2
+
3
+ /**
4
+ * Application metadata interface
5
+ *
6
+ * Extend this interface to add your own metadata properties.
7
+ * Middleware can inspect req.endpointMeta to make decisions.
8
+ */
9
+ export interface AppMeta extends FrameworkMeta {
10
+ /**
11
+ * Whether this endpoint requires authentication
12
+ */
13
+ requiresAuth: boolean;
14
+
15
+ /**
16
+ * Rate limit for this endpoint (requests per minute)
17
+ */
18
+ rateLimit: number;
19
+
20
+ /**
21
+ * Logging configuration
22
+ */
23
+ logging: {
24
+ level: 'debug' | 'info' | 'warn' | 'error';
25
+ };
26
+
27
+ /**
28
+ * Tags for categorizing endpoints
29
+ */
30
+ tags: string[];
31
+ }
@@ -0,0 +1,36 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import pino from 'pino';
4
+
5
+ const logger = pino({
6
+ level: process.env.LOG_LEVEL || 'info',
7
+ transport: {
8
+ target: 'pino-pretty',
9
+ options: {
10
+ colorize: true,
11
+ },
12
+ },
13
+ });
14
+
15
+ /**
16
+ * Register all middleware
17
+ */
18
+ export function registerMiddleware(app: Application<AppMeta>) {
19
+ // Request logging middleware
20
+ app.use(async (req, res, next) => {
21
+ const level = req.endpointMeta.logging.level;
22
+
23
+ if (level === 'debug' || level === 'info') {
24
+ logger.info({
25
+ method: req.method,
26
+ path: req.path,
27
+ event: 'request.start',
28
+ });
29
+ }
30
+
31
+ await next();
32
+ });
33
+
34
+ // Add more middleware here
35
+ // Example: Authentication, rate limiting, etc.
36
+ }
@@ -0,0 +1,26 @@
1
+ import { Application } from 'filamentjs';
2
+ import { AppMeta } from '../meta/index.js';
3
+ import { PUBLIC } from '../meta/defaults.js';
4
+
5
+ /**
6
+ * Register all routes
7
+ */
8
+ export function registerRoutes(app: Application<AppMeta>) {
9
+ // Health check endpoint
10
+ app.get('/health', PUBLIC, async (req, res) => {
11
+ res.json({
12
+ status: 'healthy',
13
+ timestamp: new Date().toISOString(),
14
+ });
15
+ });
16
+
17
+ // Example endpoint
18
+ app.get('/', PUBLIC, async (req, res) => {
19
+ res.json({
20
+ message: 'Welcome to your Filament API',
21
+ endpoints: {
22
+ health: 'GET /health',
23
+ },
24
+ });
25
+ });
26
+ }
@@ -0,0 +1,20 @@
1
+ import { suite, it, before, after } from 'node:test';
2
+ import { TestBattery } from 'test-battery';
3
+
4
+ suite('Example Test', () => {
5
+ before(() => {
6
+ // Setup code here
7
+ });
8
+
9
+ after(() => {
10
+ // Cleanup code here
11
+ });
12
+
13
+ TestBattery.test('should pass', (battery) => {
14
+ battery.test('1 + 1 = 2').value(1 + 1).value(2).equal;
15
+ });
16
+
17
+ TestBattery.test('should work with async', async (battery) => {
18
+ battery.test('result = 42').value(Promise.resolve(42)).value(42).equal;
19
+ });
20
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Application configuration
3
+ */
4
+
5
+ export const config = {
6
+ port: parseInt(process.env.PORT || '3000', 10),
7
+ nodeEnv: process.env.NODE_ENV || 'development',
8
+ logLevel: process.env.LOG_LEVEL || 'info',
9
+ };
10
+
11
+ /**
12
+ * Validate required environment variables
13
+ */
14
+ export function validateConfig() {
15
+ // Add validation for required env vars here
16
+ return true;
17
+ }