gencow 0.1.114 → 0.1.115
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 +15 -25
- package/core/index.js +52 -24
- package/dashboard/assets/{index-C26b7MIs.js → index-DDiSe7od.js} +67 -67
- package/dashboard/index.html +1 -1
- package/package.json +1 -1
- package/server/index.js +12918 -42496
- package/server/index.js.map +4 -4
- package/templates/ai-chat/chat.ts +0 -1
- package/templates/fullstack/files.ts +0 -1
- package/templates/fullstack/tasks.ts +0 -3
- package/templates/task-app/files.ts +0 -1
- package/templates/task-app/tasks.ts +0 -3
package/bin/gencow.mjs
CHANGED
|
@@ -2451,13 +2451,9 @@ ${BOLD}Examples:${RESET}
|
|
|
2451
2451
|
};
|
|
2452
2452
|
const tsFiles = scanTsFiles(gencowDir);
|
|
2453
2453
|
// query(, mutation(, httpAction( 호출이 하나라도 있으면 실질적 백엔드
|
|
2454
|
-
// ⚠️ 주석 내 코드 예시를 오탐하지 않도록 주석을 먼저 제거
|
|
2455
2454
|
const hasApiCalls = tsFiles.some(f => {
|
|
2456
2455
|
const src = readFileSync(f, "utf8");
|
|
2457
|
-
|
|
2458
|
-
.replace(/\/\/.*$/gm, "") // 한줄 주석 제거
|
|
2459
|
-
.replace(/\/\*[\s\S]*?\*\//g, ""); // 블록 주석 제거
|
|
2460
|
-
return /\b(query|mutation|httpAction)\s*\(/.test(stripped);
|
|
2456
|
+
return /\b(query|mutation|httpAction)\s*\(/.test(src);
|
|
2461
2457
|
});
|
|
2462
2458
|
if (!hasApiCalls) {
|
|
2463
2459
|
isBackendEmpty = true;
|
|
@@ -2703,29 +2699,23 @@ ${BOLD}Examples:${RESET}
|
|
|
2703
2699
|
warn("서버 시작 실패 원인:");
|
|
2704
2700
|
for (const line of errData.crashLogs) log(` ${DIM}${line}${RESET}`);
|
|
2705
2701
|
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
log("");
|
|
2710
|
-
} else {
|
|
2711
|
-
error("백엔드 배포 실패로 프론트엔드 배포를 건너뜁니다.");
|
|
2712
|
-
process.exit(1);
|
|
2713
|
-
}
|
|
2714
|
-
} else {
|
|
2715
|
-
const backendData = await backendDeployRes.json();
|
|
2716
|
-
const backendElapsed = ((Date.now() - backendStartTime) / 1000).toFixed(1);
|
|
2717
|
-
success(`백엔드 빌드 완료! (${backendElapsed}s)`);
|
|
2702
|
+
error("백엔드 배포 실패로 프론트엔드 배포를 건너뜁니다.");
|
|
2703
|
+
process.exit(1);
|
|
2704
|
+
}
|
|
2718
2705
|
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
}
|
|
2706
|
+
const backendData = await backendDeployRes.json();
|
|
2707
|
+
const backendElapsed = ((Date.now() - backendStartTime) / 1000).toFixed(1);
|
|
2708
|
+
success(`백엔드 빌드 완료! (${backendElapsed}s)`);
|
|
2723
2709
|
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
log("");
|
|
2710
|
+
// Health check — 백엔드 앱 URL로 실제 응답 확인
|
|
2711
|
+
if (backendData.url) {
|
|
2712
|
+
await this._verifyAppReady(backendData.url, appId);
|
|
2728
2713
|
}
|
|
2714
|
+
|
|
2715
|
+
info(`URL: ${backendData.url}`);
|
|
2716
|
+
info(`Hash: ${backendData.bundleHash}`);
|
|
2717
|
+
updateEnvLocalUrl(backendData.url);
|
|
2718
|
+
log("");
|
|
2729
2719
|
log(` ${BOLD}── 프론트엔드 배포 ──────────────────${RESET}\n`);
|
|
2730
2720
|
}
|
|
2731
2721
|
|
package/core/index.js
CHANGED
|
@@ -1402,7 +1402,6 @@ function query(key, handlerOrDef) {
|
|
|
1402
1402
|
}
|
|
1403
1403
|
var mutationCounter = 0;
|
|
1404
1404
|
function mutation(nameOrInvalidatesOrDef, handlerOrDef, name) {
|
|
1405
|
-
let invalidates;
|
|
1406
1405
|
let argsSchema;
|
|
1407
1406
|
let actualHandler;
|
|
1408
1407
|
let mutName;
|
|
@@ -1410,16 +1409,13 @@ function mutation(nameOrInvalidatesOrDef, handlerOrDef, name) {
|
|
|
1410
1409
|
if (typeof nameOrInvalidatesOrDef === "string") {
|
|
1411
1410
|
mutName = nameOrInvalidatesOrDef;
|
|
1412
1411
|
const def2 = handlerOrDef;
|
|
1413
|
-
invalidates = def2.invalidates || [];
|
|
1414
1412
|
actualHandler = def2.handler;
|
|
1415
1413
|
argsSchema = def2.args;
|
|
1416
1414
|
isPublic = def2.public === true;
|
|
1417
1415
|
} else if (Array.isArray(nameOrInvalidatesOrDef)) {
|
|
1418
|
-
invalidates = nameOrInvalidatesOrDef;
|
|
1419
1416
|
actualHandler = handlerOrDef;
|
|
1420
1417
|
mutName = name || `mutation_${++mutationCounter}`;
|
|
1421
1418
|
} else {
|
|
1422
|
-
invalidates = nameOrInvalidatesOrDef.invalidates;
|
|
1423
1419
|
actualHandler = nameOrInvalidatesOrDef.handler;
|
|
1424
1420
|
argsSchema = nameOrInvalidatesOrDef.args;
|
|
1425
1421
|
isPublic = nameOrInvalidatesOrDef.public === true;
|
|
@@ -1432,7 +1428,6 @@ function mutation(nameOrInvalidatesOrDef, handlerOrDef, name) {
|
|
|
1432
1428
|
}
|
|
1433
1429
|
const def = {
|
|
1434
1430
|
name: mutName,
|
|
1435
|
-
invalidates,
|
|
1436
1431
|
handler: actualHandler,
|
|
1437
1432
|
argsSchema,
|
|
1438
1433
|
isPublic
|
|
@@ -1477,8 +1472,11 @@ function deregisterClient(ws) {
|
|
|
1477
1472
|
}
|
|
1478
1473
|
function buildRealtimeCtx(options) {
|
|
1479
1474
|
const pendingEmits = /* @__PURE__ */ new Map();
|
|
1475
|
+
const _pendingRefresh = [];
|
|
1476
|
+
let _hasEmitted = false;
|
|
1480
1477
|
return {
|
|
1481
1478
|
emit(queryKey, data) {
|
|
1479
|
+
_hasEmitted = true;
|
|
1482
1480
|
const existing = pendingEmits.get(queryKey);
|
|
1483
1481
|
if (existing) clearTimeout(existing.timer);
|
|
1484
1482
|
const timer = setTimeout(() => {
|
|
@@ -1503,24 +1501,58 @@ function buildRealtimeCtx(options) {
|
|
|
1503
1501
|
}
|
|
1504
1502
|
}, 50);
|
|
1505
1503
|
pendingEmits.set(queryKey, { data, timer });
|
|
1504
|
+
},
|
|
1505
|
+
refresh(queryKey) {
|
|
1506
|
+
_hasEmitted = true;
|
|
1507
|
+
if (!_pendingRefresh.includes(queryKey)) {
|
|
1508
|
+
_pendingRefresh.push(queryKey);
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
get _hasEmitted() {
|
|
1512
|
+
return _hasEmitted;
|
|
1513
|
+
},
|
|
1514
|
+
get _pendingRefresh() {
|
|
1515
|
+
return [..._pendingRefresh];
|
|
1516
|
+
},
|
|
1517
|
+
async _flushRefresh() {
|
|
1518
|
+
if (_pendingRefresh.length === 0) return;
|
|
1519
|
+
const qMap = options?.queryMap ?? queryRegistry;
|
|
1520
|
+
for (const key of _pendingRefresh) {
|
|
1521
|
+
const queryDef = qMap.get(key);
|
|
1522
|
+
if (!queryDef) {
|
|
1523
|
+
console.warn(`[gencow] refresh("${key}"): query not found in registry. Skipping.`);
|
|
1524
|
+
continue;
|
|
1525
|
+
}
|
|
1526
|
+
try {
|
|
1527
|
+
const refreshCtx = options?.buildCtxForRefresh?.() ?? {};
|
|
1528
|
+
const result = await queryDef.handler(refreshCtx, {});
|
|
1529
|
+
if (options?.httpCallback) {
|
|
1530
|
+
options.httpCallback({ type: "emit", queryKey: key, data: result });
|
|
1531
|
+
} else {
|
|
1532
|
+
const clients = subscribers.get(key);
|
|
1533
|
+
if (clients && clients.size > 0) {
|
|
1534
|
+
const message = JSON.stringify({
|
|
1535
|
+
type: "query:updated",
|
|
1536
|
+
query: key,
|
|
1537
|
+
data: result
|
|
1538
|
+
});
|
|
1539
|
+
for (const ws of clients) {
|
|
1540
|
+
try {
|
|
1541
|
+
ws.send(message);
|
|
1542
|
+
} catch {
|
|
1543
|
+
clients.delete(ws);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
} catch (e) {
|
|
1549
|
+
console.warn(`[gencow] refresh("${key}") failed:`, e instanceof Error ? e.message : e);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
_pendingRefresh.length = 0;
|
|
1506
1553
|
}
|
|
1507
1554
|
};
|
|
1508
1555
|
}
|
|
1509
|
-
async function invalidateQueries(queryKeys, ctx, httpInvalidateCallback) {
|
|
1510
|
-
if (queryKeys.length === 0) return;
|
|
1511
|
-
if (httpInvalidateCallback) {
|
|
1512
|
-
httpInvalidateCallback(queryKeys);
|
|
1513
|
-
return;
|
|
1514
|
-
}
|
|
1515
|
-
const invalidateMsg = JSON.stringify({ type: "invalidate", queries: queryKeys });
|
|
1516
|
-
for (const ws of connectedClients) {
|
|
1517
|
-
try {
|
|
1518
|
-
ws.send(invalidateMsg);
|
|
1519
|
-
} catch {
|
|
1520
|
-
connectedClients.delete(ws);
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
1556
|
function handleWsMessage(ws, raw) {
|
|
1525
1557
|
try {
|
|
1526
1558
|
const msg = typeof raw === "string" ? JSON.parse(raw) : JSON.parse(raw.toString());
|
|
@@ -2075,7 +2107,6 @@ function crud(table, options) {
|
|
|
2075
2107
|
});
|
|
2076
2108
|
const createDef = !enabledMethods.has("create") ? void 0 : mutation(`${prefix}.create`, {
|
|
2077
2109
|
public: isPublic,
|
|
2078
|
-
invalidates: [],
|
|
2079
2110
|
handler: async (ctx, args) => {
|
|
2080
2111
|
const user = isPublic ? null : ctx.auth.requireAuth();
|
|
2081
2112
|
let insertData = { ...args };
|
|
@@ -2095,7 +2126,6 @@ function crud(table, options) {
|
|
|
2095
2126
|
});
|
|
2096
2127
|
const updateDef = !enabledMethods.has("update") ? void 0 : mutation(`${prefix}.update`, {
|
|
2097
2128
|
public: isPublic,
|
|
2098
|
-
invalidates: [],
|
|
2099
2129
|
handler: async (ctx, args) => {
|
|
2100
2130
|
if (!isPublic) ctx.auth.requireAuth();
|
|
2101
2131
|
const { id, ...updates } = args;
|
|
@@ -2121,7 +2151,6 @@ function crud(table, options) {
|
|
|
2121
2151
|
});
|
|
2122
2152
|
const removeDef = !enabledMethods.has("remove") ? void 0 : mutation(`${prefix}.remove`, {
|
|
2123
2153
|
public: isPublic,
|
|
2124
|
-
invalidates: [],
|
|
2125
2154
|
handler: async (ctx, args) => {
|
|
2126
2155
|
if (!isPublic) ctx.auth.requireAuth();
|
|
2127
2156
|
if (options?.softDelete) {
|
|
@@ -2164,7 +2193,6 @@ export {
|
|
|
2164
2193
|
getSchedulerInfo,
|
|
2165
2194
|
handleWsMessage,
|
|
2166
2195
|
httpAction,
|
|
2167
|
-
invalidateQueries,
|
|
2168
2196
|
mutation,
|
|
2169
2197
|
ownerRls,
|
|
2170
2198
|
parseArgs,
|