gencow 0.1.85 → 0.1.87
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 +14 -149
- package/lib/readme-codegen.mjs +3 -4
- package/package.json +1 -1
package/bin/gencow.mjs
CHANGED
|
@@ -1476,10 +1476,10 @@ ${BOLD}BaaS commands (login required):${RESET}
|
|
|
1476
1476
|
${DIM}--prod Deploy to production (confirmation required)${RESET}
|
|
1477
1477
|
${DIM}--name, -n Specify app name${RESET}
|
|
1478
1478
|
${DIM}--static [dir] Deploy static files (dist/, out/, build/)${RESET}
|
|
1479
|
-
${GREEN}env list${RESET} List cloud env vars
|
|
1480
|
-
${GREEN}env set K=V${RESET} Set cloud env var ${DIM}(
|
|
1481
|
-
${GREEN}env unset KEY${RESET} Remove cloud env var
|
|
1482
|
-
${GREEN}env push${RESET} Push .env to cloud
|
|
1479
|
+
${GREEN}env list${RESET} List cloud env vars
|
|
1480
|
+
${GREEN}env set K=V${RESET} Set cloud env var ${DIM}(hot-reload, no restart)${RESET}
|
|
1481
|
+
${GREEN}env unset KEY${RESET} Remove cloud env var
|
|
1482
|
+
${GREEN}env push${RESET} Push .env to cloud
|
|
1483
1483
|
${GREEN}domain set${RESET} Connect custom domain ${DIM}(myapp.com)${RESET}
|
|
1484
1484
|
${GREEN}domain status${RESET} Check domain DNS/TLS status
|
|
1485
1485
|
${GREEN}domain remove${RESET} Disconnect custom domain
|
|
@@ -3170,150 +3170,16 @@ process.exit(0);
|
|
|
3170
3170
|
});
|
|
3171
3171
|
},
|
|
3172
3172
|
|
|
3173
|
-
// ── env — 환경변수 관리 (Cloud
|
|
3173
|
+
// ── env — 환경변수 관리 (Cloud only) ─────────
|
|
3174
3174
|
async env(...envArgs) {
|
|
3175
|
-
// ── --local 플래그 파싱 ──
|
|
3176
|
-
const isLocal = envArgs.includes("--local");
|
|
3177
3175
|
const filteredArgs = envArgs.filter(a => a !== "--local");
|
|
3178
3176
|
const subcmd = filteredArgs[0] || "list";
|
|
3179
3177
|
|
|
3180
|
-
//
|
|
3181
|
-
if (
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
// ── local env list ──
|
|
3187
|
-
if (subcmd === "list") {
|
|
3188
|
-
try {
|
|
3189
|
-
const res = await fetch(base);
|
|
3190
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3191
|
-
const vars = await res.json();
|
|
3192
|
-
|
|
3193
|
-
log(`\n${BOLD}Environment Variables${RESET} ${DIM}(local, ${vars.length} total)${RESET}\n`);
|
|
3194
|
-
|
|
3195
|
-
if (vars.length === 0) {
|
|
3196
|
-
info("No environment variables configured.");
|
|
3197
|
-
info(`Use ${GREEN}gencow env set --local KEY=VALUE${RESET} to add one.`);
|
|
3198
|
-
} else {
|
|
3199
|
-
const maxLen = Math.max(...vars.map(v => v.name.length), 4);
|
|
3200
|
-
log(` ${DIM}${"NAME".padEnd(maxLen)} VALUE${RESET}`);
|
|
3201
|
-
log(` ${DIM}${"─".repeat(maxLen)} ${"─".repeat(20)}${RESET}`);
|
|
3202
|
-
for (const v of vars) {
|
|
3203
|
-
log(` ${BOLD}${v.name.padEnd(maxLen)}${RESET} ${DIM}${v.maskedValue}${RESET}`);
|
|
3204
|
-
}
|
|
3205
|
-
}
|
|
3206
|
-
log("");
|
|
3207
|
-
} catch (e) {
|
|
3208
|
-
error(`Failed to fetch env vars: ${e.message}`);
|
|
3209
|
-
info(`Make sure the local dev server is running (gencow dev --local)`);
|
|
3210
|
-
}
|
|
3211
|
-
return;
|
|
3212
|
-
}
|
|
3213
|
-
|
|
3214
|
-
// ── local env set KEY=VALUE ──
|
|
3215
|
-
if (subcmd === "set") {
|
|
3216
|
-
const pairs = filteredArgs.slice(1);
|
|
3217
|
-
if (pairs.length === 0) {
|
|
3218
|
-
error("Usage: gencow env set --local KEY=VALUE [KEY2=VALUE2 ...]");
|
|
3219
|
-
return;
|
|
3220
|
-
}
|
|
3221
|
-
for (const pair of pairs) {
|
|
3222
|
-
const eqIdx = pair.indexOf("=");
|
|
3223
|
-
if (eqIdx < 1) { error(`Invalid format: ${pair}. Use KEY=VALUE`); continue; }
|
|
3224
|
-
const name = pair.slice(0, eqIdx).trim();
|
|
3225
|
-
const value = pair.slice(eqIdx + 1).trim();
|
|
3226
|
-
if (!name) { error("Key name cannot be empty"); continue; }
|
|
3227
|
-
if (!value) { error(`Value for ${name} cannot be empty`); continue; }
|
|
3228
|
-
|
|
3229
|
-
try {
|
|
3230
|
-
const res = await fetch(base, {
|
|
3231
|
-
method: "POST",
|
|
3232
|
-
headers: { "Content-Type": "application/json" },
|
|
3233
|
-
body: JSON.stringify({ name, value }),
|
|
3234
|
-
});
|
|
3235
|
-
if (!res.ok) {
|
|
3236
|
-
const body = await res.json().catch(() => ({}));
|
|
3237
|
-
throw new Error(body.error || `HTTP ${res.status}`);
|
|
3238
|
-
}
|
|
3239
|
-
success(`Set ${BOLD}${name}${RESET} ${DIM}(local)${RESET}`);
|
|
3240
|
-
} catch (e) {
|
|
3241
|
-
error(`Failed to set ${name}: ${e.message}`);
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
log(`\n ${DIM}⚠ Restart local server to apply changes${RESET}\n`);
|
|
3245
|
-
return;
|
|
3246
|
-
}
|
|
3247
|
-
|
|
3248
|
-
// ── local env unset KEY ──
|
|
3249
|
-
if (subcmd === "unset" || subcmd === "remove" || subcmd === "delete") {
|
|
3250
|
-
const keys = filteredArgs.slice(1);
|
|
3251
|
-
if (keys.length === 0) { error("Usage: gencow env unset --local KEY [KEY2 ...]"); return; }
|
|
3252
|
-
for (const key of keys) {
|
|
3253
|
-
try {
|
|
3254
|
-
const res = await fetch(`${base}/${encodeURIComponent(key)}`, { method: "DELETE" });
|
|
3255
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3256
|
-
success(`Removed ${BOLD}${key}${RESET} ${DIM}(local)${RESET}`);
|
|
3257
|
-
} catch (e) {
|
|
3258
|
-
error(`Failed to remove ${key}: ${e.message}`);
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
log(`\n ${DIM}⚠ Restart local server to apply changes${RESET}\n`);
|
|
3262
|
-
return;
|
|
3263
|
-
}
|
|
3264
|
-
|
|
3265
|
-
// ── local env push ──
|
|
3266
|
-
if (subcmd === "push") {
|
|
3267
|
-
const envPath = resolve(process.cwd(), ".env");
|
|
3268
|
-
if (!existsSync(envPath)) { error("No .env file found in current directory"); return; }
|
|
3269
|
-
|
|
3270
|
-
const content = readFileSync(envPath, "utf-8");
|
|
3271
|
-
const pairs = [];
|
|
3272
|
-
for (const line of content.split("\n")) {
|
|
3273
|
-
const trimmed = line.trim();
|
|
3274
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3275
|
-
const eqIdx = trimmed.indexOf("=");
|
|
3276
|
-
if (eqIdx < 1) continue;
|
|
3277
|
-
const key = trimmed.slice(0, eqIdx).trim();
|
|
3278
|
-
let val = trimmed.slice(eqIdx + 1).trim();
|
|
3279
|
-
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
3280
|
-
val = val.slice(1, -1);
|
|
3281
|
-
}
|
|
3282
|
-
if (key && val) pairs.push({ key, val });
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3285
|
-
if (pairs.length === 0) { warn("No valid KEY=VALUE pairs found in .env"); return; }
|
|
3286
|
-
|
|
3287
|
-
log(`\n${BOLD}Pushing .env${RESET} ${DIM}(local, ${pairs.length} variables)${RESET}\n`);
|
|
3288
|
-
|
|
3289
|
-
let ok = 0, fail = 0;
|
|
3290
|
-
for (const { key, val } of pairs) {
|
|
3291
|
-
try {
|
|
3292
|
-
const res = await fetch(base, {
|
|
3293
|
-
method: "POST",
|
|
3294
|
-
headers: { "Content-Type": "application/json" },
|
|
3295
|
-
body: JSON.stringify({ name: key, value: val }),
|
|
3296
|
-
});
|
|
3297
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3298
|
-
success(`${key}`);
|
|
3299
|
-
ok++;
|
|
3300
|
-
} catch {
|
|
3301
|
-
error(`${key}`);
|
|
3302
|
-
fail++;
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
|
|
3306
|
-
log(`\n ${GREEN}${ok} set${RESET}${fail > 0 ? `, ${RED}${fail} failed${RESET}` : ""}`);
|
|
3307
|
-
log(` ${DIM}⚠ Restart local server to apply changes${RESET}\n`);
|
|
3308
|
-
return;
|
|
3309
|
-
}
|
|
3310
|
-
|
|
3311
|
-
error(`Unknown env subcommand: ${subcmd}`);
|
|
3312
|
-
log(`\n ${BOLD}Usage (local):${RESET}`);
|
|
3313
|
-
log(` gencow env list --local List local env vars`);
|
|
3314
|
-
log(` gencow env set --local K=V Set local variable(s)`);
|
|
3315
|
-
log(` gencow env unset --local KEY Remove local variable(s)`);
|
|
3316
|
-
log(` gencow env push --local Push .env to local server\n`);
|
|
3178
|
+
// --local 사용 시 .env 파일 사용 안내
|
|
3179
|
+
if (envArgs.includes("--local")) {
|
|
3180
|
+
warn(`--local flag has been removed.`);
|
|
3181
|
+
info(`For local development, use .env file directly.`);
|
|
3182
|
+
info(`Changes in .env are loaded automatically when running ${GREEN}gencow dev${RESET}.\n`);
|
|
3317
3183
|
return;
|
|
3318
3184
|
}
|
|
3319
3185
|
|
|
@@ -3331,7 +3197,7 @@ process.exit(0);
|
|
|
3331
3197
|
if (!appId) {
|
|
3332
3198
|
error("No gencow.json found. Cannot determine cloud app.");
|
|
3333
3199
|
info(`Run ${GREEN}gencow deploy${RESET} first to create a cloud app.`);
|
|
3334
|
-
info(`Or use ${GREEN}
|
|
3200
|
+
info(`Or use ${GREEN}.env${RESET} file for local development.`);
|
|
3335
3201
|
return;
|
|
3336
3202
|
}
|
|
3337
3203
|
|
|
@@ -3422,7 +3288,7 @@ process.exit(0);
|
|
|
3422
3288
|
error(`Failed to remove ${key}: ${e.message}`);
|
|
3423
3289
|
}
|
|
3424
3290
|
}
|
|
3425
|
-
log(`\n ${DIM}
|
|
3291
|
+
log(`\n ${DIM}⚡ Changes apply instantly — no restart needed${RESET}\n`);
|
|
3426
3292
|
return;
|
|
3427
3293
|
}
|
|
3428
3294
|
|
|
@@ -3470,7 +3336,7 @@ process.exit(0);
|
|
|
3470
3336
|
error(`Failed to push env vars: ${e.message}`);
|
|
3471
3337
|
}
|
|
3472
3338
|
|
|
3473
|
-
log(` ${DIM}
|
|
3339
|
+
log(` ${DIM}⚡ Changes apply instantly — no restart needed${RESET}\n`);
|
|
3474
3340
|
return;
|
|
3475
3341
|
}
|
|
3476
3342
|
|
|
@@ -3480,8 +3346,7 @@ process.exit(0);
|
|
|
3480
3346
|
log(` gencow env list List cloud env vars`);
|
|
3481
3347
|
log(` gencow env set K=V Set cloud variable(s)`);
|
|
3482
3348
|
log(` gencow env unset KEY Remove cloud variable(s)`);
|
|
3483
|
-
log(` gencow env push Push .env to cloud`);
|
|
3484
|
-
log(` ${DIM}Add --local for local dev server${RESET}\n`);
|
|
3349
|
+
log(` gencow env push Push .env to cloud\n`);
|
|
3485
3350
|
},
|
|
3486
3351
|
|
|
3487
3352
|
async platform() {
|
package/lib/readme-codegen.mjs
CHANGED
|
@@ -306,7 +306,7 @@ export function buildAiPrompt(apiObj, namespaces) {
|
|
|
306
306
|
md += `- 환경변수는 \`npx gencow env set KEY=VALUE\`로 클라우드에 설정해. 즉시 반영 (재시작 불필요).\n`;
|
|
307
307
|
md += `- process.env.KEY는 반드시 handler 내부에서 접근해 (모듈 상단 캐싱 시 hot-reload 안 됨).\n`;
|
|
308
308
|
md += `- .env 파일은 로컬 개발 전용이야. 클라우드에는 gencow env push로 올려.\n`;
|
|
309
|
-
md += `- 로컬
|
|
309
|
+
md += `- 로컬 개발은 .env 파일 사용 (gencow dev가 자동 로드).\n`;
|
|
310
310
|
md += `\n`;
|
|
311
311
|
md += `⚠️ 데이터 격리 (보안 필수):\n`;
|
|
312
312
|
md += `- 스키마에서 gencowTable()을 사용해. pgTable() 대신.\n`;
|
|
@@ -388,8 +388,7 @@ export function buildDeploySection() {
|
|
|
388
388
|
md += `| \`gencow env list\` | 클라우드 환경변수 목록 |\n`;
|
|
389
389
|
md += `| \`gencow env set KEY=VALUE\` | 클라우드 환경변수 추가/수정 (즉시 반영) |\n`;
|
|
390
390
|
md += `| \`gencow env unset KEY\` | 클라우드 환경변수 삭제 (즉시 반영) |\n`;
|
|
391
|
-
md += `| \`gencow env push\` | .env를 클라우드에 일괄 업로드 |\n`;
|
|
392
|
-
md += `| \`--local\` 옵션 | 로컬 dev 서버 대상 (예: \`env set --local K=V\`) |\n\n`;
|
|
391
|
+
md += `| \`gencow env push\` | .env를 클라우드에 일괄 업로드 |\n\n`;
|
|
393
392
|
md += `> ⚡ **Hot-Reload:** 환경변수는 앱 재시작 없이 즉시 반영됩니다.\n`;
|
|
394
393
|
md += `> 단, \`process.env.KEY\`를 모듈 최상단에서 캐싱하면 반영되지 않습니다.\n`;
|
|
395
394
|
md += `> 반드시 handler 내부에서 접근하세요:\n\n`;
|
|
@@ -502,7 +501,7 @@ export function buildDevTips() {
|
|
|
502
501
|
md += `- 로컬 개발: \`gencow dev\` — 로컬 서버 시작\n`;
|
|
503
502
|
md += `- 배포된 앱: \`https://{앱ID}.gencow.app\` — .env의 VITE_API_URL에 자동 설정됨\n`;
|
|
504
503
|
md += `- Self-fetch: \`process.env.GENCOW_INTERNAL_URL\` — cron/mutation에서 다른 함수 호출 시 사용 (자동 설정)\n`;
|
|
505
|
-
md += `- .env 파일은 로컬 전용. 클라우드에는 \`gencow env push\`로
|
|
504
|
+
md += `- .env 파일은 로컬 전용. 클라우드에는 \`gencow env push\`로 올리세요.\n`;
|
|
506
505
|
return md;
|
|
507
506
|
}
|
|
508
507
|
|