gencow 0.1.39 → 0.1.40
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 +154 -24
- package/package.json +29 -28
- package/server/index.js +29 -11
- package/server/index.js.map +2 -2
package/bin/gencow.mjs
CHANGED
|
@@ -457,7 +457,7 @@ function generateReadmeMd(config, apiObj) {
|
|
|
457
457
|
md += `\`\`\`\n\n`;
|
|
458
458
|
md += `또는 \`gencowAuth()\`에 명시적으로 baseUrl을 전달하세요:\n\n`;
|
|
459
459
|
md += `\`\`\`typescript\n`;
|
|
460
|
-
md += `const { signIn, useAuth } = gencowAuth(
|
|
460
|
+
md += `const { signIn, useAuth } = gencowAuth(import.meta.env.VITE_API_URL || "http://localhost:5456");\n`;
|
|
461
461
|
md += `\`\`\`\n\n`;
|
|
462
462
|
|
|
463
463
|
// ── 1-3. RPC 직접 호출 (접힘 — 비-React 환경용) ──────────
|
|
@@ -561,7 +561,7 @@ function generateReadmeMd(config, apiObj) {
|
|
|
561
561
|
md += `npx gencow env set DATABASE_URL=postgres://...\n`;
|
|
562
562
|
md += `npx gencow env list\n`;
|
|
563
563
|
md += `\`\`\`\n\n`;
|
|
564
|
-
md += `> 배포 후 앱은 \`https://{앱이름}.gencow.
|
|
564
|
+
md += `> 배포 후 앱은 \`https://{앱이름}.gencow.app\`에서 접근 가능\n\n`;
|
|
565
565
|
md += `### 환경변수 관리\n\n`;
|
|
566
566
|
md += `| 명령어 | 설명 |\n`;
|
|
567
567
|
md += `| :--- | :--- |\n`;
|
|
@@ -599,28 +599,32 @@ function generateReadmeMd(config, apiObj) {
|
|
|
599
599
|
// ─── Deploy → .env.local 자동 업데이트 ────────────────────
|
|
600
600
|
function updateEnvLocalUrl(deployUrl) {
|
|
601
601
|
if (!deployUrl) return;
|
|
602
|
-
const envKey = "
|
|
603
|
-
const
|
|
602
|
+
const envKey = "VITE_API_URL";
|
|
603
|
+
const envPath = resolve(process.cwd(), ".env");
|
|
604
604
|
|
|
605
605
|
try {
|
|
606
606
|
let content = "";
|
|
607
|
-
try { content = readFileSync(
|
|
607
|
+
try { content = readFileSync(envPath, "utf-8"); } catch { /* doesn't exist yet */ }
|
|
608
608
|
|
|
609
609
|
const line = `${envKey}=${deployUrl}`;
|
|
610
610
|
const regex = new RegExp(`^${envKey}=.*$`, "m");
|
|
611
611
|
|
|
612
|
-
|
|
612
|
+
// 기존 NEXT_PUBLIC_GENCOW_URL 도 함께 치환 (레거시 호환)
|
|
613
|
+
const legacyRegex = /^NEXT_PUBLIC_GENCOW_URL=.*$/m;
|
|
614
|
+
if (legacyRegex.test(content)) {
|
|
615
|
+
content = content.replace(legacyRegex, line);
|
|
616
|
+
} else if (regex.test(content)) {
|
|
613
617
|
content = content.replace(regex, line);
|
|
614
618
|
} else {
|
|
615
619
|
content = content.trimEnd() + (content ? "\n" : "") + line + "\n";
|
|
616
620
|
}
|
|
617
621
|
|
|
618
|
-
writeFileSync(
|
|
619
|
-
success(`.env
|
|
620
|
-
info(` ${DIM}Vercel
|
|
622
|
+
writeFileSync(envPath, content);
|
|
623
|
+
success(`.env에 ${envKey} 자동 설정됨`);
|
|
624
|
+
info(` ${DIM}배포 플랫폼(Vercel 등) 환경변수에도 추가하세요:${RESET}`);
|
|
621
625
|
info(` ${envKey}=${deployUrl}`);
|
|
622
626
|
} catch (e) {
|
|
623
|
-
warn(`.env
|
|
627
|
+
warn(`.env 업데이트 실패: ${e.message}`);
|
|
624
628
|
}
|
|
625
629
|
}
|
|
626
630
|
|
|
@@ -1306,7 +1310,7 @@ ${hasPrompt ? `
|
|
|
1306
1310
|
// ── help ─────────────────────────────────────────────
|
|
1307
1311
|
help() {
|
|
1308
1312
|
log(`
|
|
1309
|
-
${BOLD}${CYAN}Gencow CLI${RESET} ${DIM}— Backend
|
|
1313
|
+
${BOLD}${CYAN}Gencow CLI${RESET} ${DIM}— AI Backend Engine${RESET}
|
|
1310
1314
|
|
|
1311
1315
|
${BOLD}Usage:${RESET}
|
|
1312
1316
|
gencow <command>
|
|
@@ -1331,8 +1335,9 @@ ${BOLD}BaaS commands (login required):${RESET}
|
|
|
1331
1335
|
${GREEN}logout${RESET} Clear credentials
|
|
1332
1336
|
${GREEN}whoami${RESET} Show current user info
|
|
1333
1337
|
${GREEN}deploy${RESET} Bundle gencow/ and deploy to platform
|
|
1334
|
-
${DIM}--prod
|
|
1338
|
+
${DIM}--prod Deploy to production (confirmation required)${RESET}
|
|
1335
1339
|
${DIM}--name, -n Specify app name${RESET}
|
|
1340
|
+
${DIM}--static [dir] Deploy static files (dist/, out/, build/)${RESET}
|
|
1336
1341
|
${GREEN}env list${RESET} List remote env vars ${DIM}(--prod for production)${RESET}
|
|
1337
1342
|
${GREEN}env set K=V${RESET} Set remote env var
|
|
1338
1343
|
${GREEN}env unset KEY${RESET} Remove remote env var
|
|
@@ -1357,7 +1362,7 @@ ${BOLD}Examples:${RESET}
|
|
|
1357
1362
|
async login() {
|
|
1358
1363
|
log(`\n${BOLD}${CYAN}Gencow Login${RESET}\n`);
|
|
1359
1364
|
|
|
1360
|
-
const platformUrl = process.env.GENCOW_PLATFORM_URL || "https://gencow.
|
|
1365
|
+
const platformUrl = process.env.GENCOW_PLATFORM_URL || "https://gencow.app";
|
|
1361
1366
|
info(`Platform: ${platformUrl}`);
|
|
1362
1367
|
|
|
1363
1368
|
// 1. auth-start → 인증 코드 생성
|
|
@@ -1502,11 +1507,22 @@ ${BOLD}Examples:${RESET}
|
|
|
1502
1507
|
let appId = null;
|
|
1503
1508
|
let displayName = null;
|
|
1504
1509
|
let envTarget = "dev";
|
|
1510
|
+
let staticDir = null; // --static 옵션
|
|
1511
|
+
let isStatic = false;
|
|
1505
1512
|
|
|
1506
1513
|
for (let i = 0; i < deployArgs.length; i++) {
|
|
1507
1514
|
const a = deployArgs[i];
|
|
1508
1515
|
if (a === "--prod") envTarget = "prod";
|
|
1509
1516
|
else if (a === "--app" || a === "-a") appId = deployArgs[++i];
|
|
1517
|
+
else if (a === "--static") {
|
|
1518
|
+
isStatic = true;
|
|
1519
|
+
// 다음 인자가 옵션이 아니면 디렉토리로 사용
|
|
1520
|
+
const next = deployArgs[i + 1];
|
|
1521
|
+
if (next && !next.startsWith("-")) {
|
|
1522
|
+
staticDir = next;
|
|
1523
|
+
i++;
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1510
1526
|
}
|
|
1511
1527
|
|
|
1512
1528
|
// gencow.json에서 appId 로드
|
|
@@ -1525,6 +1541,11 @@ ${BOLD}Examples:${RESET}
|
|
|
1525
1541
|
}
|
|
1526
1542
|
if (!displayName) displayName = basename(process.cwd());
|
|
1527
1543
|
|
|
1544
|
+
// ── Static Deploy 분기 ────────────────────────────────
|
|
1545
|
+
if (isStatic) {
|
|
1546
|
+
return await this._deployStatic(creds, appId, displayName, staticDir, gencowJsonPath);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1528
1549
|
log(`\n${BOLD}${CYAN}Gencow Deploy${RESET}\n`);
|
|
1529
1550
|
if (appId) {
|
|
1530
1551
|
info(`앱 ID: ${appId}`);
|
|
@@ -1709,6 +1730,115 @@ ${BOLD}Examples:${RESET}
|
|
|
1709
1730
|
}
|
|
1710
1731
|
},
|
|
1711
1732
|
|
|
1733
|
+
// ── deploy --static 내부 헬퍼 ─────────────────────────
|
|
1734
|
+
async _deployStatic(creds, appId, displayName, staticDirArg, gencowJsonPath) {
|
|
1735
|
+
// 정적 폴더 자동 감지
|
|
1736
|
+
const AUTO_DETECT = ["dist", "out", "build", ".next/out"];
|
|
1737
|
+
let targetDir = staticDirArg;
|
|
1738
|
+
|
|
1739
|
+
if (!targetDir) {
|
|
1740
|
+
for (const candidate of AUTO_DETECT) {
|
|
1741
|
+
const p = resolve(process.cwd(), candidate);
|
|
1742
|
+
if (existsSync(p)) {
|
|
1743
|
+
targetDir = candidate;
|
|
1744
|
+
break;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
if (!targetDir || !existsSync(resolve(process.cwd(), targetDir))) {
|
|
1750
|
+
error(`정적 파일 폴더를 찾을 수 없습니다.`);
|
|
1751
|
+
info(`자동 감지 순서: ${AUTO_DETECT.join(", ")}`);
|
|
1752
|
+
info(`수동 지정: gencow deploy --static <dir>`);
|
|
1753
|
+
process.exit(1);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
log(`\n${BOLD}${CYAN}Gencow Static Deploy${RESET}\n`);
|
|
1757
|
+
info(`폴더: ${targetDir}/`);
|
|
1758
|
+
if (appId) {
|
|
1759
|
+
info(`앱 ID: ${appId}`);
|
|
1760
|
+
} else {
|
|
1761
|
+
info(`앱: 신규 (ID 자동 생성)`);
|
|
1762
|
+
}
|
|
1763
|
+
log("");
|
|
1764
|
+
|
|
1765
|
+
// 1. tar.gz 패키징
|
|
1766
|
+
info("정적 파일 패키징 중...");
|
|
1767
|
+
const { execSync: exec } = await import("child_process");
|
|
1768
|
+
const tmpBundle = resolve(process.cwd(), ".gencow", "static-bundle.tar.gz");
|
|
1769
|
+
mkdirSync(dirname(tmpBundle), { recursive: true });
|
|
1770
|
+
|
|
1771
|
+
try {
|
|
1772
|
+
exec(`tar -czf "${tmpBundle}" -C "${resolve(process.cwd(), targetDir)}" .`, { cwd: process.cwd() });
|
|
1773
|
+
} catch (e) {
|
|
1774
|
+
error(`패키징 실패: ${e.message}`);
|
|
1775
|
+
process.exit(1);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
const bundleSize = statSync(tmpBundle).size;
|
|
1779
|
+
const MAX_SIZE = 100 * 1024 * 1024;
|
|
1780
|
+
if (bundleSize > MAX_SIZE) {
|
|
1781
|
+
error(`번들이 너무 큽니다: ${(bundleSize / (1024 * 1024)).toFixed(1)} MB (최대 100 MB)`);
|
|
1782
|
+
try { unlinkSync(tmpBundle); } catch { }
|
|
1783
|
+
process.exit(1);
|
|
1784
|
+
}
|
|
1785
|
+
success(`번들 생성: ${(bundleSize / 1024).toFixed(1)} KB`);
|
|
1786
|
+
|
|
1787
|
+
// 2. 앱이 없으면 생성
|
|
1788
|
+
if (!appId) {
|
|
1789
|
+
info("앱 생성 중 (ID 자동 생성)...");
|
|
1790
|
+
const createRes = await rpcMutation(creds, "apps.create", { name: displayName });
|
|
1791
|
+
if (!createRes.ok) {
|
|
1792
|
+
const createErr = await createRes.json().catch(() => ({}));
|
|
1793
|
+
error(`앱 생성 실패: ${createErr.error || createRes.statusText}`);
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1796
|
+
const createData = await createRes.json();
|
|
1797
|
+
appId = createData.appId || createData.name;
|
|
1798
|
+
success(`앱 "${appId}" 생성 완료. 프로비저닝 대기 중...`);
|
|
1799
|
+
writeFileSync(gencowJsonPath, JSON.stringify({
|
|
1800
|
+
appId, displayName, platformUrl: creds.platformUrl,
|
|
1801
|
+
}, null, 2));
|
|
1802
|
+
info(`${DIM}gencow.json 생성됨 (appId: ${appId})${RESET}`);
|
|
1803
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
// 3. 업로드
|
|
1807
|
+
info("정적 파일 배포 중...");
|
|
1808
|
+
const bundleBuffer = readFileSync(tmpBundle);
|
|
1809
|
+
|
|
1810
|
+
const deployRes = await platformFetch(creds, `/platform/apps/${appId}/deploy-static`, {
|
|
1811
|
+
method: "POST",
|
|
1812
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
1813
|
+
body: bundleBuffer,
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
try { unlinkSync(tmpBundle); } catch { }
|
|
1817
|
+
|
|
1818
|
+
if (!deployRes.ok) {
|
|
1819
|
+
const errData = await deployRes.json().catch(() => ({}));
|
|
1820
|
+
error(`정적 배포 실패: ${errData.error || deployRes.statusText}`);
|
|
1821
|
+
process.exit(1);
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
const data = await deployRes.json();
|
|
1825
|
+
log("");
|
|
1826
|
+
success(`정적 배포 완료!`);
|
|
1827
|
+
info(`앱 ID: ${appId}`);
|
|
1828
|
+
info(`URL: ${data.url}`);
|
|
1829
|
+
info(`파일: ${data.files}개 (${(data.size / 1024).toFixed(1)} KB)`);
|
|
1830
|
+
info(`Hash: ${data.bundleHash}`);
|
|
1831
|
+
if (data.deployId) info(`ID: ${data.deployId}`);
|
|
1832
|
+
updateEnvLocalUrl(data.url);
|
|
1833
|
+
log("");
|
|
1834
|
+
|
|
1835
|
+
if (!existsSync(gencowJsonPath)) {
|
|
1836
|
+
writeFileSync(gencowJsonPath, JSON.stringify({
|
|
1837
|
+
appId, displayName, platformUrl: creds.platformUrl,
|
|
1838
|
+
}, null, 2));
|
|
1839
|
+
}
|
|
1840
|
+
},
|
|
1841
|
+
|
|
1712
1842
|
// ── env ───────────────────────────────────────────────
|
|
1713
1843
|
async env(...envArgs) {
|
|
1714
1844
|
const creds = requireCreds();
|
|
@@ -2113,18 +2243,18 @@ process.exit(0);
|
|
|
2113
2243
|
const cwd = process.cwd();
|
|
2114
2244
|
const config = loadConfig();
|
|
2115
2245
|
|
|
2116
|
-
// 1. .env
|
|
2117
|
-
const
|
|
2118
|
-
const envLine = `
|
|
2119
|
-
if (existsSync(
|
|
2120
|
-
let envContent = readFileSync(
|
|
2121
|
-
if (!envContent.includes("
|
|
2122
|
-
writeFileSync(
|
|
2123
|
-
success(`.env
|
|
2246
|
+
// 1. .env — GENCOW_URL for frontend
|
|
2247
|
+
const envFilePath = resolve(cwd, ".env");
|
|
2248
|
+
const envLine = `VITE_API_URL=${data.url}`;
|
|
2249
|
+
if (existsSync(envFilePath)) {
|
|
2250
|
+
let envContent = readFileSync(envFilePath, "utf8");
|
|
2251
|
+
if (!envContent.includes("VITE_API_URL")) {
|
|
2252
|
+
writeFileSync(envFilePath, envContent.trimEnd() + "\n" + envLine + "\n");
|
|
2253
|
+
success(`.env — added VITE_API_URL`);
|
|
2124
2254
|
}
|
|
2125
2255
|
} else {
|
|
2126
|
-
writeFileSync(
|
|
2127
|
-
success(`.env
|
|
2256
|
+
writeFileSync(envFilePath, `# Gencow app backend URL\n${envLine}\n`);
|
|
2257
|
+
success(`.env — created`);
|
|
2128
2258
|
}
|
|
2129
2259
|
|
|
2130
2260
|
// 2. gencow/ starter — create index.ts if folder is empty/missing
|
|
@@ -2152,7 +2282,7 @@ process.exit(0);
|
|
|
2152
2282
|
${BOLD}App ready:${RESET}
|
|
2153
2283
|
${GREEN}▸${RESET} API: ${data.url}
|
|
2154
2284
|
${GREEN}▸${RESET} Dashboard: ${data.dashboard}
|
|
2155
|
-
${GREEN}▸${RESET} .env
|
|
2285
|
+
${GREEN}▸${RESET} .env: VITE_API_URL set
|
|
2156
2286
|
|
|
2157
2287
|
${DIM}pnpm gencow dev:remote — watch & auto-deploy${RESET}
|
|
2158
2288
|
`);
|
package/package.json
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
2
|
+
"name": "gencow",
|
|
3
|
+
"version": "0.1.40",
|
|
4
|
+
"description": "Gencow — AI Backend Engine",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gencow": "./bin/gencow.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"templates/",
|
|
12
|
+
"server/",
|
|
13
|
+
"scripts/",
|
|
14
|
+
"dashboard/"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "node scripts/bundle-server.mjs",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
22
|
+
"open": "^10.1.0",
|
|
23
|
+
"tar": "^7",
|
|
24
|
+
"ws": "^8.19.0",
|
|
25
|
+
"zod": "^4.3.6"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25",
|
|
29
|
+
"esbuild": "^0.27.3"
|
|
30
|
+
}
|
|
30
31
|
}
|
package/server/index.js
CHANGED
|
@@ -70170,14 +70170,18 @@ function storageRoutes(storage, rawSql, storageDir) {
|
|
|
70170
70170
|
if (!meta5) {
|
|
70171
70171
|
return c.json({ error: "Not found" }, 404);
|
|
70172
70172
|
}
|
|
70173
|
+
const headers = {
|
|
70174
|
+
"Content-Type": meta5.type,
|
|
70175
|
+
"Content-Disposition": `inline; filename="${encodeURIComponent(meta5.name)}"; filename*=UTF-8''${encodeURIComponent(meta5.name)}`,
|
|
70176
|
+
"Cache-Control": "public, max-age=31536000, immutable"
|
|
70177
|
+
};
|
|
70178
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
70179
|
+
const bunFile = Bun.file(meta5.path);
|
|
70180
|
+
return new Response(bunFile, { headers });
|
|
70181
|
+
}
|
|
70173
70182
|
const file3 = await fs.readFile(meta5.path);
|
|
70174
|
-
|
|
70175
|
-
|
|
70176
|
-
"Content-Type": meta5.type,
|
|
70177
|
-
"Content-Disposition": `attachment; filename="${encodeURIComponent(meta5.name)}"; filename*=UTF-8''${encodeURIComponent(meta5.name)}`,
|
|
70178
|
-
"Content-Length": String(meta5.size)
|
|
70179
|
-
}
|
|
70180
|
-
});
|
|
70183
|
+
headers["Content-Length"] = String(file3.byteLength);
|
|
70184
|
+
return c.body(file3, 200, headers);
|
|
70181
70185
|
};
|
|
70182
70186
|
}
|
|
70183
70187
|
|
|
@@ -71853,6 +71857,17 @@ async function main() {
|
|
|
71853
71857
|
process.exit(1);
|
|
71854
71858
|
}
|
|
71855
71859
|
}
|
|
71860
|
+
try {
|
|
71861
|
+
await rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS display_name TEXT`);
|
|
71862
|
+
await rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS plan TEXT DEFAULT 'free'`);
|
|
71863
|
+
await rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS current_deploy_id INTEGER`);
|
|
71864
|
+
await rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS static_deployed_at TIMESTAMP`);
|
|
71865
|
+
await rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS static_size BIGINT`);
|
|
71866
|
+
await rawSql(`ALTER TABLE deployments ADD COLUMN IF NOT EXISTS env TEXT DEFAULT 'dev'`);
|
|
71867
|
+
console.log("[db] schema upgrade \u2713");
|
|
71868
|
+
} catch (e) {
|
|
71869
|
+
console.warn("[db] schema upgrade warning:", e?.message);
|
|
71870
|
+
}
|
|
71856
71871
|
const storageDir = process.env.GENCOW_STORAGE || "./uploads";
|
|
71857
71872
|
const storage = createStorage(storageDir);
|
|
71858
71873
|
initAuth(db);
|
|
@@ -71872,10 +71887,10 @@ async function main() {
|
|
|
71872
71887
|
const { eq: eqOp } = await import("drizzle-orm");
|
|
71873
71888
|
app.use("*", async (c, next) => {
|
|
71874
71889
|
const host = (c.req.header("host") || "").split(":")[0];
|
|
71875
|
-
if (!host || host === "gencow.
|
|
71890
|
+
if (!host || host === "gencow.app" || host === "www.gencow.app" || host.startsWith("localhost") || host.startsWith("127.")) {
|
|
71876
71891
|
return next();
|
|
71877
71892
|
}
|
|
71878
|
-
const match2 = host.match(/^([a-z0-9][a-z0-9-]*[a-z0-9]?)\.gencow\.
|
|
71893
|
+
const match2 = host.match(/^([a-z0-9][a-z0-9-]*[a-z0-9]?)\.gencow\.app$/);
|
|
71879
71894
|
if (!match2) return next();
|
|
71880
71895
|
const appName = match2[1];
|
|
71881
71896
|
try {
|
|
@@ -71908,7 +71923,7 @@ async function main() {
|
|
|
71908
71923
|
return c.json({ error: `Proxy error: ${e.message}` }, 502);
|
|
71909
71924
|
}
|
|
71910
71925
|
});
|
|
71911
|
-
console.log("[platform] Subdomain proxy enabled for *.gencow.
|
|
71926
|
+
console.log("[platform] Subdomain proxy enabled for *.gencow.app");
|
|
71912
71927
|
try {
|
|
71913
71928
|
const { provisionApp: restoreApp } = await import(resolve4(functionsPath, "../src/provisioner.ts"));
|
|
71914
71929
|
const runningApps = await db.select({
|
|
@@ -72163,12 +72178,15 @@ async function main() {
|
|
|
72163
72178
|
};
|
|
72164
72179
|
try {
|
|
72165
72180
|
const result = await action.handler(ctx, req);
|
|
72181
|
+
if (result instanceof Response) {
|
|
72182
|
+
return result;
|
|
72183
|
+
}
|
|
72166
72184
|
const status = result.status ?? 200;
|
|
72167
72185
|
const headers = result.headers ?? {};
|
|
72168
72186
|
if (result.body instanceof Response) {
|
|
72169
72187
|
return result.body;
|
|
72170
72188
|
}
|
|
72171
|
-
if (result.body instanceof ArrayBuffer || result.body instanceof Uint8Array) {
|
|
72189
|
+
if (result.body instanceof ArrayBuffer || result.body instanceof Uint8Array || result.body && typeof result.body === "object" && "byteLength" in result.body) {
|
|
72172
72190
|
return new Response(result.body, { status, headers });
|
|
72173
72191
|
}
|
|
72174
72192
|
return c.json(result.body ?? null, status, headers);
|