gencow 0.1.67 β 0.1.69
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/bin/gencow.mjs +143 -5
- package/package.json +1 -1
- package/server/index.js +4 -0
- package/server/index.js.map +2 -2
package/bin/gencow.mjs
CHANGED
|
@@ -523,8 +523,9 @@ function generateReadmeMd(config, apiObj) {
|
|
|
523
523
|
md += `<summary>π‘ RPC μ§μ νΈμΆ (Node.js / cURL / λΉ-React νκ²½)</summary>\n\n`;
|
|
524
524
|
md += `> β οΈ Reactμμλ μ΄ λ°©λ²μ μ¬μ©νμ§ λ§μΈμ. μμ \`useQuery\`/\`useMutation\`μ μ¬μ©νμΈμ.\n\n`;
|
|
525
525
|
md += `\`\`\`typescript\n`;
|
|
526
|
-
md += `// Query
|
|
527
|
-
md += `const
|
|
526
|
+
md += `// Query νΈμΆ (self-fetch: μλ² λ΄λΆμμ λ€λ₯Έ ν¨μ νΈμΆ μ)\n`;
|
|
527
|
+
md += `const baseUrl = process.env.GENCOW_INTERNAL_URL || "http://localhost:5456";\n`;
|
|
528
|
+
md += `const res = await fetch(\`\${baseUrl}/api/query\`, {\n`;
|
|
528
529
|
md += ` method: "POST",\n`;
|
|
529
530
|
md += ` headers: { "Content-Type": "application/json" },\n`;
|
|
530
531
|
md += ` credentials: "include",\n`;
|
|
@@ -537,7 +538,7 @@ function generateReadmeMd(config, apiObj) {
|
|
|
537
538
|
if (Object.values(apiObj)[0]?.mutations?.length > 0) {
|
|
538
539
|
const firstMut = Object.values(apiObj)[0].mutations[0];
|
|
539
540
|
md += `// Mutation νΈμΆ\n`;
|
|
540
|
-
md += `const res = await fetch(
|
|
541
|
+
md += `const res = await fetch(\`\${baseUrl}/api/mutation\`, {\n`;
|
|
541
542
|
md += ` method: "POST",\n`;
|
|
542
543
|
md += ` headers: { "Content-Type": "application/json" },\n`;
|
|
543
544
|
md += ` credentials: "include",\n`;
|
|
@@ -566,6 +567,13 @@ function generateReadmeMd(config, apiObj) {
|
|
|
566
567
|
md += `- λ°λμ useQueryμ useMutationμ μ¬μ©ν΄μ λ°μ΄ν°μ μ°κ²°ν΄μ€.\n`;
|
|
567
568
|
md += `- fetch()λ₯Ό μ§μ νΈμΆνκ±°λ apiPost() κ°μ λνΌλ₯Ό λ§λ€μ§ λ§.\n`;
|
|
568
569
|
md += `- gencow/api.tsλ μλ μμ±λ νμΌμ΄μΌ. μλμΌλ‘ λ§λ€μ§ λ§.\n`;
|
|
570
|
+
md += `- gencow/index.tsμ re-exportλ export * as moduleName from "./moduleName" ν¨ν΄μ μ¨.\n`;
|
|
571
|
+
md += ` Module, Mod κ°μ μ λ―Έμ¬λ₯Ό λΆμ΄μ§ λ§.\n`;
|
|
572
|
+
md += `\n`;
|
|
573
|
+
md += `β οΈ mutation μ ν:\n`;
|
|
574
|
+
md += `- mutationμ 10μ΄ μ΄λ΄μ μλ£λμ΄μΌ ν΄. μΈλΆ APIλ LLM νΈμΆμ΄ κΈΈλ©΄ λ¨κ³λ³λ‘ λΆλ¦¬ν΄.\n`;
|
|
575
|
+
md += `- κΈ΄ μμ
μ ctx.scheduler.runAfter(0, "module.nextStep", { sessionId }) λ‘ λ€μ λ¨κ³λ₯Ό μμ½.\n`;
|
|
576
|
+
md += `- μ: ν¬λ‘€λ§(Step1) β νν°λ§(Step2) β μμ½(Step3) κ°κ° λ³λ mutationμΌλ‘ λΆλ¦¬.\n`;
|
|
569
577
|
md += `\n`;
|
|
570
578
|
md += `ν¬λ‘ μ‘ (μμ½ μμ
):\n`;
|
|
571
579
|
md += ` gencow/crons.tsμμ cronJobs()λ‘ μ μΈ\n`;
|
|
@@ -578,7 +586,11 @@ function generateReadmeMd(config, apiObj) {
|
|
|
578
586
|
md += `μ APIλ₯Ό κΈ°λ°μΌλ‘ Next.js + Tailwind CSS UI μ»΄ν¬λνΈλ₯Ό λ§λ€μ΄μ€.\n`;
|
|
579
587
|
md += `- TypeScript νμ
μ μ΅λν νμ©νκ³ , λ‘λ©/μλ¬ μνλ μ²λ¦¬ν΄μ€.\n`;
|
|
580
588
|
md += `- ctx.ai.chat()μ μ¬μ©ν΄μ AIλ₯Ό νΈμΆνκ³ , OpenAI SDKλ₯Ό μ§μ μ€μΉνμ§ λ§.\n`;
|
|
581
|
-
md +=
|
|
589
|
+
md += `\n`;
|
|
590
|
+
md += `λ°°ν¬ κ·μΉ:\n`;
|
|
591
|
+
md += `- λ°±μλ: \`npx gencow deploy\` (gencow/ ν΄λλ§ λ°°ν¬λ¨. νλ‘ νΈμλλ ν¬ν¨ μ λ¨)\n`;
|
|
592
|
+
md += `- νλ‘ νΈμλ: VITE_API_URL=https://{μ±ID}.gencow.app npm run build ν \`npx gencow deploy --static dist/\`\n`;
|
|
593
|
+
md += `- gencow deployλ νλ‘ νΈμλλ₯Ό ν¬ν¨νμ§ μμ. λ°λμ λ³λλ‘ --static λ°°ν¬ν΄.\n`;
|
|
582
594
|
md += `- νκ²½λ³μλ \`npx gencow env set KEY=VALUE\`λ‘ κ΄λ¦¬ν΄.\n`;
|
|
583
595
|
md += `- .env νμΌμ λ‘컬 κ°λ° μ μ©μ΄μΌ. μλ²μλ gencow env pushλ‘ μ¬λ €.\n`;
|
|
584
596
|
md += `\`\`\`\n\n`;
|
|
@@ -654,13 +666,45 @@ function generateReadmeMd(config, apiObj) {
|
|
|
654
666
|
md += `\`\`\`\n\n`;
|
|
655
667
|
md += `> β οΈ \`export default crons\`κ° μμΌλ©΄ μλ²κ° cronμ μΈμνμ§ μμ΅λλ€.\n`;
|
|
656
668
|
md += `> β οΈ action λ¬Έμμ΄μ κΈ°μ‘΄ mutation μ΄λ¦κ³Ό μ νν λ§€μΉλμ΄μΌ ν©λλ€.\n\n`;
|
|
669
|
+
md += `> π‘ cron νΈλ€λ¬μμ mutationμ νΈμΆνλ €λ©΄ self-fetchλ₯Ό μ¬μ©νμΈμ:\n`;
|
|
670
|
+
md += `> \`\`\`typescript\n`;
|
|
671
|
+
md += `> const baseUrl = process.env.GENCOW_INTERNAL_URL || "http://localhost:5456";\n`;
|
|
672
|
+
md += `> await fetch(\`\${baseUrl}/api/mutation\`, { method: "POST", ... });\n`;
|
|
673
|
+
md += `> \`\`\`\n\n`;
|
|
674
|
+
|
|
675
|
+
// ββ 7. λ°°ν¬ ββββββββββββββββββββββββββββββββββββββββββββββ
|
|
676
|
+
md += `---\n\n## π λ°°ν¬\n\n`;
|
|
677
|
+
md += `### λ°±μλ API λ°°ν¬\n`;
|
|
678
|
+
md += `\`\`\`bash\n`;
|
|
679
|
+
md += `gencow deploy # gencow/ ν΄λ β ν΄λΌμ°λ μλ² λ°°ν¬\n`;
|
|
680
|
+
md += `\`\`\`\n\n`;
|
|
681
|
+
md += `### νλ‘ νΈμλ λ°°ν¬ (frontend/ μλ κ²½μ°)\n`;
|
|
682
|
+
md += `\`\`\`bash\n`;
|
|
683
|
+
md += `# 1. λ°±μλ URLμ νκ²½λ³μλ‘ λΉλ\n`;
|
|
684
|
+
md += `cd frontend\n`;
|
|
685
|
+
md += `VITE_API_URL=https://{μ±ID}.gencow.app npm run build\n\n`;
|
|
686
|
+
md += `# 2. λΉλ κ²°κ³Όλ¬Ό μ μ λ°°ν¬\n`;
|
|
687
|
+
md += `gencow deploy --static dist/\n`;
|
|
688
|
+
md += `\`\`\`\n\n`;
|
|
689
|
+
md += `### μ μ μ¬μ΄νΈ μ μ© (API μλ κ²½μ°)\n`;
|
|
690
|
+
md += `\`\`\`bash\n`;
|
|
691
|
+
md += `gencow deploy --static dist/ # μμ HTML/CSS/JSλ§ λ°°ν¬\n`;
|
|
692
|
+
md += `\`\`\`\n\n`;
|
|
693
|
+
md += `> β οΈ νλ‘ νΈμλμμ APIλ₯Ό νΈμΆνλ €λ©΄ λΉλ μ \`VITE_API_URL\`μ λ°λμ μ€μ νμΈμ.\n\n`;
|
|
694
|
+
md += `### CORS μ€μ \n\n`;
|
|
695
|
+
md += `- \`*.gencow.app\` μλΈλλ©μΈ κ° μμ²μ **μλ νμ©**λ©λλ€.\n`;
|
|
696
|
+
md += `- 컀μ€ν
λλ©μΈμμ APIλ₯Ό νΈμΆνλ €λ©΄ νκ²½λ³μλ₯Ό μ€μ νμΈμ:\n\n`;
|
|
697
|
+
md += `\`\`\`bash\n`;
|
|
698
|
+
md += `gencow env set CORS_ORIGINS=https://myapp.com,https://www.myapp.com\n`;
|
|
699
|
+
md += `\`\`\`\n\n`;
|
|
657
700
|
|
|
658
|
-
// ββ
|
|
701
|
+
// ββ 8. Dev Tips ββββββββββββββββββββββββββββββββββββββββ
|
|
659
702
|
md += `---\n\n## π‘ κ°λ° ν\n\n`;
|
|
660
703
|
md += `- \`gencow/\` ν΄λ λ΄ νμΌμ μμ νλ©΄ \`api.ts\`μ μ΄ READMEκ° **μλμΌλ‘ μ¬μμ±**λ©λλ€.\n`;
|
|
661
704
|
md += `- μ€ν€λ§ λ³κ²½ ν \`gencow db:push\`λ₯Ό μ€ννλ©΄ DBκ° μ¦μ λκΈ°νλ©λλ€.\n`;
|
|
662
705
|
md += `- MCP μλ²λ₯Ό μ¬μ©νλ©΄ AIκ° μ΄ κ΅¬μ‘°λ₯Ό μλμΌλ‘ μΈμν©λλ€.\n`;
|
|
663
706
|
md += `- λ‘컬 κ°λ°: \`gencow dev\` β \`http://localhost:5456\`\n`;
|
|
707
|
+
md += `- Self-fetch: \`process.env.GENCOW_INTERNAL_URL\` β cron/mutationμμ λ€λ₯Έ ν¨μ νΈμΆ μ μ¬μ©\n`;
|
|
664
708
|
md += `- .env νμΌμ λ‘컬 μ μ©. μλ²μλ \`gencow env push\`λ‘ μ¬λ¦¬μΈμ.\n`;
|
|
665
709
|
|
|
666
710
|
// ββ 5. κΈ°μ‘΄ μ»΄ν¬λνΈ μΉμ
보쑴 (gencow addλ‘ μΆκ°λ λΆλΆ) ββ
|
|
@@ -919,6 +963,39 @@ const commands = {
|
|
|
919
963
|
success("Created gencow/SECURITY.md (보μ κ°μ΄λ)");
|
|
920
964
|
}
|
|
921
965
|
|
|
966
|
+
// 3.7. crons.ts scaffold (ν¬λ‘ μ€μΌμ€λ¬ β λΉ ν
νλ¦Ώ)
|
|
967
|
+
const cronsPath = resolve(gencowDir, "crons.ts");
|
|
968
|
+
if (!existsSync(cronsPath)) {
|
|
969
|
+
writeFileSync(cronsPath, `/**
|
|
970
|
+
* gencow/crons.ts
|
|
971
|
+
* ν¬λ‘ μ€μΌμ€λ¬ μ μ β μ£ΌκΈ°μ μΌλ‘ μ€νν μμ
μ λ±λ‘ν©λλ€.
|
|
972
|
+
*
|
|
973
|
+
* β οΈ export default crons κ° μμΌλ©΄ μλ²κ° cronμ μΈμνμ§ μμ΅λλ€.
|
|
974
|
+
* β οΈ action λ¬Έμμ΄μ κΈ°μ‘΄ mutation μ΄λ¦κ³Ό μ νν λ§€μΉλμ΄μΌ ν©λλ€.
|
|
975
|
+
*/
|
|
976
|
+
import { cronJobs } from "@gencow/core";
|
|
977
|
+
|
|
978
|
+
const crons = cronJobs();
|
|
979
|
+
|
|
980
|
+
// βββ μμ (νμν κ²λ§ μ£Όμ ν΄μ ) ββββββββββββββββββββββ
|
|
981
|
+
|
|
982
|
+
// 30λΆλ§λ€ μ€ν
|
|
983
|
+
// crons.interval("crawlNews", { minutes: 30 }, "crawlPipeline.runStep1");
|
|
984
|
+
|
|
985
|
+
// λ§€μΌ KST 07:00 (UTC 22:00) μ€ν
|
|
986
|
+
// crons.daily("generateDigest", { hour: 22 }, "llmActions.generateDigest");
|
|
987
|
+
|
|
988
|
+
// λ§€μ£Ό μμμΌ 09:00 (UTC 00:00) μ€ν
|
|
989
|
+
// crons.weekly("weeklyReport", { dayOfWeek: 1, hour: 0 }, "reports.generateWeekly");
|
|
990
|
+
|
|
991
|
+
// cron ννμ μ§μ μ¬μ©
|
|
992
|
+
// crons.cron("customJob", "0 */6 * * *", "module.mutation");
|
|
993
|
+
|
|
994
|
+
export default crons;
|
|
995
|
+
`);
|
|
996
|
+
success("Created gencow/crons.ts (ν¬λ‘ μ€μΌμ€λ¬ ν
νλ¦Ώ)");
|
|
997
|
+
}
|
|
998
|
+
|
|
922
999
|
// 3.7. auth.ts (auth μ€μ β defineAuth κΈ°λ°, shadcn ν¨ν΄μΌλ‘ μ¬μ©μ μμ )
|
|
923
1000
|
const authConfigSource = resolve(__dirname, "..", "templates", "auth.ts");
|
|
924
1001
|
if (existsSync(authConfigSource)) {
|
|
@@ -2118,6 +2195,67 @@ ${BOLD}Examples:${RESET}
|
|
|
2118
2195
|
}
|
|
2119
2196
|
log("");
|
|
2120
2197
|
|
|
2198
|
+
// ββ κ°λλ μΌ 1: λΉλ κ²°κ³Όλ¬Ό API μ°Έμ‘° μ€μΊ ββββββββββββββ
|
|
2199
|
+
try {
|
|
2200
|
+
const fullTargetDir = resolve(process.cwd(), targetDir);
|
|
2201
|
+
const scanDir = (dir) => {
|
|
2202
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
2203
|
+
const files = [];
|
|
2204
|
+
for (const e of entries) {
|
|
2205
|
+
const p = resolve(dir, e.name);
|
|
2206
|
+
if (e.isDirectory() && e.name !== "node_modules") {
|
|
2207
|
+
files.push(...scanDir(p));
|
|
2208
|
+
} else if (e.isFile() && e.name.endsWith(".js")) {
|
|
2209
|
+
files.push(p);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
return files;
|
|
2213
|
+
};
|
|
2214
|
+
const jsFiles = scanDir(fullTargetDir);
|
|
2215
|
+
const apiRefFiles = [];
|
|
2216
|
+
for (const f of jsFiles) {
|
|
2217
|
+
const content = readFileSync(f, "utf8");
|
|
2218
|
+
if (content.includes("/api/query") || content.includes("/api/mutation")) {
|
|
2219
|
+
apiRefFiles.push(f.replace(fullTargetDir + "/", ""));
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
if (apiRefFiles.length > 0) {
|
|
2223
|
+
log("");
|
|
2224
|
+
warn(`λΉλ νμΌμμ API μ°Έμ‘°κ° λ°κ²¬λμμ΅λλ€:`);
|
|
2225
|
+
for (const f of apiRefFiles.slice(0, 5)) log(` ${DIM}- ${f}${RESET}`);
|
|
2226
|
+
if (apiRefFiles.length > 5) log(` ${DIM}... μΈ ${apiRefFiles.length - 5}κ°${RESET}`);
|
|
2227
|
+
log("");
|
|
2228
|
+
warn(`μ μ νΈμ€ν
μλ API μλ²κ° μμ΄ 404κ° λ°μν©λλ€.`);
|
|
2229
|
+
info(`π‘ λ°±μλκ° νμνλ€λ©΄: ${CYAN}VITE_API_URL=https://{backend}.gencow.app npm run build${RESET} ν λ°°ν¬`);
|
|
2230
|
+
info(`π‘ λ³λ λ°±μλλ₯Ό μ¬μ©νλ€λ©΄: ${CYAN}VITE_API_URL${RESET} νκ²½λ³μλ‘ λΉλ λμμ μ§μ νμΈμ.`);
|
|
2231
|
+
log("");
|
|
2232
|
+
|
|
2233
|
+
const { createInterface } = await import("readline");
|
|
2234
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2235
|
+
const answer = await new Promise(resolve => {
|
|
2236
|
+
rl.question(` ${YELLOW}β ${RESET} κ·Έλλ μ μ λ°°ν¬λ₯Ό κ³μνμκ² μ΅λκΉ? (y/N) `, resolve);
|
|
2237
|
+
});
|
|
2238
|
+
rl.close();
|
|
2239
|
+
if (answer.toLowerCase() !== "y") {
|
|
2240
|
+
info("λ°°ν¬ μ·¨μλ¨.");
|
|
2241
|
+
return;
|
|
2242
|
+
}
|
|
2243
|
+
log("");
|
|
2244
|
+
}
|
|
2245
|
+
} catch { /* μ€μΊ μ€ν¨ β 무μνκ³ μ§ν */ }
|
|
2246
|
+
|
|
2247
|
+
// ββ κ°λλ μΌ 2: λμΌ νλ‘μ νΈ λ°±μλ κ°μ§ βββββββββββββ
|
|
2248
|
+
const parentDir = resolve(process.cwd(), "..");
|
|
2249
|
+
const hasParentBackend = existsSync(resolve(parentDir, "gencow"))
|
|
2250
|
+
|| existsSync(resolve(parentDir, "gencow.config.ts"));
|
|
2251
|
+
const hasSelfBackend = existsSync(resolve(process.cwd(), "..", "gencow"))
|
|
2252
|
+
&& process.cwd().includes("frontend");
|
|
2253
|
+
if (hasParentBackend || hasSelfBackend) {
|
|
2254
|
+
warn(`μμ λλ ν 리μ Gencow λ°±μλ νλ‘μ νΈκ° κ°μ§λμμ΅λλ€.`);
|
|
2255
|
+
info(`π‘ ν΅ν© λ°°ν¬: ${CYAN}cd ${hasSelfBackend ? ".." : resolve(parentDir)} && gencow deploy${RESET}`);
|
|
2256
|
+
log("");
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2121
2259
|
// 1. tar.gz ν¨ν€μ§
|
|
2122
2260
|
info("μ μ νμΌ ν¨ν€μ§ μ€...");
|
|
2123
2261
|
const { execSync: exec } = await import("child_process");
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -72587,6 +72587,7 @@ var websocket2 = {
|
|
|
72587
72587
|
app.use("*", cors({
|
|
72588
72588
|
origin: (origin) => {
|
|
72589
72589
|
if (!origin || origin.startsWith("http://localhost")) return origin;
|
|
72590
|
+
if (origin.endsWith(".gencow.app")) return origin;
|
|
72590
72591
|
const allowed = process.env.CORS_ORIGINS?.split(",") ?? [];
|
|
72591
72592
|
return allowed.includes(origin) ? origin : "";
|
|
72592
72593
|
},
|
|
@@ -73420,6 +73421,9 @@ async function main() {
|
|
|
73420
73421
|
);
|
|
73421
73422
|
}
|
|
73422
73423
|
const port = Number(process.env.PORT || 5456);
|
|
73424
|
+
if (!process.env.GENCOW_INTERNAL_URL) {
|
|
73425
|
+
process.env.GENCOW_INTERNAL_URL = `http://localhost:${port}`;
|
|
73426
|
+
}
|
|
73423
73427
|
if (IS_BAAS && !process.env.PORT) {
|
|
73424
73428
|
console.error("[FATAL] BaaS app started without PORT env var. All apps would collide on :5456. Exiting.");
|
|
73425
73429
|
process.exit(1);
|