gencow 0.1.165 → 0.1.166

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.
@@ -7,13 +7,33 @@ import {
7
7
  formatAuthSchemaConflictMessage,
8
8
  isServerCodegenWatchPath,
9
9
  } from "./codegen-command.mjs";
10
+ import { runDrizzleGenerateWithFallback } from "./drizzle-generate.mjs";
10
11
 
11
12
  export function shouldUseLocalDev({ devArgs, processEnv = process.env }) {
12
13
  return processEnv.GENCOW_LOCAL === "1" || devArgs.includes("--local");
13
14
  }
14
15
 
15
- export function buildKillPortsCommand(ports) {
16
- const flags = ports.map((port) => `-ti:${port}`).join(" ");
16
+ function normalizePortList(ports) {
17
+ const seen = new Set();
18
+ const normalized = [];
19
+ for (const port of ports) {
20
+ const value = String(port).trim();
21
+ if (!/^\d+$/.test(value)) continue;
22
+ if (seen.has(value)) continue;
23
+ seen.add(value);
24
+ normalized.push(value);
25
+ }
26
+ return normalized;
27
+ }
28
+
29
+ export function buildKillPortsCommand(ports, platform = process.platform) {
30
+ const normalized = normalizePortList(ports);
31
+ if (normalized.length === 0) return "";
32
+ if (platform === "win32") {
33
+ const list = normalized.join(",");
34
+ return `powershell -NoProfile -ExecutionPolicy Bypass -Command "$ports=@(${list}); Get-NetTCPConnection -LocalPort $ports -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }"`;
35
+ }
36
+ const flags = normalized.map((port) => `-ti:${port}`).join(" ");
17
37
  return `lsof ${flags} 2>/dev/null | xargs kill -9 2>/dev/null || true`;
18
38
  }
19
39
 
@@ -121,7 +141,8 @@ export function createDevLocalCommands({
121
141
  const dashPort = config.dashboardPort || 5100;
122
142
  const samplePort = config.samplePort || 5001;
123
143
  try {
124
- execSyncImpl(buildKillPortsCommand([apiPort, dashPort, samplePort]), { stdio: "ignore" });
144
+ const killCommand = buildKillPortsCommand([apiPort, dashPort, samplePort]);
145
+ if (killCommand) execSyncImpl(killCommand, { stdio: "ignore" });
125
146
  } catch {
126
147
  /* ignore */
127
148
  }
@@ -147,11 +168,13 @@ export function createDevLocalCommands({
147
168
  stdio: "inherit",
148
169
  });
149
170
  } else {
150
- const dk = drizzleKitCmdImpl("generate");
151
- execSyncImpl(dk.cmd, {
171
+ runDrizzleGenerateWithFallback({
152
172
  cwd,
153
- env: { ...genEnv, ...dk.env },
173
+ drizzleKitCmdImpl,
174
+ env: genEnv,
175
+ execSyncImpl,
154
176
  stdio: "inherit",
177
+ warnImpl,
155
178
  });
156
179
  }
157
180
  successImpl("Schema -> migrations synced");
@@ -237,7 +260,8 @@ export function createDevLocalCommands({
237
260
 
238
261
  const killAll = () => {
239
262
  try {
240
- execSyncImpl(buildKillPortsCommand([dashPort, samplePort]), { stdio: "ignore" });
263
+ const killCommand = buildKillPortsCommand([dashPort, samplePort]);
264
+ if (killCommand) execSyncImpl(killCommand, { stdio: "ignore" });
241
265
  } catch {
242
266
  /* ignore */
243
267
  }
@@ -0,0 +1,34 @@
1
+ export function getCommandErrorMessage(error) {
2
+ return (error?.stderr?.toString() || error?.message || "").trim();
3
+ }
4
+
5
+ export function shouldRetryLegacyGenerate(error) {
6
+ const message = getCommandErrorMessage(error);
7
+ return message.includes("unknown command 'generate'") && message.includes("generate:pg");
8
+ }
9
+
10
+ export function runDrizzleGenerateWithFallback({
11
+ cwd,
12
+ drizzleKitCmdImpl,
13
+ env = {},
14
+ execSyncImpl,
15
+ stdio = "inherit",
16
+ warnImpl,
17
+ }) {
18
+ const run = (subcmd) => {
19
+ const dk = drizzleKitCmdImpl(subcmd);
20
+ execSyncImpl(dk.cmd, {
21
+ cwd,
22
+ env: { ...env, ...dk.env },
23
+ stdio,
24
+ });
25
+ };
26
+
27
+ try {
28
+ run("generate");
29
+ } catch (error) {
30
+ if (!shouldRetryLegacyGenerate(error)) throw error;
31
+ warnImpl?.("drizzle-kit uses legacy generate:pg; retrying migration generation...");
32
+ run("generate:pg");
33
+ }
34
+ }
@@ -1,8 +1,8 @@
1
- import { execSync } from "child_process";
2
1
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
3
- import { resolve } from "path";
2
+ import { relative, resolve } from "path";
4
3
  import { BOLD, CYAN, DIM, RESET, YELLOW, error, info, log, success, warn } from "./output.mjs";
5
4
  import { platformFetch, rpcMutation } from "./platform-client.mjs";
5
+ import { createTarGzipArchive } from "./tar-archive.mjs";
6
6
 
7
7
  export function resolveStaticDeployDir({
8
8
  staticDirArg,
@@ -94,7 +94,7 @@ export function findBuiltApiReferenceFiles({
94
94
  const content = readFileSyncImpl(file, "utf8");
95
95
  return content.includes("/api/query") || content.includes("/api/mutation");
96
96
  })
97
- .map((file) => file.replace(`${targetDir}/`, ""))
97
+ .map((file) => relative(targetDir, file).replace(/\\/g, "/"))
98
98
  .sort();
99
99
  }
100
100
 
@@ -134,7 +134,6 @@ export function createStaticDeployRuntime({
134
134
  createInterfaceImpl,
135
135
  cwdImpl = () => process.cwd(),
136
136
  errorImpl = error,
137
- execSyncImpl = execSync,
138
137
  existsSyncImpl = existsSync,
139
138
  exitImpl = (code) => process.exit(code),
140
139
  infoImpl = info,
@@ -147,6 +146,7 @@ export function createStaticDeployRuntime({
147
146
  setTimeoutImpl = setTimeout,
148
147
  statSyncImpl = statSync,
149
148
  successImpl = success,
149
+ tarCreateImpl,
150
150
  unlinkSyncImpl = unlinkSync,
151
151
  warnImpl = warn,
152
152
  writeFileSyncImpl = writeFileSync,
@@ -223,8 +223,11 @@ export function createStaticDeployRuntime({
223
223
  mkdirSyncImpl(resolvePathImpl(tmpBundle, ".."), { recursive: true });
224
224
 
225
225
  try {
226
- execSyncImpl(`COPYFILE_DISABLE=1 tar -czf "${tmpBundle}" -C "${resolvePathImpl(cwd, targetDir)}" .`, {
227
- cwd,
226
+ await createTarGzipArchive({
227
+ cwd: resolvePathImpl(cwd, targetDir),
228
+ file: tmpBundle,
229
+ entries: ["."],
230
+ tarCreateImpl,
228
231
  });
229
232
  } catch (error) {
230
233
  errorImpl(`Packaging failed: ${error.message}`);
@@ -0,0 +1,61 @@
1
+ function normalizeTarPath(value) {
2
+ return String(value || "")
3
+ .replace(/\\/g, "/")
4
+ .replace(/^\.\//, "")
5
+ .replace(/\/+$/, "");
6
+ }
7
+
8
+ function splitTarPath(value) {
9
+ return normalizeTarPath(value).split("/").filter(Boolean);
10
+ }
11
+
12
+ function segmentMatchesPattern(segment, pattern) {
13
+ if (pattern.endsWith(".*")) {
14
+ return segment.startsWith(pattern.slice(0, -1));
15
+ }
16
+ return segment === pattern;
17
+ }
18
+
19
+ function matchesTarExclude(entryPath, pattern) {
20
+ const normalizedPattern = normalizeTarPath(pattern);
21
+ if (!normalizedPattern) return false;
22
+ const entrySegments = splitTarPath(entryPath);
23
+ const patternSegments = splitTarPath(normalizedPattern);
24
+ if (entrySegments.length === 0 || patternSegments.length === 0) return false;
25
+
26
+ if (patternSegments.length === 1) {
27
+ return entrySegments.some((segment) => segmentMatchesPattern(segment, patternSegments[0]));
28
+ }
29
+
30
+ for (let index = 0; index <= entrySegments.length - patternSegments.length; index += 1) {
31
+ const matches = patternSegments.every((segment, offset) =>
32
+ segmentMatchesPattern(entrySegments[index + offset], segment),
33
+ );
34
+ if (matches) return true;
35
+ }
36
+ return false;
37
+ }
38
+
39
+ export function shouldIncludeTarEntry(entryPath, excludes = []) {
40
+ return !excludes.some((pattern) => matchesTarExclude(entryPath, pattern));
41
+ }
42
+
43
+ export async function createTarGzipArchive({
44
+ cwd,
45
+ file,
46
+ entries = ["."],
47
+ excludes = [],
48
+ tarCreateImpl,
49
+ }) {
50
+ const createImpl = tarCreateImpl ?? (await import("tar")).create;
51
+ const options = {
52
+ cwd,
53
+ file,
54
+ gzip: true,
55
+ portable: true,
56
+ };
57
+ if (excludes.length > 0) {
58
+ options.filter = (entryPath) => shouldIncludeTarEntry(entryPath, excludes);
59
+ }
60
+ await createImpl(options, entries);
61
+ }
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
3
3
  import { basename, resolve } from "path";
4
4
  import { BOLD, CYAN, DIM, GREEN, RESET, error, info, log, success } from "./output.mjs";
5
5
  import { platformFetch, requireCreds } from "./platform-client.mjs";
6
+ import { createTarGzipArchive } from "./tar-archive.mjs";
6
7
  import {
7
8
  buildTemplateTarExcludes,
8
9
  detectStaticTemplateProject,
@@ -39,29 +40,42 @@ function centsFromPrice(value) {
39
40
  return Math.round(numeric * 100);
40
41
  }
41
42
 
42
- function shellQuote(value) {
43
- return `'${String(value).replace(/'/g, "'\\''")}'`;
44
- }
45
-
46
- function createSourceBundle({ cwd, staticOutputDir, execSyncImpl = execSync, mkdirSyncImpl = mkdirSync }) {
43
+ async function createSourceBundle({ cwd, staticOutputDir, mkdirSyncImpl = mkdirSync, tarCreateImpl }) {
47
44
  const out = resolve(cwd, ".gencow", "template-source.tar.gz");
48
45
  mkdirSyncImpl(resolve(cwd, ".gencow"), { recursive: true });
49
- const excludes = buildTemplateTarExcludes(staticOutputDir)
50
- .map((item) => `--exclude=${shellQuote(item)}`)
51
- .join(" ");
52
- execSyncImpl(`COPYFILE_DISABLE=1 tar ${excludes} -czf ${shellQuote(out)} .`, { cwd });
46
+ await createTarGzipArchive({
47
+ cwd,
48
+ file: out,
49
+ entries: ["."],
50
+ excludes: buildTemplateTarExcludes(staticOutputDir),
51
+ tarCreateImpl,
52
+ });
53
53
  return out;
54
54
  }
55
55
 
56
- function createStaticBundle({ cwd, outputDir, execSyncImpl = execSync, mkdirSyncImpl = mkdirSync }) {
56
+ async function createStaticBundle({ cwd, outputDir, mkdirSyncImpl = mkdirSync, resolvePathImpl = resolve, tarCreateImpl }) {
57
57
  const out = resolve(cwd, ".gencow", "template-static.tar.gz");
58
58
  mkdirSyncImpl(resolve(cwd, ".gencow"), { recursive: true });
59
- execSyncImpl(`COPYFILE_DISABLE=1 tar -czf ${shellQuote(out)} -C ${shellQuote(resolve(cwd, outputDir))} .`, {
60
- cwd,
59
+ await createTarGzipArchive({
60
+ cwd: resolvePathImpl(cwd, outputDir),
61
+ file: out,
62
+ entries: ["."],
63
+ tarCreateImpl,
61
64
  });
62
65
  return out;
63
66
  }
64
67
 
68
+ async function extractTemplateArchive({
69
+ archive,
70
+ targetDir,
71
+ mkdirSyncImpl = mkdirSync,
72
+ tarExtractImpl,
73
+ }) {
74
+ mkdirSyncImpl(targetDir, { recursive: true });
75
+ const extractImpl = tarExtractImpl ?? (await import("tar")).extract;
76
+ await extractImpl({ file: archive, cwd: targetDir });
77
+ }
78
+
65
79
  async function rpc(creds, name, args, platformFetchImpl) {
66
80
  const res = await platformFetchImpl(creds, "/api/query", {
67
81
  method: "POST",
@@ -81,12 +95,15 @@ export function createTemplateMarketplaceCommand({
81
95
  exitImpl = (code) => process.exit(code),
82
96
  infoImpl = info,
83
97
  logImpl = log,
98
+ mkdirSyncImpl = mkdirSync,
84
99
  platformFetchImpl = platformFetch,
85
100
  readFileSyncImpl = readFileSync,
86
101
  requireCredsImpl = requireCreds,
87
102
  resolvePathImpl = resolve,
88
103
  rmSyncImpl = rmSync,
89
104
  successImpl = success,
105
+ tarCreateImpl,
106
+ tarExtractImpl,
90
107
  writeFileSyncImpl = writeFileSync,
91
108
  } = {}) {
92
109
  async function publish(options) {
@@ -124,15 +141,18 @@ export function createTemplateMarketplaceCommand({
124
141
  });
125
142
  if (!outputValidation.ok) throw new Error(outputValidation.error);
126
143
 
127
- const sourceBundle = createSourceBundle({
144
+ const sourceBundle = await createSourceBundle({
128
145
  cwd,
129
146
  staticOutputDir: detection.staticOutputDir,
130
- execSyncImpl,
147
+ mkdirSyncImpl,
148
+ tarCreateImpl,
131
149
  });
132
- const staticBundle = createStaticBundle({
150
+ const staticBundle = await createStaticBundle({
133
151
  cwd: resolvePathImpl(cwd, detection.buildWorkdir),
134
152
  outputDir: detection.staticOutputDir,
135
- execSyncImpl,
153
+ mkdirSyncImpl,
154
+ resolvePathImpl,
155
+ tarCreateImpl,
136
156
  });
137
157
 
138
158
  const creds = requireCredsImpl();
@@ -215,8 +235,11 @@ export function createTemplateMarketplaceCommand({
215
235
  const slug = options._[0];
216
236
  const dir = options._[1] || slug;
217
237
  const archive = await download(slug, { ...options, outFile: ".gencow-template-clone.tar.gz" }, true);
218
- execSyncImpl(`mkdir -p ${shellQuote(dir)} && tar -xzf ${shellQuote(archive)} -C ${shellQuote(dir)}`, {
219
- cwd: cwdImpl(),
238
+ await extractTemplateArchive({
239
+ archive,
240
+ targetDir: resolvePathImpl(cwdImpl(), dir),
241
+ mkdirSyncImpl,
242
+ tarExtractImpl,
220
243
  });
221
244
  rmSyncImpl(archive, { force: true });
222
245
  successImpl(`Cloned into: ${dir}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.165",
3
+ "version": "0.1.166",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
package/server/index.js CHANGED
@@ -117234,6 +117234,7 @@ function createHttpActionRequest(c) {
117234
117234
  params: c.req.param(),
117235
117235
  query: c.req.query(),
117236
117236
  headers: Object.fromEntries(c.req.raw.headers.entries()),
117237
+ raw: c.req.raw,
117237
117238
  json: () => c.req.json(),
117238
117239
  formData: () => c.req.formData(),
117239
117240
  arrayBuffer: () => c.req.arrayBuffer(),