create-tilcayo-app 0.0.1 → 0.0.3
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 +294 -49
- package/dist/bin.js +13 -4
- package/dist/fullstack.d.ts +2 -0
- package/dist/fullstack.js +107 -0
- package/dist/index.js +38 -10
- package/dist/installTenancy.d.ts +2 -0
- package/dist/installTenancy.js +86 -0
- package/dist/options.d.ts +4 -2
- package/dist/options.js +38 -14
- package/dist/react-auth.json +83 -0
- package/dist/react-starter.json +75 -0
- package/dist/templates.js +113 -74
- package/package.json +27 -26
package/dist/templates.js
CHANGED
|
@@ -1,99 +1,138 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { adminFiles, adminBackendFiles } from "@tilcayo/cli";
|
|
4
|
+
import { fullstackTemplates } from "./fullstack.js";
|
|
2
5
|
export function templates(options, localPackages = {}) {
|
|
6
|
+
if (options.type === "fullstack")
|
|
7
|
+
return fullstackTemplates(options, localPackages);
|
|
8
|
+
if (options.type === "react") {
|
|
9
|
+
const files = JSON.parse(readFileSync(new URL('./react-starter.json', import.meta.url), 'utf8'));
|
|
10
|
+
const manifest = JSON.parse(files['package.json']);
|
|
11
|
+
manifest.name = options.name;
|
|
12
|
+
manifest.engines = { node: '^22.12.0 || >=24.0.0' };
|
|
13
|
+
manifest.dependencies['@tilcayo/styles'] = localPackages.styles ?? '^0.0.3';
|
|
14
|
+
manifest.dependencies['@tilcayo/react'] = localPackages.react ?? '^0.0.3';
|
|
15
|
+
manifest.dependencies['@tilcayo/ui'] = localPackages.ui ?? '^0.0.3';
|
|
16
|
+
manifest.tilcayo = { type: 'react', auth: options.auth, admin: options.admin ?? false, packageManager: options.packageManager };
|
|
17
|
+
files['package.json'] = JSON.stringify(manifest, null, 2) + '\n';
|
|
18
|
+
if (options.packageManager === 'yarn')
|
|
19
|
+
files['.yarnrc.yml'] = 'nodeLinker: node-modules\n';
|
|
20
|
+
if (options.auth) {
|
|
21
|
+
const authFiles = JSON.parse(readFileSync(new URL('./react-auth.json', import.meta.url), 'utf8'));
|
|
22
|
+
Object.assign(files, authFiles);
|
|
23
|
+
files['.gitignore'] += '\n.env\n.env.*\n!.env.example\n';
|
|
24
|
+
delete files['src/lib/api.ts'];
|
|
25
|
+
}
|
|
26
|
+
if (options.admin) {
|
|
27
|
+
files['src/components/navigation.tsx'] = files['src/components/navigation.tsx'].replace('const adminEnabled = false', 'const adminEnabled = true');
|
|
28
|
+
manifest.dependencies['@tilcayo/admin'] = localPackages.admin ?? '^0.0.3';
|
|
29
|
+
for (const file of adminFiles())
|
|
30
|
+
files[`src/${file.folder}/${file.name}`] = file.source;
|
|
31
|
+
{
|
|
32
|
+
const source = files['src/components/session-skeleton.tsx'];
|
|
33
|
+
files['src/components/session-skeleton.tsx'] = "import { AdminSessionShell } from '../features/admin/session-shell';\n" + source.replace(" const { pathname } = useLocation()", " const { pathname } = useLocation()\n if (/^\\/admin(?:\\/|$)/.test(pathname)) return <AdminSessionShell />");
|
|
34
|
+
}
|
|
35
|
+
files['src/routes.tsx'] = "import { adminRoutes } from './features/admin/admin.routes';\n" + files['src/routes.tsx'].replace('export const routes: RouteObject[] = [', 'export const routes: RouteObject[] = [\n ...adminRoutes,');
|
|
36
|
+
files['README.md'] += '\nAdmin overview and user directory are at /admin and /admin/users. On a separate API, register app.routes(auth.adminRoutes) to enable /api/admin/users. Assign the admin role through trusted server code; registration does not grant admin rights. Authorize backend resource routes with auth.middleware and auth.requireRole("admin").\n';
|
|
37
|
+
files['package.json'] = JSON.stringify(manifest, null, 2) + '\n';
|
|
38
|
+
}
|
|
39
|
+
return files;
|
|
40
|
+
}
|
|
3
41
|
const mongo = options.type === "api" || options.auth;
|
|
4
42
|
const json = (value) => JSON.stringify(value, null, 2) + "\n";
|
|
5
43
|
const env = `# Server\nPORT=9149\n${mongo ? `\n# Database\nMONGODB_URI=mongodb://127.0.0.1:27017/${options.name.replaceAll("-", "_")}\n` : ""}`;
|
|
6
44
|
return {
|
|
45
|
+
...(options.admin ? Object.fromEntries(adminBackendFiles().map(file => [`src/${file.folder}/${file.name}`, file.source])) : {}),
|
|
7
46
|
"package.json": json({
|
|
8
47
|
name: options.name, version: "0.0.1", private: true, type: "module",
|
|
9
48
|
engines: { node: ">=22.9.0" },
|
|
10
49
|
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.
|
|
13
|
-
devDependencies: { "@tilcayo/cli": localPackages.cli ?? "^0.0.
|
|
50
|
+
scripts: { dev: "tilcayo dev", build: "tilcayo build", start: "tilcayo start", routes: "tilcayo routes:list", ...(options.admin ? { 'seed:demo': 'node --env-file-if-exists=.env dist/scripts/seed-admin-demo.js' } : {}) },
|
|
51
|
+
dependencies: { "@tilcayo/core": localPackages.core ?? "^0.0.3", ...(options.auth ? { "@tilcayo/auth": localPackages.auth ?? "^0.0.3", "@tilcayo/cloudinary": localPackages.cloudinary ?? "^0.0.3" } : {}), ...(mongo ? { mongoose: localPackages.mongoose ?? "^9.10.2" } : {}), zod: localPackages.zod ?? "^4.0.0" },
|
|
52
|
+
devDependencies: { "@tilcayo/cli": localPackages.cli ?? "^0.0.3", "@types/node": "^26.6.3", typescript: "^7.0.2", nodemon: "^3.1.14" },
|
|
14
53
|
}),
|
|
15
54
|
"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
55
|
".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` : ""),
|
|
56
|
+
".env.example": env + (options.auth ? "\n# Authentication - use private values from .env\nAUTH_ACCESS_SECRET=\nAUTH_REFRESH_SECRET=\n\n# Cloudinary (backend only)\nCLOUDINARY_CLOUD_NAME=\nCLOUDINARY_API_KEY=\nCLOUDINARY_API_SECRET_KEY=\n\n# Password recovery (backend only)\nMAIL_USER=\nMAIL_PASS=\nMAIL_HOST=smtp.gmail.com\nMAIL_PORT=465\n" : ""),
|
|
57
|
+
".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\n# Cloudinary (backend only)\nCLOUDINARY_CLOUD_NAME=\nCLOUDINARY_API_KEY=\nCLOUDINARY_API_SECRET_KEY=\n` : ""),
|
|
19
58
|
...(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' : ""}};
|
|
59
|
+
"src/config.ts": `const port = Number(process.env.PORT ?? 9149);
|
|
60
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error("PORT must be an integer between 0 and 65535.");
|
|
61
|
+
|
|
62
|
+
export const config = {
|
|
63
|
+
port,
|
|
64
|
+
${mongo ? ' mongoUri: process.env.MONGODB_URI ?? "",\n' : ""}};
|
|
26
65
|
`,
|
|
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;
|
|
66
|
+
"src/app.ts": `import { createApp, requestId, securityHeaders } from "@tilcayo/core";
|
|
67
|
+
import healthRoutes from "./routes/health.routes.js";
|
|
68
|
+
${options.type === "api" ? 'import notesRoutes from "./routes/notes.routes.js";\n' : ""}${options.auth ? 'import authRoutes from "./routes/auth.routes.js";\n' : ""}${options.admin ? 'import { auth } from "./auth.js";\nimport adminProductsRoutes from "./routes/admin-products.routes.js";\nimport adminOrdersRoutes from "./routes/admin-orders.routes.js";\n' : ""}
|
|
69
|
+
const app = createApp({ middleware: [requestId(), securityHeaders()] });
|
|
70
|
+
app.routes(healthRoutes);
|
|
71
|
+
${options.type === "api" ? "app.routes(notesRoutes);\n" : ""}${options.auth ? "app.routes(authRoutes);\n" : ""}${options.admin ? "app.routes(auth.adminRoutes);\napp.routes(adminProductsRoutes);\napp.routes(adminOrdersRoutes);\n" : ""}
|
|
72
|
+
export default app;
|
|
34
73
|
`,
|
|
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
|
-
});
|
|
74
|
+
"src/index.ts": `${mongo ? 'import { connectMongo, disconnectMongo } from "@tilcayo/core";\n' : ""}
|
|
75
|
+
async function main() {
|
|
76
|
+
const { config } = await import("./config.js");
|
|
77
|
+
const { default: app } = await import("./app.js");
|
|
78
|
+
${mongo ? " await connectMongo(config.mongoUri);\n" : ""} const server = app.listen(config.port);
|
|
79
|
+
const shutdown = () => {
|
|
80
|
+
const timeout = setTimeout(() => process.exit(1), 10_000);
|
|
81
|
+
timeout.unref();
|
|
82
|
+
server.close(() => {
|
|
83
|
+
${mongo ? " void disconnectMongo().then(() => process.exit(0), () => process.exit(1));" : " process.exit(0);"}
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
process.once("SIGINT", shutdown);
|
|
87
|
+
process.once("SIGTERM", shutdown);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
main().catch(() => {
|
|
91
|
+
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" : ""}.");
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
});
|
|
55
94
|
`,
|
|
56
|
-
"src/controllers/health.controller.ts": `import type { TilcayoContext } from "@tilcayo/core";
|
|
57
|
-
|
|
58
|
-
export const health = (ctx: TilcayoContext) => ctx.response.success({ status: "ok" });
|
|
95
|
+
"src/controllers/health.controller.ts": `import type { TilcayoContext } from "@tilcayo/core";
|
|
96
|
+
|
|
97
|
+
export const health = (ctx: TilcayoContext) => ctx.response.success({ status: "ok" });
|
|
59
98
|
`,
|
|
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
|
-
});
|
|
99
|
+
"src/routes/health.routes.ts": `import { defineRoutes } from "@tilcayo/core";
|
|
100
|
+
import { health } from "../controllers/health.controller.js";
|
|
101
|
+
|
|
102
|
+
export default defineRoutes((router) => {
|
|
103
|
+
router.get("/health", health);
|
|
104
|
+
});
|
|
66
105
|
`,
|
|
67
106
|
"src/models/.gitkeep": "",
|
|
68
107
|
"src/services/.gitkeep": "",
|
|
69
108
|
"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." : ""}
|
|
109
|
+
"README.md": `# ${options.name}
|
|
110
|
+
|
|
111
|
+
Tilcayo ${options.type === "api" ? "MongoDB CRUD" : "minimal"} API${options.auth ? " with JWT authentication" : ""}.
|
|
112
|
+
${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" : ""}
|
|
113
|
+
|
|
114
|
+
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.
|
|
115
|
+
${mongo ? "\nStart MongoDB locally or set MONGODB_URI in .env to your connection string.\n" : ""}
|
|
116
|
+
Install dependencies if you skipped setup:
|
|
117
|
+
|
|
118
|
+
\`\`\`sh
|
|
119
|
+
${options.packageManager} install
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
With the Tilcayo CLI on PATH:
|
|
123
|
+
|
|
124
|
+
\`\`\`sh
|
|
125
|
+
tilcayo dev
|
|
126
|
+
tilcayo build
|
|
127
|
+
tilcayo start
|
|
128
|
+
tilcayo routes:list
|
|
129
|
+
\`\`\`
|
|
130
|
+
|
|
131
|
+
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.
|
|
132
|
+
|
|
133
|
+
GET /health returns the application status. The default port is 9149.
|
|
134
|
+
${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" : ""}
|
|
135
|
+
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
136
|
`,
|
|
98
137
|
};
|
|
99
138
|
}
|
package/package.json
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "create-tilcayo-app",
|
|
3
|
-
"version": "0.0.
|
|
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": "
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
"@
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "create-tilcayo-app",
|
|
3
|
+
"version": "0.0.3",
|
|
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 && node scripts/bundle-react.mjs",
|
|
20
|
+
"prepack": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^1.8.1",
|
|
24
|
+
"@tilcayo/cli": "^0.0.3",
|
|
25
|
+
"picocolors": "^1.1.1"
|
|
26
|
+
}
|
|
27
|
+
}
|