create-celsian 0.2.0 → 0.3.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ThenJS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.js CHANGED
@@ -1,37 +1,37 @@
1
1
  #!/usr/bin/env node
2
2
  // create-celsian — Project scaffolder
3
3
  // Zero external dependencies. Interactive prompts via raw stdin.
4
- import { mkdirSync, writeFileSync } from 'node:fs';
5
- import { join, dirname, basename, isAbsolute } from 'node:path';
6
- import { createInterface } from 'node:readline';
7
- import { basicTemplate } from './templates/basic.js';
8
- import { restApiTemplate } from './templates/rest-api.js';
9
- import { rpcApiTemplate } from './templates/rpc-api.js';
10
- import { fullTemplate } from './templates/full.js';
4
+ import { mkdirSync, writeFileSync } from "node:fs";
5
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
6
+ import { createInterface } from "node:readline";
7
+ import { basicTemplate } from "./templates/basic.js";
8
+ import { fullTemplate } from "./templates/full.js";
9
+ import { restApiTemplate } from "./templates/rest-api.js";
10
+ import { rpcApiTemplate } from "./templates/rpc-api.js";
11
11
  // ─── Template Registry ───
12
12
  const templates = {
13
13
  full: fullTemplate,
14
14
  basic: basicTemplate,
15
- 'rest-api': restApiTemplate,
16
- 'rpc-api': rpcApiTemplate,
15
+ "rest-api": restApiTemplate,
16
+ "rpc-api": rpcApiTemplate,
17
17
  };
18
18
  const templateDescriptions = {
19
- full: 'Full-stack API with auth, CRUD, RPC, tasks, cron, OpenAPI, Docker',
20
- basic: 'Minimal API server',
21
- 'rest-api': 'REST API with TypeBox schemas',
22
- 'rpc-api': 'RPC-first with typed client',
19
+ full: "Full-stack API with auth, CRUD, RPC, tasks, cron, OpenAPI, Docker",
20
+ basic: "Minimal API server",
21
+ "rest-api": "REST API with TypeBox schemas",
22
+ "rpc-api": "RPC-first with typed client",
23
23
  };
24
24
  // ─── CLI Argument Parsing ───
25
25
  const args = process.argv.slice(2);
26
26
  // Handle --help
27
- if (args.includes('--help') || args.includes('-h')) {
27
+ if (args.includes("--help") || args.includes("-h")) {
28
28
  printUsage();
29
29
  process.exit(0);
30
30
  }
31
31
  // Extract flags
32
- const templateFlag = args.indexOf('--template');
32
+ const templateFlag = args.indexOf("--template");
33
33
  const templateArg = templateFlag !== -1 ? args[templateFlag + 1] : undefined;
34
- const nameArg = args.find(a => !a.startsWith('--') && (templateFlag === -1 || args.indexOf(a) !== templateFlag + 1));
34
+ const nameArg = args.find((a) => !a.startsWith("--") && (templateFlag === -1 || args.indexOf(a) !== templateFlag + 1));
35
35
  // ─── Interactive Mode ───
36
36
  async function prompt(question, defaultValue) {
37
37
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -43,29 +43,29 @@ async function prompt(question, defaultValue) {
43
43
  });
44
44
  }
45
45
  function detectPackageManager() {
46
- const userAgent = process.env.npm_config_user_agent ?? '';
47
- if (userAgent.startsWith('pnpm'))
48
- return 'pnpm';
49
- if (userAgent.startsWith('bun'))
50
- return 'bun';
51
- return 'npm';
46
+ const userAgent = process.env.npm_config_user_agent ?? "";
47
+ if (userAgent.startsWith("pnpm"))
48
+ return "pnpm";
49
+ if (userAgent.startsWith("bun"))
50
+ return "bun";
51
+ return "npm";
52
52
  }
53
53
  async function interactiveMode() {
54
- console.log('');
55
- console.log(' Create a new Celsian project');
56
- console.log(' ────────────────────────────');
57
- console.log('');
58
- const name = await prompt('Project name', 'my-celsian-app');
59
- console.log('');
60
- console.log(' Available templates:');
54
+ console.log("");
55
+ console.log(" Create a new Celsian project");
56
+ console.log(" ────────────────────────────");
57
+ console.log("");
58
+ const name = await prompt("Project name", "my-celsian-app");
59
+ console.log("");
60
+ console.log(" Available templates:");
61
61
  for (const [key, desc] of Object.entries(templateDescriptions)) {
62
- const marker = key === 'full' ? ' (recommended)' : '';
62
+ const marker = key === "full" ? " (recommended)" : "";
63
63
  console.log(` ${key.padEnd(12)} ${desc}${marker}`);
64
64
  }
65
- console.log('');
66
- const template = await prompt('Template', 'full');
65
+ console.log("");
66
+ const template = await prompt("Template", "full");
67
67
  const detected = detectPackageManager();
68
- const pm = await prompt('Package manager', detected);
68
+ const pm = await prompt("Package manager", detected);
69
69
  return { name, template, pm };
70
70
  }
71
71
  // ─── Scaffold ───
@@ -73,14 +73,26 @@ function scaffold(name, template, pm) {
73
73
  const files = templates[template];
74
74
  if (!files) {
75
75
  console.error(`\n Unknown template: ${template}`);
76
- console.error(` Available: ${Object.keys(templates).join(', ')}\n`);
76
+ console.error(` Available: ${Object.keys(templates).join(", ")}\n`);
77
+ process.exit(1);
78
+ }
79
+ // Sanitize: reject names containing path traversal
80
+ if (name.includes("..")) {
81
+ console.error("\n Invalid project name: must not contain '..'.\n");
82
+ process.exit(1);
83
+ }
84
+ const cwd = process.cwd();
85
+ const dir = isAbsolute(name) ? name : join(cwd, name);
86
+ const resolved = resolve(dir);
87
+ // Ensure the resolved path is a child of cwd
88
+ if (!resolved.startsWith(cwd + "/") && resolved !== cwd) {
89
+ console.error("\n Invalid project name: resolved path must be inside the current directory.\n");
77
90
  process.exit(1);
78
91
  }
79
- const dir = isAbsolute(name) ? name : join(process.cwd(), name);
80
92
  const projectName = basename(dir);
81
93
  console.log(`\n Creating Celsian project: ${projectName}`);
82
94
  console.log(` Template: ${template}`);
83
- console.log('');
95
+ console.log("");
84
96
  for (const [filePath, content] of Object.entries(files)) {
85
97
  const fullPath = join(dir, filePath);
86
98
  const fileDir = dirname(fullPath);
@@ -88,26 +100,26 @@ function scaffold(name, template, pm) {
88
100
  writeFileSync(fullPath, content.replace(/\{\{name\}\}/g, projectName));
89
101
  console.log(` + ${filePath}`);
90
102
  }
91
- const install = pm === 'npm' ? 'npm install' : `${pm} install`;
92
- const dev = pm === 'npm' ? 'npm run dev' : `${pm} run dev`;
103
+ const install = pm === "npm" ? "npm install" : `${pm} install`;
104
+ const dev = pm === "npm" ? "npm run dev" : `${pm} run dev`;
93
105
  console.log(`\n Done! Next steps:\n`);
94
106
  console.log(` cd ${projectName}`);
95
107
  console.log(` ${install}`);
96
- if (template === 'full') {
97
- console.log(' cp .env.example .env');
108
+ if (template === "full") {
109
+ console.log(" cp .env.example .env");
98
110
  }
99
111
  console.log(` ${dev}`);
100
- if (template === 'full') {
101
- console.log('');
102
- console.log(' Open http://localhost:3000/docs for API documentation');
112
+ if (template === "full") {
113
+ console.log("");
114
+ console.log(" Open http://localhost:3000/docs for API documentation");
103
115
  }
104
- console.log('');
116
+ console.log("");
105
117
  }
106
118
  // ─── Main ───
107
119
  async function main() {
108
120
  // If both name and template are provided via CLI args, skip interactive mode
109
121
  if (nameArg) {
110
- const template = templateArg ?? 'full';
122
+ const template = templateArg ?? "full";
111
123
  const pm = detectPackageManager();
112
124
  scaffold(nameArg, template, pm);
113
125
  return;
@@ -124,17 +136,17 @@ async function main() {
124
136
  }
125
137
  }
126
138
  function printUsage() {
127
- console.log('');
128
- console.log(' Usage: create-celsian <project-name> [--template full|basic|rest-api|rpc-api]');
129
- console.log('');
130
- console.log(' Templates:');
139
+ console.log("");
140
+ console.log(" Usage: create-celsian <project-name> [--template full|basic|rest-api|rpc-api]");
141
+ console.log("");
142
+ console.log(" Templates:");
131
143
  for (const [key, desc] of Object.entries(templateDescriptions)) {
132
- const defaultMarker = key === 'full' ? ' (default)' : '';
144
+ const defaultMarker = key === "full" ? " (default)" : "";
133
145
  console.log(` ${key.padEnd(12)} ${desc}${defaultMarker}`);
134
146
  }
135
- console.log('');
136
- console.log(' Run without arguments for interactive mode.');
137
- console.log('');
147
+ console.log("");
148
+ console.log(" Run without arguments for interactive mode.");
149
+ console.log("");
138
150
  }
139
151
  main().catch((err) => {
140
152
  console.error(err);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export declare const basicTemplate: {
2
- 'package.json': string;
3
- 'tsconfig.json': string;
4
- 'src/index.ts': string;
2
+ "package.json": string;
3
+ "tsconfig.json": string;
4
+ "src/index.ts": string;
5
5
  };
6
6
  //# sourceMappingURL=basic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"basic.d.ts","sourceRoot":"","sources":["../../src/templates/basic.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;CAqDzB,CAAC"}
1
+ {"version":3,"file":"basic.d.ts","sourceRoot":"","sources":["../../src/templates/basic.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;CAsEzB,CAAC"}
@@ -1,38 +1,55 @@
1
1
  export const basicTemplate = {
2
- 'package.json': JSON.stringify({
3
- name: '{{name}}',
4
- version: '0.0.1',
5
- type: 'module',
2
+ "package.json": JSON.stringify({
3
+ name: "{{name}}",
4
+ version: "0.0.1",
5
+ type: "module",
6
6
  scripts: {
7
- dev: 'npx celsian dev',
8
- build: 'tsc',
9
- start: 'node dist/index.js',
7
+ dev: "npx tsx --watch src/index.ts",
8
+ build: "tsc",
9
+ start: "node dist/index.js",
10
10
  },
11
11
  dependencies: {
12
- celsian: '^0.1.0',
12
+ celsian: "latest",
13
13
  },
14
14
  devDependencies: {
15
- typescript: '^5.7.0',
16
- tsx: '^4.0.0',
15
+ typescript: "^5.7.0",
16
+ tsx: "^4.0.0",
17
17
  },
18
18
  }, null, 2),
19
- 'tsconfig.json': JSON.stringify({
19
+ "tsconfig.json": JSON.stringify({
20
20
  compilerOptions: {
21
- target: 'ES2022',
22
- module: 'ESNext',
23
- moduleResolution: 'bundler',
21
+ target: "ES2022",
22
+ module: "ESNext",
23
+ moduleResolution: "bundler",
24
24
  strict: true,
25
25
  esModuleInterop: true,
26
26
  skipLibCheck: true,
27
- outDir: 'dist',
28
- rootDir: 'src',
27
+ outDir: "dist",
28
+ rootDir: "src",
29
29
  },
30
- include: ['src'],
30
+ include: ["src"],
31
31
  }, null, 2),
32
- 'src/index.ts': `import { createApp, serve } from 'celsian';
32
+ "src/index.ts": `import { createApp, serve, cors, security } from 'celsian';
33
33
 
34
34
  const app = createApp();
35
35
 
36
+ // ─── Security (CORS + security headers) ───
37
+
38
+ const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:3000';
39
+
40
+ await app.register(cors({
41
+ origin: CORS_ORIGIN,
42
+ credentials: true,
43
+ maxAge: 86400,
44
+ }));
45
+
46
+ await app.register(security({
47
+ hsts: { maxAge: 31536000, includeSubDomains: true },
48
+ referrerPolicy: 'strict-origin-when-cross-origin',
49
+ }));
50
+
51
+ // ─── Routes ───
52
+
36
53
  app.get('/health', (req, reply) => {
37
54
  return reply.json({ status: 'ok', timestamp: new Date().toISOString() });
38
55
  });
@@ -1 +1 @@
1
- {"version":3,"file":"basic.js","sourceRoot":"","sources":["../../src/templates/basic.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,iBAAiB;YACtB,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;SAClB;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;CAajB;CACA,CAAC"}
1
+ {"version":3,"file":"basic.js","sourceRoot":"","sources":["../../src/templates/basic.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,8BAA8B;YACnC,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;SAClB;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BjB;CACA,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"full.d.ts","sourceRoot":"","sources":["../../src/templates/full.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA23B/C,CAAC"}
1
+ {"version":3,"file":"full.d.ts","sourceRoot":"","sources":["../../src/templates/full.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAg4B/C,CAAC"}
@@ -1,37 +1,37 @@
1
1
  export const fullTemplate = {
2
- 'package.json': JSON.stringify({
3
- name: '{{name}}',
4
- version: '0.1.0',
5
- type: 'module',
2
+ "package.json": JSON.stringify({
3
+ name: "{{name}}",
4
+ version: "0.1.0",
5
+ type: "module",
6
6
  scripts: {
7
- dev: 'npx tsx --watch src/index.ts',
8
- build: 'tsc',
9
- start: 'node dist/index.js',
10
- test: 'npx vitest run',
11
- lint: 'npx tsc --noEmit',
7
+ dev: "npx tsx --watch src/index.ts",
8
+ build: "tsc",
9
+ start: "node dist/index.js",
10
+ test: "npx vitest run",
11
+ lint: "npx tsc --noEmit",
12
12
  },
13
13
  dependencies: {
14
- celsian: '^0.2.0',
15
- '@celsian/core': '^0.2.0',
16
- '@celsian/jwt': '^0.2.0',
17
- '@celsian/rpc': '^0.2.0',
18
- '@celsian/rate-limit': '^0.2.0',
19
- '@sinclair/typebox': '^0.34.0',
14
+ celsian: "latest",
15
+ "@celsian/core": "latest",
16
+ "@celsian/jwt": "latest",
17
+ "@celsian/rpc": "latest",
18
+ "@celsian/rate-limit": "latest",
19
+ "@sinclair/typebox": "^0.34.0",
20
20
  },
21
21
  devDependencies: {
22
- typescript: '^5.7.0',
23
- tsx: '^4.0.0',
24
- vitest: '^3.0.0',
25
- '@types/node': '^22.0.0',
22
+ typescript: "^5.7.0",
23
+ tsx: "^4.0.0",
24
+ vitest: "^3.0.0",
25
+ "@types/node": "^22.0.0",
26
26
  },
27
27
  }, null, 2),
28
- 'tsconfig.json': JSON.stringify({
28
+ "tsconfig.json": JSON.stringify({
29
29
  compilerOptions: {
30
- target: 'ES2022',
31
- module: 'ESNext',
32
- moduleResolution: 'bundler',
33
- lib: ['ES2022'],
34
- types: ['node'],
30
+ target: "ES2022",
31
+ module: "ESNext",
32
+ moduleResolution: "bundler",
33
+ lib: ["ES2022"],
34
+ types: ["node"],
35
35
  strict: true,
36
36
  esModuleInterop: true,
37
37
  skipLibCheck: true,
@@ -39,15 +39,15 @@ export const fullTemplate = {
39
39
  resolveJsonModule: true,
40
40
  isolatedModules: true,
41
41
  declaration: true,
42
- outDir: 'dist',
43
- rootDir: 'src',
42
+ outDir: "dist",
43
+ rootDir: "src",
44
44
  },
45
- include: ['src'],
45
+ include: ["src"],
46
46
  }, null, 2),
47
- '.env.example': `# Server
47
+ ".env.example": `# Server
48
48
  PORT=3000
49
49
  HOST=0.0.0.0
50
- CORS_ORIGIN=*
50
+ CORS_ORIGIN=http://localhost:3000
51
51
 
52
52
  # Auth
53
53
  JWT_SECRET=change-me-to-a-real-secret-at-least-32-chars
@@ -58,14 +58,14 @@ DATABASE_URL=file:./data.db
58
58
  # Environment
59
59
  NODE_ENV=development
60
60
  `,
61
- '.gitignore': `node_modules/
61
+ ".gitignore": `node_modules/
62
62
  dist/
63
63
  *.tsbuildinfo
64
64
  .env
65
65
  data.db
66
66
  `,
67
67
  // ─── src/types.ts ───
68
- 'src/types.ts': `// Shared types for {{name}}
68
+ "src/types.ts": `// Shared types for {{name}}
69
69
 
70
70
  export interface User {
71
71
  id: string;
@@ -98,7 +98,7 @@ export interface JWTPayload {
98
98
  }
99
99
  `,
100
100
  // ─── src/plugins/database.ts ───
101
- 'src/plugins/database.ts': `// Database module — in-memory store for development
101
+ "src/plugins/database.ts": `// Database module — in-memory store for development
102
102
  // Replace with a real database (PostgreSQL, SQLite, etc.) for production
103
103
 
104
104
  import type { User, Session } from '../types.js';
@@ -133,7 +133,7 @@ const demoUser: User = {
133
133
  db.users.set(demoUser.id, demoUser);
134
134
  `,
135
135
  // ─── src/plugins/auth.ts ───
136
- 'src/plugins/auth.ts': `// JWT auth plugin — guards protected routes via Bearer token
136
+ "src/plugins/auth.ts": `// JWT auth plugin — guards protected routes via Bearer token
137
137
  // Uses @celsian/jwt under the hood
138
138
 
139
139
  import { jwt, createJWTGuard } from '@celsian/jwt';
@@ -141,6 +141,15 @@ import type { PluginFunction, HookHandler } from '@celsian/core';
141
141
 
142
142
  const JWT_SECRET = process.env.JWT_SECRET ?? 'dev-secret-change-me';
143
143
 
144
+ // Refuse to start in production with the default dev secret
145
+ if (process.env.NODE_ENV === 'production' && JWT_SECRET === 'dev-secret-change-me') {
146
+ throw new Error(
147
+ '[celsian] FATAL: JWT_SECRET is set to the default dev value. ' +
148
+ 'Set a strong, unique JWT_SECRET environment variable before running in production. ' +
149
+ 'Generate one with: node -e "console.log(require(\\'crypto\\').randomBytes(32).toString(\\'base64\\'))"'
150
+ );
151
+ }
152
+
144
153
  /**
145
154
  * Register the JWT plugin. After this, \`app.jwt\` is available for
146
155
  * signing and verifying tokens.
@@ -158,19 +167,30 @@ export const requireAuth: HookHandler = createJWTGuard({
158
167
  });
159
168
  `,
160
169
  // ─── src/plugins/security.ts ───
161
- 'src/plugins/security.ts': `// Security plugin — CORS + CSRF + security headers + rate limiting
170
+ "src/plugins/security.ts": `// Security plugin — CORS + CSRF + security headers + rate limiting
162
171
  // Combines multiple @celsian/core plugins into a single registration
163
172
 
164
173
  import { cors, security, csrf } from '@celsian/core';
165
174
  import { rateLimit } from '@celsian/rate-limit';
166
175
  import type { PluginFunction } from '@celsian/core';
167
176
 
168
- const CORS_ORIGIN = process.env.CORS_ORIGIN ?? '*';
177
+ const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:3000';
169
178
 
170
179
  /**
171
180
  * Register all security-related plugins in one call.
172
181
  */
173
182
  export function securityPlugins(): PluginFunction[] {
183
+ // WARNING: credentials:true is incompatible with origin:'*'.
184
+ // Browsers will reject Set-Cookie headers when the CORS origin is a wildcard.
185
+ // Always set CORS_ORIGIN to a specific origin (e.g. 'http://localhost:3000')
186
+ // when credentials:true is enabled.
187
+ if (CORS_ORIGIN === '*') {
188
+ console.warn(
189
+ '[celsian] WARNING: CORS_ORIGIN=* with credentials:true is insecure and will not work in browsers. ' +
190
+ 'Set CORS_ORIGIN to a specific origin.'
191
+ );
192
+ }
193
+
174
194
  return [
175
195
  // CORS — allow cross-origin requests
176
196
  cors({
@@ -201,7 +221,7 @@ export function securityPlugins(): PluginFunction[] {
201
221
  }
202
222
  `,
203
223
  // ─── src/routes/health.ts ───
204
- 'src/routes/health.ts': `// Health check route — GET /health
224
+ "src/routes/health.ts": `// Health check route — GET /health
205
225
  // Returns server status and uptime for load balancers and monitoring
206
226
 
207
227
  import type { PluginFunction } from '@celsian/core';
@@ -223,12 +243,12 @@ export default function healthRoutes(): PluginFunction {
223
243
  }
224
244
  `,
225
245
  // ─── src/routes/users.ts ───
226
- 'src/routes/users.ts': `// User CRUD routes — /users
246
+ "src/routes/users.ts": `// User CRUD routes — /users
227
247
  // Full REST: GET (list), POST (create), GET/:id, PUT/:id, DELETE/:id
228
248
 
229
249
  import { Type } from '@sinclair/typebox';
230
- import type { PluginFunction, CelsianRequest, CelsianReply } from '@celsian/core';
231
- import type { User, CreateUserInput, UpdateUserInput } from '../types.js';
250
+ import type { PluginFunction } from '@celsian/core';
251
+ import type { User } from '../types.js';
232
252
  import { db } from '../plugins/database.js';
233
253
  import { requireAuth } from '../plugins/auth.js';
234
254
 
@@ -250,22 +270,19 @@ export default function userRoutes(): PluginFunction {
250
270
  return reply.json(allUsers);
251
271
  });
252
272
 
253
- // POST /users — create a new user
254
- app.route({
255
- method: 'POST',
256
- url: '/users',
273
+ // POST /users — create a new user (typed body from schema)
274
+ app.post('/users', {
257
275
  schema: { body: CreateUserSchema },
258
- handler(req: CelsianRequest, reply: CelsianReply) {
259
- const { name, email } = req.parsedBody as CreateUserInput;
260
- const user: User = {
261
- id: db.generateId(),
262
- name,
263
- email,
264
- createdAt: new Date().toISOString(),
265
- };
266
- db.users.set(user.id, user);
267
- return reply.status(201).json(user);
268
- },
276
+ }, (req, reply) => {
277
+ const { name, email } = req.parsedBody;
278
+ const user: User = {
279
+ id: db.generateId(),
280
+ name,
281
+ email,
282
+ createdAt: new Date().toISOString(),
283
+ };
284
+ db.users.set(user.id, user);
285
+ return reply.status(201).json(user);
269
286
  });
270
287
 
271
288
  // GET /users/:id — get a single user
@@ -275,21 +292,18 @@ export default function userRoutes(): PluginFunction {
275
292
  return reply.json(user);
276
293
  });
277
294
 
278
- // PUT /users/:id — update a user (protected)
279
- app.route({
280
- method: 'PUT',
281
- url: '/users/:id',
295
+ // PUT /users/:id — update a user (protected, typed body from schema)
296
+ app.put('/users/:id', {
282
297
  schema: { body: UpdateUserSchema },
283
298
  onRequest: requireAuth,
284
- handler(req: CelsianRequest, reply: CelsianReply) {
285
- const user = db.users.get(req.params.id);
286
- if (!user) return reply.status(404).json({ error: 'User not found' });
287
- const updates = req.parsedBody as UpdateUserInput;
288
- if (updates.name !== undefined) user.name = updates.name;
289
- if (updates.email !== undefined) user.email = updates.email;
290
- db.users.set(user.id, user);
291
- return reply.json(user);
292
- },
299
+ }, (req, reply) => {
300
+ const user = db.users.get(req.params.id);
301
+ if (!user) return reply.status(404).json({ error: 'User not found' });
302
+ const updates = req.parsedBody;
303
+ if (updates.name !== undefined) user.name = updates.name;
304
+ if (updates.email !== undefined) user.email = updates.email;
305
+ db.users.set(user.id, user);
306
+ return reply.json(user);
293
307
  });
294
308
 
295
309
  // DELETE /users/:id — delete a user (protected)
@@ -307,7 +321,7 @@ export default function userRoutes(): PluginFunction {
307
321
  }
308
322
  `,
309
323
  // ─── src/routes/rpc.ts ───
310
- 'src/routes/rpc.ts': `// RPC endpoint — type-safe procedures at /_rpc/*
324
+ "src/routes/rpc.ts": `// RPC endpoint — type-safe procedures at /_rpc/*
311
325
  // Demonstrates queries and mutations with typed schemas
312
326
 
313
327
  import { procedure, router, RPCHandler } from '@celsian/rpc';
@@ -318,24 +332,21 @@ import type { PluginFunction } from '@celsian/core';
318
332
  const appRouter = router({
319
333
  greeting: {
320
334
  hello: procedure
321
- .input(Type.Object({ name: Type.String() }))
335
+ .input<{ name: string }>(Type.Object({ name: Type.String() }))
322
336
  .query(({ input }) => {
323
- const { name } = input as { name: string };
324
- return { message: \`Hello, \${name}!\` };
337
+ return { message: \`Hello, \${input.name}!\` };
325
338
  }),
326
339
  },
327
340
  math: {
328
341
  add: procedure
329
- .input(Type.Object({ a: Type.Number(), b: Type.Number() }))
342
+ .input<{ a: number; b: number }>(Type.Object({ a: Type.Number(), b: Type.Number() }))
330
343
  .query(({ input }) => {
331
- const { a, b } = input as { a: number; b: number };
332
- return { result: a + b };
344
+ return { result: input.a + input.b };
333
345
  }),
334
346
  multiply: procedure
335
- .input(Type.Object({ a: Type.Number(), b: Type.Number() }))
347
+ .input<{ a: number; b: number }>(Type.Object({ a: Type.Number(), b: Type.Number() }))
336
348
  .mutation(({ input }) => {
337
- const { a, b } = input as { a: number; b: number };
338
- return { result: a * b };
349
+ return { result: input.a * input.b };
339
350
  }),
340
351
  },
341
352
  system: {
@@ -363,7 +374,7 @@ export default function rpcRoutes(): PluginFunction {
363
374
  }
364
375
  `,
365
376
  // ─── src/tasks/cleanup.ts ───
366
- 'src/tasks/cleanup.ts': `// Background task: clean up expired sessions
377
+ "src/tasks/cleanup.ts": `// Background task: clean up expired sessions
367
378
  // Registered with app.task() and runs when enqueued or on a schedule
368
379
 
369
380
  import type { TaskDefinition } from '@celsian/core';
@@ -391,7 +402,7 @@ export const cleanupTask: TaskDefinition = {
391
402
  };
392
403
  `,
393
404
  // ─── src/tasks/report.ts ───
394
- 'src/tasks/report.ts': `// Cron job: daily report generation
405
+ "src/tasks/report.ts": `// Cron job: daily report generation
395
406
  // Runs every day at midnight via app.cron()
396
407
 
397
408
  /**
@@ -411,7 +422,7 @@ export async function generateDailyReport(): Promise<void> {
411
422
  }
412
423
  `,
413
424
  // ─── src/index.ts ───
414
- 'src/index.ts': `// {{name}} — Full-stack Celsian API
425
+ "src/index.ts": `// {{name}} — Full-stack Celsian API
415
426
  // Routes, plugins, background tasks, and cron — all wired up
416
427
 
417
428
  import { createApp, serve, openapi } from 'celsian';
@@ -439,12 +450,12 @@ const app = createApp({ logger: true });
439
450
  // ─── Security (CORS, CSRF, headers, rate limiting) ───
440
451
 
441
452
  for (const plugin of securityPlugins()) {
442
- await app.register(plugin);
453
+ await app.register(plugin, { encapsulate: false });
443
454
  }
444
455
 
445
456
  // ─── Auth (JWT signing & verification) ───
446
457
 
447
- await app.register(authPlugin());
458
+ await app.register(authPlugin(), { encapsulate: false });
448
459
 
449
460
  // ─── API Documentation (OpenAPI + Swagger UI) ───
450
461
 
@@ -481,7 +492,7 @@ const port = parseInt(process.env.PORT ?? '3000', 10);
481
492
  serve(app, { port });
482
493
  `,
483
494
  // ─── test/api.test.ts ───
484
- 'test/api.test.ts': `// Integration tests using app.inject() — no server needed
495
+ "test/api.test.ts": `// Integration tests using app.inject() — no server needed
485
496
  // Run with: npm test
486
497
 
487
498
  import { describe, it, expect, beforeAll } from 'vitest';
@@ -642,7 +653,7 @@ EXPOSE 3000
642
653
  CMD ["node", "dist/index.js"]
643
654
  `,
644
655
  // ─── README.md ───
645
- 'README.md': `# {{name}}
656
+ "README.md": `# {{name}}
646
657
 
647
658
  A full-stack API built with [CelsianJS](https://github.com/CelsianJs/celsian) — the fast, modular Node.js framework.
648
659
 
@@ -772,22 +783,16 @@ Add schemas to your routes for richer documentation:
772
783
  \`\`\`typescript
773
784
  import { Type } from '@sinclair/typebox';
774
785
 
775
- app.route({
776
- method: 'POST',
777
- url: '/products',
778
- schema: {
779
- body: Type.Object({
780
- name: Type.String(),
781
- price: Type.Number({ minimum: 0 }),
782
- }),
783
- response: {
784
- 201: Type.Object({ id: Type.Number(), name: Type.String() }),
785
- },
786
- },
787
- handler(req, reply) {
788
- // req.parsedBody is validated against the schema
789
- return reply.status(201).json({ id: 1, ...req.parsedBody });
790
- },
786
+ const CreateProductSchema = Type.Object({
787
+ name: Type.String(),
788
+ price: Type.Number({ minimum: 0 }),
789
+ });
790
+
791
+ // parsedBody is fully typed — no cast needed!
792
+ app.post('/products', {
793
+ schema: { body: CreateProductSchema },
794
+ }, (req, reply) => {
795
+ return reply.status(201).json({ id: 1, name: req.parsedBody.name });
791
796
  });
792
797
  \`\`\`
793
798
 
@@ -1 +1 @@
1
- {"version":3,"file":"full.js","sourceRoot":"","sources":["../../src/templates/full.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"full.js","sourceRoot":"","sources":["../../src/templates/full.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export declare const restApiTemplate: {
2
- 'package.json': string;
3
- 'tsconfig.json': string;
4
- 'src/index.ts': string;
2
+ "package.json": string;
3
+ "tsconfig.json": string;
4
+ "src/index.ts": string;
5
5
  };
6
6
  //# sourceMappingURL=rest-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/templates/rest-api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;;;CA6E3B,CAAC"}
1
+ {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/templates/rest-api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;;;CA2F3B,CAAC"}
@@ -1,40 +1,57 @@
1
1
  export const restApiTemplate = {
2
- 'package.json': JSON.stringify({
3
- name: '{{name}}',
4
- version: '0.0.1',
5
- type: 'module',
2
+ "package.json": JSON.stringify({
3
+ name: "{{name}}",
4
+ version: "0.0.1",
5
+ type: "module",
6
6
  scripts: {
7
- dev: 'npx celsian dev',
8
- build: 'tsc',
9
- start: 'node dist/index.js',
7
+ dev: "npx tsx --watch src/index.ts",
8
+ build: "tsc",
9
+ start: "node dist/index.js",
10
10
  },
11
11
  dependencies: {
12
- celsian: '^0.1.0',
13
- '@sinclair/typebox': '^0.34.0',
12
+ celsian: "latest",
13
+ "@sinclair/typebox": "^0.34.0",
14
14
  },
15
15
  devDependencies: {
16
- typescript: '^5.7.0',
17
- tsx: '^4.0.0',
16
+ typescript: "^5.7.0",
17
+ tsx: "^4.0.0",
18
18
  },
19
19
  }, null, 2),
20
- 'tsconfig.json': JSON.stringify({
20
+ "tsconfig.json": JSON.stringify({
21
21
  compilerOptions: {
22
- target: 'ES2022',
23
- module: 'ESNext',
24
- moduleResolution: 'bundler',
22
+ target: "ES2022",
23
+ module: "ESNext",
24
+ moduleResolution: "bundler",
25
25
  strict: true,
26
26
  esModuleInterop: true,
27
27
  skipLibCheck: true,
28
- outDir: 'dist',
29
- rootDir: 'src',
28
+ outDir: "dist",
29
+ rootDir: "src",
30
30
  },
31
- include: ['src'],
31
+ include: ["src"],
32
32
  }, null, 2),
33
- 'src/index.ts': `import { createApp, serve } from 'celsian';
33
+ "src/index.ts": `import { createApp, serve, cors, security } from 'celsian';
34
34
  import { Type } from '@sinclair/typebox';
35
35
 
36
36
  const app = createApp();
37
37
 
38
+ // ─── Security (CORS + security headers) ───
39
+
40
+ const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:3000';
41
+
42
+ await app.register(cors({
43
+ origin: CORS_ORIGIN,
44
+ credentials: true,
45
+ maxAge: 86400,
46
+ }));
47
+
48
+ await app.register(security({
49
+ hsts: { maxAge: 31536000, includeSubDomains: true },
50
+ referrerPolicy: 'strict-origin-when-cross-origin',
51
+ }));
52
+
53
+ // ─── Routes ───
54
+
38
55
  const CreateUserSchema = Type.Object({
39
56
  name: Type.String(),
40
57
  email: Type.String({ format: 'email' }),
@@ -47,16 +64,13 @@ app.get('/users', (req, reply) => {
47
64
  return reply.json(users);
48
65
  });
49
66
 
50
- app.route({
51
- method: 'POST',
52
- url: '/users',
67
+ app.post('/users', {
53
68
  schema: { body: CreateUserSchema },
54
- handler(req, reply) {
55
- const { name, email } = req.parsedBody as { name: string; email: string };
56
- const user = { id: nextId++, name, email };
57
- users.push(user);
58
- return reply.status(201).json(user);
59
- },
69
+ }, (req, reply) => {
70
+ const { name, email } = req.parsedBody;
71
+ const user = { id: nextId++, name, email };
72
+ users.push(user);
73
+ return reply.status(201).json(user);
60
74
  });
61
75
 
62
76
  app.get('/users/:id', (req, reply) => {
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../src/templates/rest-api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,iBAAiB;YACtB,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;YACjB,mBAAmB,EAAE,SAAS;SAC/B;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCjB;CACA,CAAC"}
1
+ {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../src/templates/rest-api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,8BAA8B;YACnC,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;YACjB,mBAAmB,EAAE,SAAS;SAC/B;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDjB;CACA,CAAC"}
@@ -1,6 +1,6 @@
1
1
  export declare const rpcApiTemplate: {
2
- 'package.json': string;
3
- 'tsconfig.json': string;
4
- 'src/index.ts': string;
2
+ "package.json": string;
3
+ "tsconfig.json": string;
4
+ "src/index.ts": string;
5
5
  };
6
6
  //# sourceMappingURL=rpc-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-api.d.ts","sourceRoot":"","sources":["../../src/templates/rpc-api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;CA8E1B,CAAC"}
1
+ {"version":3,"file":"rpc-api.d.ts","sourceRoot":"","sources":["../../src/templates/rpc-api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;CA+F1B,CAAC"}
@@ -1,42 +1,59 @@
1
1
  export const rpcApiTemplate = {
2
- 'package.json': JSON.stringify({
3
- name: '{{name}}',
4
- version: '0.0.1',
5
- type: 'module',
2
+ "package.json": JSON.stringify({
3
+ name: "{{name}}",
4
+ version: "0.0.1",
5
+ type: "module",
6
6
  scripts: {
7
- dev: 'npx celsian dev',
8
- build: 'tsc',
9
- start: 'node dist/index.js',
7
+ dev: "npx tsx --watch src/index.ts",
8
+ build: "tsc",
9
+ start: "node dist/index.js",
10
10
  },
11
11
  dependencies: {
12
- celsian: '^0.1.0',
13
- '@celsian/rpc': '^0.1.0',
14
- '@sinclair/typebox': '^0.34.0',
12
+ celsian: "latest",
13
+ "@celsian/rpc": "latest",
14
+ "@sinclair/typebox": "^0.34.0",
15
15
  },
16
16
  devDependencies: {
17
- typescript: '^5.7.0',
18
- tsx: '^4.0.0',
17
+ typescript: "^5.7.0",
18
+ tsx: "^4.0.0",
19
19
  },
20
20
  }, null, 2),
21
- 'tsconfig.json': JSON.stringify({
21
+ "tsconfig.json": JSON.stringify({
22
22
  compilerOptions: {
23
- target: 'ES2022',
24
- module: 'ESNext',
25
- moduleResolution: 'bundler',
23
+ target: "ES2022",
24
+ module: "ESNext",
25
+ moduleResolution: "bundler",
26
26
  strict: true,
27
27
  esModuleInterop: true,
28
28
  skipLibCheck: true,
29
- outDir: 'dist',
30
- rootDir: 'src',
29
+ outDir: "dist",
30
+ rootDir: "src",
31
31
  },
32
- include: ['src'],
32
+ include: ["src"],
33
33
  }, null, 2),
34
- 'src/index.ts': `import { createApp, serve } from 'celsian';
34
+ "src/index.ts": `import { createApp, serve, cors, security } from 'celsian';
35
35
  import { procedure, router, RPCHandler } from '@celsian/rpc';
36
36
  import { Type } from '@sinclair/typebox';
37
37
 
38
38
  const app = createApp();
39
39
 
40
+ // ─── Security (CORS + security headers) ───
41
+
42
+ const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:3000';
43
+
44
+ await app.register(cors({
45
+ origin: CORS_ORIGIN,
46
+ credentials: true,
47
+ maxAge: 86400,
48
+ }));
49
+
50
+ await app.register(security({
51
+ hsts: { maxAge: 31536000, includeSubDomains: true },
52
+ referrerPolicy: 'strict-origin-when-cross-origin',
53
+ }));
54
+
55
+ // ─── Routes ───
56
+
40
57
  const appRouter = router({
41
58
  greeting: {
42
59
  hello: procedure
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-api.js","sourceRoot":"","sources":["../../src/templates/rpc-api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,iBAAiB;YACtB,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;YACjB,cAAc,EAAE,QAAQ;YACxB,mBAAmB,EAAE,SAAS;SAC/B;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCjB;CACA,CAAC"}
1
+ {"version":3,"file":"rpc-api.js","sourceRoot":"","sources":["../../src/templates/rpc-api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,8BAA8B;YACnC,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;SAC5B;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,QAAQ;YACjB,cAAc,EAAE,QAAQ;YACxB,mBAAmB,EAAE,SAAS;SAC/B;QACD,eAAe,EAAE;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,QAAQ;SACd;KACF,EACD,IAAI,EACJ,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,SAAS,CAC7B;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;SACf;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;KACjB,EACD,IAAI,EACJ,CAAC,CACF;IACD,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDjB;CACA,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-celsian",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-celsian": "dist/index.js"
@@ -10,8 +10,11 @@
10
10
  "files": [
11
11
  "dist"
12
12
  ],
13
+ "license": "MIT",
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
13
17
  "scripts": {
14
18
  "build": "tsc -b"
15
- },
16
- "license": "MIT"
17
- }
19
+ }
20
+ }