create-tilcayo-app 0.0.0-stage → 0.0.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 +48 -2
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +84 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +86 -0
- package/dist/options.d.ts +14 -0
- package/dist/options.js +73 -0
- package/dist/templates.d.ts +2 -0
- package/dist/templates.js +99 -0
- package/package.json +24 -4
package/README.md
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-tilcayo-app
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create a Tilcayo API with an interactive setup wizard:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
create-tilcayo-app
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Once published to your registry, bootstrap without a global install:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm create tilcayo-app@latest
|
|
13
|
+
pnpm create tilcayo-app
|
|
14
|
+
yarn create tilcayo-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For local development in the Tilcayo repository, build the workspace and run
|
|
18
|
+
`node packages/create-tilcayo-app/dist/bin.js my-api`, or link this package to expose
|
|
19
|
+
`create-tilcayo-app` on PATH.
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
create-tilcayo-app my-api --type api --auth --package-manager npm --yes
|
|
23
|
+
create-tilcayo-app tiny-api --type minimal --no-auth --no-install --yes
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The wizard offers project name, package manager (npm, pnpm, or Yarn), application
|
|
27
|
+
type, and authentication. Use the arrow keys and Enter to choose from colored
|
|
28
|
+
menus; project name remains a text field. Ctrl+C cancels before files are created.
|
|
29
|
+
`api` includes MongoDB-backed note CRUD; `minimal`
|
|
30
|
+
includes a health endpoint. Enabling authentication adds MongoDB to either type.
|
|
31
|
+
Noninteractive runs use defaults for omitted options. Existing paths are refused.
|
|
32
|
+
|
|
33
|
+
Generated projects contain controllers, routes, models, services, validators,
|
|
34
|
+
separate app and startup modules, TypeScript configuration, `.gitignore`,
|
|
35
|
+
`.env.example`, and a private `.env`. Authentication gets independent random
|
|
36
|
+
secrets in `.env`; the example file leaves secrets blank.
|
|
37
|
+
|
|
38
|
+
Setup installs dependencies and builds unless `--no-install` is supplied. The
|
|
39
|
+
selected package manager must be installed. Running the creator from a built
|
|
40
|
+
Tilcayo source checkout automatically links the local framework packages and
|
|
41
|
+
their shared Zod and Mongoose dependencies. Keep that checkout available while
|
|
42
|
+
developing the generated app. The published creator uses registry versions of
|
|
43
|
+
`@tilcayo/core`, `@tilcayo/auth`, and `@tilcayo/cli` instead.
|
|
44
|
+
Installation failures retain the generated project and report recovery steps.
|
|
45
|
+
MongoDB must be running before starting an API that uses it.
|
|
46
|
+
|
|
47
|
+
Inside the generated project, use `tilcayo dev`, `tilcayo build`, `tilcayo start`,
|
|
48
|
+
and `tilcayo routes:list`. If the CLI is installed only in the project, invoke
|
|
49
|
+
it through `npx tilcayo`, `pnpm exec tilcayo`, or `yarn exec tilcayo`.
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import { cancel, intro, isCancel, select, text } from "@clack/prompts";
|
|
4
|
+
import color from "picocolors";
|
|
5
|
+
import { generateApp, installApp } from "./index.js";
|
|
6
|
+
import { help, parseOptions, validateOptions } from "./options.js";
|
|
7
|
+
function answer(value) {
|
|
8
|
+
if (isCancel(value)) {
|
|
9
|
+
cancel("Setup cancelled. No files were created.");
|
|
10
|
+
process.exit(130);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
async function main() {
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
17
|
+
console.log(help);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { options, missing, yes } = parseOptions(args);
|
|
21
|
+
if (!yes && stdin.isTTY && stdout.isTTY) {
|
|
22
|
+
intro(color.bgCyan(color.black(" Create Tilcayo App ")));
|
|
23
|
+
if (missing.has("name"))
|
|
24
|
+
options.name = answer(await text({
|
|
25
|
+
message: "Project name",
|
|
26
|
+
placeholder: options.name,
|
|
27
|
+
defaultValue: options.name,
|
|
28
|
+
validate(value) {
|
|
29
|
+
try {
|
|
30
|
+
validateOptions({ ...options, name: value?.trim() || options.name });
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return error instanceof Error ? error.message : "Invalid project name.";
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
})).trim();
|
|
37
|
+
if (missing.has("packageManager"))
|
|
38
|
+
options.packageManager = answer(await select({
|
|
39
|
+
message: "Package manager (use arrow keys, Enter to select)",
|
|
40
|
+
initialValue: options.packageManager,
|
|
41
|
+
options: [
|
|
42
|
+
{ value: "npm", label: color.red("npm") },
|
|
43
|
+
{ value: "pnpm", label: color.yellow("pnpm") },
|
|
44
|
+
{ value: "yarn", label: color.cyan("yarn") },
|
|
45
|
+
],
|
|
46
|
+
}));
|
|
47
|
+
if (missing.has("type"))
|
|
48
|
+
options.type = answer(await select({
|
|
49
|
+
message: "Application type",
|
|
50
|
+
initialValue: options.type,
|
|
51
|
+
options: [
|
|
52
|
+
{ value: "api", label: color.green("API"), hint: "MongoDB with sample CRUD routes" },
|
|
53
|
+
{ value: "minimal", label: color.magenta("Minimal"), hint: "Health-check endpoint only" },
|
|
54
|
+
],
|
|
55
|
+
}));
|
|
56
|
+
if (missing.has("auth"))
|
|
57
|
+
options.auth = answer(await select({
|
|
58
|
+
message: "Include authentication?",
|
|
59
|
+
initialValue: options.auth,
|
|
60
|
+
options: [
|
|
61
|
+
{ value: true, label: color.green("Yes"), hint: "Register, login, refresh and logout; requires MongoDB" },
|
|
62
|
+
{ value: false, label: color.yellow("No"), hint: "Start without authentication" },
|
|
63
|
+
],
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
validateOptions(options);
|
|
67
|
+
const target = await generateApp(options);
|
|
68
|
+
console.log(`Created ${target}`);
|
|
69
|
+
if (options.install) {
|
|
70
|
+
console.log(`Installing dependencies with ${options.packageManager} and building the API...`);
|
|
71
|
+
await installApp(target, options.packageManager);
|
|
72
|
+
}
|
|
73
|
+
console.log(`\nNext:\n cd ${options.name}`);
|
|
74
|
+
if (!options.install)
|
|
75
|
+
console.log(` ${options.packageManager} install`);
|
|
76
|
+
const cli = options.packageManager === "npm" ? "npx tilcayo" : `${options.packageManager} exec tilcayo`;
|
|
77
|
+
console.log(` ${cli} dev\n\nWith Tilcayo on PATH, use tilcayo dev directly.`);
|
|
78
|
+
if (options.type === "api" || options.auth)
|
|
79
|
+
console.log("Start MongoDB or update MONGODB_URI in .env before starting the API.");
|
|
80
|
+
}
|
|
81
|
+
main().catch((error) => {
|
|
82
|
+
console.error(error instanceof Error ? error.message : "Unable to create application.");
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type StarterOptions } from "./options.js";
|
|
2
|
+
export type { StarterOptions } from "./options.js";
|
|
3
|
+
export declare function generateApp(options: StarterOptions, root?: string): Promise<string>;
|
|
4
|
+
export declare function installApp(target: string, manager: StarterOptions["packageManager"]): Promise<void>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { mkdir, writeFile, readFile, access } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { make } from "@tilcayo/cli";
|
|
7
|
+
import { templates } from "./templates.js";
|
|
8
|
+
import { validateOptions } from "./options.js";
|
|
9
|
+
async function localDependencies(target, options) {
|
|
10
|
+
const checkout = fileURLToPath(new URL("../../../", import.meta.url));
|
|
11
|
+
let manifest;
|
|
12
|
+
try {
|
|
13
|
+
manifest = JSON.parse(await readFile(path.join(checkout, "package.json"), "utf8"));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
if (manifest.name !== "tilcayo" || manifest.private !== true || !Array.isArray(manifest.workspaces) || !manifest.workspaces.includes("packages/*"))
|
|
19
|
+
return {};
|
|
20
|
+
const dependencies = {};
|
|
21
|
+
for (const name of ["core", "cli", ...(options.auth ? ["auth"] : [])]) {
|
|
22
|
+
const directory = path.join(checkout, "packages", name);
|
|
23
|
+
const pkg = JSON.parse(await readFile(path.join(directory, "package.json"), "utf8"));
|
|
24
|
+
if (pkg.name !== `@tilcayo/${name}`)
|
|
25
|
+
throw new Error(`Invalid local Tilcayo package: ${directory}`);
|
|
26
|
+
try {
|
|
27
|
+
await access(path.join(directory, "dist/index.js"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error(`Build the Tilcayo workspace before creating an application: ${directory}/dist/index.js is missing.`);
|
|
31
|
+
}
|
|
32
|
+
const relative = path.relative(target, directory).split(path.sep).join("/");
|
|
33
|
+
dependencies[name] = `${options.packageManager === "npm" ? "file" : "link"}:${relative}`;
|
|
34
|
+
}
|
|
35
|
+
const require = createRequire(path.join(checkout, "packages/core/package.json"));
|
|
36
|
+
for (const name of ["zod", ...(options.type === "api" || options.auth ? ["mongoose"] : [])]) {
|
|
37
|
+
const directory = path.dirname(require.resolve(`${name}/package.json`));
|
|
38
|
+
const relative = path.relative(target, directory).split(path.sep).join("/");
|
|
39
|
+
dependencies[name] = `${options.packageManager === "npm" ? "file" : "link"}:${relative}`;
|
|
40
|
+
}
|
|
41
|
+
return dependencies;
|
|
42
|
+
}
|
|
43
|
+
export async function generateApp(options, root = process.cwd()) {
|
|
44
|
+
validateOptions(options);
|
|
45
|
+
const target = path.resolve(root, options.name);
|
|
46
|
+
const sources = templates(options, await localDependencies(target, options));
|
|
47
|
+
try {
|
|
48
|
+
await mkdir(target);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error.code === "EEXIST")
|
|
52
|
+
throw new Error(`Target already exists: ${target}. Choose a new project name.`);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
for (const [filename, source] of Object.entries(sources)) {
|
|
56
|
+
const destination = path.join(target, filename);
|
|
57
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
58
|
+
await writeFile(destination, source, { flag: "wx", ...(filename === ".env" ? { mode: 0o600 } : {}) });
|
|
59
|
+
}
|
|
60
|
+
if (options.type === "api")
|
|
61
|
+
await make(["make:resource", "Note", "title:string", "content?:string"], target);
|
|
62
|
+
if (options.auth)
|
|
63
|
+
await make(["make:auth"], target);
|
|
64
|
+
return target;
|
|
65
|
+
}
|
|
66
|
+
function run(command, args, cwd, shell = false) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const child = spawn(command, args, { cwd, stdio: "inherit", shell, windowsHide: true });
|
|
69
|
+
child.once("error", reject);
|
|
70
|
+
child.once("exit", (code, signal) => code === 0 ? resolve() : reject(new Error(`${command} failed (${signal ?? code}).`)));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export async function installApp(target, manager) {
|
|
74
|
+
if (!["npm", "pnpm", "yarn"].includes(manager))
|
|
75
|
+
throw new Error("Unsupported package manager.");
|
|
76
|
+
try {
|
|
77
|
+
// Both the command and its arguments are fixed, not user-supplied shell text.
|
|
78
|
+
await run(manager, ["install"], target, process.platform === "win32");
|
|
79
|
+
const require = createRequire(path.join(target, "package.json"));
|
|
80
|
+
const cli = path.join(path.dirname(require.resolve("@tilcayo/cli")), "bin.js");
|
|
81
|
+
await run(process.execPath, [cli, "build"], target);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new Error(`Project created at ${target}, but dependency installation or build failed. Check that ${manager} is installed and Tilcayo packages are available in your registry, then run ${manager} install and the Tilcayo build command inside the project.`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface StarterOptions {
|
|
2
|
+
name: string;
|
|
3
|
+
packageManager: "npm" | "pnpm" | "yarn";
|
|
4
|
+
type: "api" | "minimal";
|
|
5
|
+
auth: boolean;
|
|
6
|
+
install: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const help = "Usage: create-tilcayo-app [project-name] [options]\n\n --package-manager npm|pnpm|yarn\n --type api|minimal MongoDB CRUD API or minimal health-check API\n --auth / --no-auth Include JWT authentication (requires MongoDB)\n --no-install Generate files without installing dependencies\n --yes Use defaults for unanswered choices\n --help Show this help\n\nDefaults: my-api, npm, api, no authentication, install dependencies.\nInteractive terminals prompt for missing choices. Automation uses defaults.\nExisting directories are never overwritten.";
|
|
9
|
+
export declare function validateOptions(options: StarterOptions): void;
|
|
10
|
+
export declare function parseOptions(args: string[]): {
|
|
11
|
+
options: StarterOptions;
|
|
12
|
+
missing: Set<string>;
|
|
13
|
+
yes: boolean;
|
|
14
|
+
};
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export const help = `Usage: create-tilcayo-app [project-name] [options]
|
|
2
|
+
|
|
3
|
+
--package-manager npm|pnpm|yarn
|
|
4
|
+
--type api|minimal MongoDB CRUD API or minimal health-check API
|
|
5
|
+
--auth / --no-auth Include JWT authentication (requires MongoDB)
|
|
6
|
+
--no-install Generate files without installing dependencies
|
|
7
|
+
--yes Use defaults for unanswered choices
|
|
8
|
+
--help Show this help
|
|
9
|
+
|
|
10
|
+
Defaults: my-api, npm, api, no authentication, install dependencies.
|
|
11
|
+
Interactive terminals prompt for missing choices. Automation uses defaults.
|
|
12
|
+
Existing directories are never overwritten.`;
|
|
13
|
+
export function validateOptions(options) {
|
|
14
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(options.name) || options.name.length > 214 || ["node_modules", "con", "prn", "aux", "nul"].includes(options.name) || /^(com|lpt)[0-9]$/.test(options.name)) {
|
|
15
|
+
throw new Error("Use a project name containing lowercase letters, numbers, and hyphens (not a path or reserved system name).");
|
|
16
|
+
}
|
|
17
|
+
if (!["npm", "pnpm", "yarn"].includes(options.packageManager))
|
|
18
|
+
throw new Error("Package manager must be npm, pnpm, or yarn.");
|
|
19
|
+
if (!["api", "minimal"].includes(options.type))
|
|
20
|
+
throw new Error("Application type must be api or minimal.");
|
|
21
|
+
if (typeof options.auth !== "boolean" || typeof options.install !== "boolean")
|
|
22
|
+
throw new Error("Authentication and install choices must be booleans.");
|
|
23
|
+
}
|
|
24
|
+
export function parseOptions(args) {
|
|
25
|
+
const options = { name: "my-api", packageManager: "npm", type: "api", auth: false, install: true };
|
|
26
|
+
const missing = new Set(["name", "packageManager", "type", "auth"]);
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
let yes = false;
|
|
29
|
+
for (let i = 0; i < args.length; i++) {
|
|
30
|
+
const arg = args[i];
|
|
31
|
+
if (!arg.startsWith("-")) {
|
|
32
|
+
if (!missing.has("name"))
|
|
33
|
+
throw new Error("Provide only one project name.");
|
|
34
|
+
options.name = arg;
|
|
35
|
+
missing.delete("name");
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const key = arg === "--no-auth" ? "--auth" : arg;
|
|
39
|
+
if (seen.has(key))
|
|
40
|
+
throw new Error(`Duplicate or conflicting option: ${arg}`);
|
|
41
|
+
seen.add(key);
|
|
42
|
+
if (arg === "--yes" || arg === "-y") {
|
|
43
|
+
yes = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === "--no-install") {
|
|
47
|
+
options.install = false;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (arg === "--auth" || arg === "--no-auth") {
|
|
51
|
+
options.auth = arg === "--auth";
|
|
52
|
+
missing.delete("auth");
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (arg === "--package-manager" || arg === "--type") {
|
|
56
|
+
const value = args[++i];
|
|
57
|
+
if (!value || value.startsWith("-"))
|
|
58
|
+
throw new Error(`Missing value for ${arg}.`);
|
|
59
|
+
if (arg === "--package-manager") {
|
|
60
|
+
options.packageManager = value;
|
|
61
|
+
missing.delete("packageManager");
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
options.type = value;
|
|
65
|
+
missing.delete("type");
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`Unknown option: ${arg}. Run create-tilcayo-app --help.`);
|
|
70
|
+
}
|
|
71
|
+
validateOptions(options);
|
|
72
|
+
return { options, missing, yes };
|
|
73
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
export function templates(options, localPackages = {}) {
|
|
3
|
+
const mongo = options.type === "api" || options.auth;
|
|
4
|
+
const json = (value) => JSON.stringify(value, null, 2) + "\n";
|
|
5
|
+
const env = `# Server\nPORT=9149\n${mongo ? `\n# Database\nMONGODB_URI=mongodb://127.0.0.1:27017/${options.name.replaceAll("-", "_")}\n` : ""}`;
|
|
6
|
+
return {
|
|
7
|
+
"package.json": json({
|
|
8
|
+
name: options.name, version: "0.0.1", private: true, type: "module",
|
|
9
|
+
engines: { node: ">=22.9.0" },
|
|
10
|
+
tilcayo: { database: mongo ? "mongo" : "none", type: options.type, packageManager: options.packageManager },
|
|
11
|
+
scripts: { dev: "tilcayo dev", build: "tilcayo build", start: "tilcayo start", routes: "tilcayo routes:list" },
|
|
12
|
+
dependencies: { "@tilcayo/core": localPackages.core ?? "^0.0.1", ...(options.auth ? { "@tilcayo/auth": localPackages.auth ?? "^0.0.1" } : {}), ...(mongo ? { mongoose: localPackages.mongoose ?? "^9.10.2" } : {}), zod: localPackages.zod ?? "^4.0.0" },
|
|
13
|
+
devDependencies: { "@tilcayo/cli": localPackages.cli ?? "^0.0.1", "@types/node": "^26.6.3", typescript: "^7.0.2", nodemon: "^3.1.14" },
|
|
14
|
+
}),
|
|
15
|
+
"tsconfig.json": json({ compilerOptions: { target: "ES2022", module: "NodeNext", moduleResolution: "NodeNext", strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, rootDir: "src", outDir: "dist", types: ["node"] }, include: ["src/**/*.ts"] }),
|
|
16
|
+
".gitignore": "node_modules/\ndist/\n.env\n.env.*\n!.env.example\n*.log\n.DS_Store\n",
|
|
17
|
+
".env.example": env + (options.auth ? "\n# Authentication - use private values from .env\nAUTH_ACCESS_SECRET=\nAUTH_REFRESH_SECRET=\n" : ""),
|
|
18
|
+
".env": env + (options.auth ? `\n# Authentication - keep these secrets private\nAUTH_ACCESS_SECRET=${randomBytes(32).toString("hex")}\nAUTH_REFRESH_SECRET=${randomBytes(32).toString("hex")}\n` : ""),
|
|
19
|
+
...(options.packageManager === "yarn" ? { ".yarnrc.yml": "nodeLinker: node-modules\n" } : {}),
|
|
20
|
+
"src/config.ts": `const port = Number(process.env.PORT ?? 9149);
|
|
21
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error("PORT must be an integer between 0 and 65535.");
|
|
22
|
+
|
|
23
|
+
export const config = {
|
|
24
|
+
port,
|
|
25
|
+
${mongo ? ' mongoUri: process.env.MONGODB_URI ?? "",\n' : ""}};
|
|
26
|
+
`,
|
|
27
|
+
"src/app.ts": `import { createApp, requestId, securityHeaders } from "@tilcayo/core";
|
|
28
|
+
import healthRoutes from "./routes/health.routes.js";
|
|
29
|
+
${options.type === "api" ? 'import notesRoutes from "./routes/notes.routes.js";\n' : ""}${options.auth ? 'import authRoutes from "./routes/auth.routes.js";\n' : ""}
|
|
30
|
+
const app = createApp({ middleware: [requestId(), securityHeaders()] });
|
|
31
|
+
app.routes(healthRoutes);
|
|
32
|
+
${options.type === "api" ? "app.routes(notesRoutes);\n" : ""}${options.auth ? "app.routes(authRoutes);\n" : ""}
|
|
33
|
+
export default app;
|
|
34
|
+
`,
|
|
35
|
+
"src/index.ts": `${mongo ? 'import { connectMongo, disconnectMongo } from "@tilcayo/core";\n' : ""}
|
|
36
|
+
async function main() {
|
|
37
|
+
const { config } = await import("./config.js");
|
|
38
|
+
const { default: app } = await import("./app.js");
|
|
39
|
+
${mongo ? " await connectMongo(config.mongoUri);\n" : ""} const server = app.listen(config.port);
|
|
40
|
+
const shutdown = () => {
|
|
41
|
+
const timeout = setTimeout(() => process.exit(1), 10_000);
|
|
42
|
+
timeout.unref();
|
|
43
|
+
server.close(() => {
|
|
44
|
+
${mongo ? " void disconnectMongo().then(() => process.exit(0), () => process.exit(1));" : " process.exit(0);"}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
process.once("SIGINT", shutdown);
|
|
48
|
+
process.once("SIGTERM", shutdown);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
main().catch(() => {
|
|
52
|
+
console.error("Unable to start the API. Check .env configuration${mongo ? ", MongoDB connectivity" : ""}${options.auth ? ", and distinct auth secrets of at least 32 bytes each" : ""}.");
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
});
|
|
55
|
+
`,
|
|
56
|
+
"src/controllers/health.controller.ts": `import type { TilcayoContext } from "@tilcayo/core";
|
|
57
|
+
|
|
58
|
+
export const health = (ctx: TilcayoContext) => ctx.response.success({ status: "ok" });
|
|
59
|
+
`,
|
|
60
|
+
"src/routes/health.routes.ts": `import { defineRoutes } from "@tilcayo/core";
|
|
61
|
+
import { health } from "../controllers/health.controller.js";
|
|
62
|
+
|
|
63
|
+
export default defineRoutes((router) => {
|
|
64
|
+
router.get("/health", health);
|
|
65
|
+
});
|
|
66
|
+
`,
|
|
67
|
+
"src/models/.gitkeep": "",
|
|
68
|
+
"src/services/.gitkeep": "",
|
|
69
|
+
"src/validators/.gitkeep": "",
|
|
70
|
+
"README.md": `# ${options.name}
|
|
71
|
+
|
|
72
|
+
Tilcayo ${options.type === "api" ? "MongoDB CRUD" : "minimal"} API${options.auth ? " with JWT authentication" : ""}.
|
|
73
|
+
${Object.keys(localPackages).length ? "\nTilcayo dependencies link to your local framework checkout. Keep that checkout available and rebuild its packages after framework changes. Replace these links with published versions before moving or sharing this application.\n" : ""}
|
|
74
|
+
|
|
75
|
+
Use Node.js 22.9+ and ${options.packageManager}. A local .env has been created${options.auth ? " with distinct random auth secrets" : ""}. Keep it private; .env.example contains shareable settings.
|
|
76
|
+
${mongo ? "\nStart MongoDB locally or set MONGODB_URI in .env to your connection string.\n" : ""}
|
|
77
|
+
Install dependencies if you skipped setup:
|
|
78
|
+
|
|
79
|
+
\`\`\`sh
|
|
80
|
+
${options.packageManager} install
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
With the Tilcayo CLI on PATH:
|
|
84
|
+
|
|
85
|
+
\`\`\`sh
|
|
86
|
+
tilcayo dev
|
|
87
|
+
tilcayo build
|
|
88
|
+
tilcayo start
|
|
89
|
+
tilcayo routes:list
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
If the CLI is only installed locally, use ${options.packageManager === "npm" ? "npx tilcayo" : `${options.packageManager} exec tilcayo`} with the same commands. Package scripts also expose dev, build, start, and routes.
|
|
93
|
+
|
|
94
|
+
GET /health returns the application status. The default port is 9149.
|
|
95
|
+
${options.type === "api" ? "\nThe /notes resource includes GET, POST, GET /:id, PUT /:id, and DELETE /:id. Create a note with JSON {\"title\":\"First note\",\"content\":\"Hello\"}. These sample routes are public.\n" : ""}${options.auth ? "\nAuth routes: POST /api/auth/register, /login, /refresh, /logout; GET /api/auth/me. Register with name, email, and password. Send the access token as Authorization: Bearer <token>. Protect other routes with auth.middleware.\n" : ""}
|
|
96
|
+
Register generated routes in src/app.ts. Database connection and server startup live in src/index.ts. Rebuild after changing routes before using routes:list. ${!mongo ? "To add MongoDB resources or auth later, set tilcayo.database to mongo, add the required packages and environment keys, and connect MongoDB in src/index.ts." : ""}
|
|
97
|
+
`,
|
|
98
|
+
};
|
|
99
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tilcayo-app",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Create a complete Tilcayo API application",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"create-tilcayo-app": "./dist/bin.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.9.0"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.json"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@clack/prompts": "^1.8.1",
|
|
23
|
+
"@tilcayo/cli": "^0.0.1",
|
|
24
|
+
"picocolors": "^1.1.1"
|
|
25
|
+
}
|
|
26
|
+
}
|