postgresdk 0.18.27 → 0.18.28

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.
@@ -0,0 +1,14 @@
1
+ /** Parse --force / -y / --yes from CLI args */
2
+ export declare function parseForceFlag(args: string[]): boolean;
3
+ /**
4
+ * For each stale file, prompt the user to confirm deletion (shadcn-style per-file).
5
+ * If `force` is true, all files are deleted without prompting.
6
+ * If stdout is not a TTY (e.g. CI), files are skipped with a warning unless `force` is true.
7
+ *
8
+ * Returns counts of deleted and skipped files.
9
+ */
10
+ export declare function confirmAndDeleteStaleFiles(staleFiles: string[], force: boolean): Promise<{
11
+ deleted: number;
12
+ skipped: number;
13
+ filesDeleted: string[];
14
+ }>;
package/dist/cli.js CHANGED
@@ -528,9 +528,8 @@ async function collectDirsRecursively(root) {
528
528
  }
529
529
  return dirs;
530
530
  }
531
- async function deleteStaleFiles(generatedPaths, dirsToScan) {
532
- let deleted = 0;
533
- const filesDeleted = [];
531
+ async function findStaleFiles(generatedPaths, dirsToScan) {
532
+ const stale = [];
534
533
  for (const dir of dirsToScan) {
535
534
  if (!existsSync(dir))
536
535
  continue;
@@ -542,13 +541,11 @@ async function deleteStaleFiles(generatedPaths, dirsToScan) {
542
541
  continue;
543
542
  const fullPath = join(dir, entry.name);
544
543
  if (!generatedPaths.has(fullPath)) {
545
- await unlink(fullPath);
546
- deleted++;
547
- filesDeleted.push(fullPath);
544
+ stale.push(fullPath);
548
545
  }
549
546
  }
550
547
  }
551
- return { deleted, filesDeleted };
548
+ return stale;
552
549
  }
553
550
  var pascal = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
554
551
  var init_utils = () => {};
@@ -1427,6 +1424,50 @@ var init_emit_sdk_contract = __esm(() => {
1427
1424
  init_emit_include_methods();
1428
1425
  });
1429
1426
 
1427
+ // src/cli-utils.ts
1428
+ import { unlink as unlink2 } from "fs/promises";
1429
+ import prompts from "prompts";
1430
+ function parseForceFlag(args) {
1431
+ return args.includes("--force") || args.includes("-y") || args.includes("--yes");
1432
+ }
1433
+ async function confirmAndDeleteStaleFiles(staleFiles, force) {
1434
+ if (staleFiles.length === 0)
1435
+ return { deleted: 0, skipped: 0, filesDeleted: [] };
1436
+ if (!force && !process.stdout.isTTY) {
1437
+ console.log(`⚠️ ${staleFiles.length} stale file(s) not deleted (non-interactive shell). Re-run with --force to delete.`);
1438
+ return { deleted: 0, skipped: staleFiles.length, filesDeleted: [] };
1439
+ }
1440
+ let deleted = 0;
1441
+ let skipped = 0;
1442
+ const filesDeleted = [];
1443
+ for (const filePath of staleFiles) {
1444
+ let shouldDelete = force;
1445
+ if (!force) {
1446
+ const { confirmed } = await prompts({
1447
+ type: "confirm",
1448
+ name: "confirmed",
1449
+ message: `Delete stale file: ${filePath}?`,
1450
+ initial: false
1451
+ });
1452
+ if (confirmed === undefined) {
1453
+ console.log("Stale file deletion aborted.");
1454
+ break;
1455
+ }
1456
+ shouldDelete = confirmed;
1457
+ }
1458
+ if (shouldDelete) {
1459
+ await unlink2(filePath);
1460
+ console.log(` ✗ ${filePath}`);
1461
+ filesDeleted.push(filePath);
1462
+ deleted++;
1463
+ } else {
1464
+ skipped++;
1465
+ }
1466
+ }
1467
+ return { deleted, skipped, filesDeleted };
1468
+ }
1469
+ var init_cli_utils = () => {};
1470
+
1430
1471
  // src/cli-config-utils.ts
1431
1472
  function extractConfigFields(configContent) {
1432
1473
  const fields = [];
@@ -1848,7 +1889,7 @@ __export(exports_cli_init, {
1848
1889
  });
1849
1890
  import { existsSync as existsSync3, writeFileSync, readFileSync as readFileSync2, copyFileSync } from "fs";
1850
1891
  import { resolve } from "path";
1851
- import prompts from "prompts";
1892
+ import prompts2 from "prompts";
1852
1893
  async function initCommand(args) {
1853
1894
  console.log(`\uD83D\uDE80 Initializing postgresdk configuration...
1854
1895
  `);
@@ -1873,7 +1914,7 @@ async function initCommand(args) {
1873
1914
  }
1874
1915
  });
1875
1916
  console.log();
1876
- const { mergeStrategy } = await prompts({
1917
+ const { mergeStrategy } = await prompts2({
1877
1918
  type: "select",
1878
1919
  name: "mergeStrategy",
1879
1920
  message: "How would you like to proceed?",
@@ -1913,7 +1954,7 @@ async function initCommand(args) {
1913
1954
  \uD83D\uDD04 Let's review your configuration:
1914
1955
  `);
1915
1956
  for (const field of existingFields.filter((f) => !f.isCommented)) {
1916
- const { choice } = await prompts({
1957
+ const { choice } = await prompts2({
1917
1958
  type: "select",
1918
1959
  name: "choice",
1919
1960
  message: `${field.description}:
@@ -1945,7 +1986,7 @@ async function initCommand(args) {
1945
1986
  \uD83D\uDCE6 New configuration options available:
1946
1987
  `);
1947
1988
  for (const option of missingOptions) {
1948
- const { addOption } = await prompts({
1989
+ const { addOption } = await prompts2({
1949
1990
  type: "confirm",
1950
1991
  name: "addOption",
1951
1992
  message: `Add ${option.description} configuration? (commented out by default)`,
@@ -1984,7 +2025,7 @@ async function initCommand(args) {
1984
2025
  } else if (isSdkSide) {
1985
2026
  projectType = "sdk";
1986
2027
  } else {
1987
- const response = await prompts({
2028
+ const response = await prompts2({
1988
2029
  type: "select",
1989
2030
  name: "projectType",
1990
2031
  message: "What type of project is this?",
@@ -2280,6 +2321,7 @@ async function pullCommand(args) {
2280
2321
  console.error("⚠️ Failed to load config file:", err);
2281
2322
  }
2282
2323
  }
2324
+ const force = parseForceFlag(args);
2283
2325
  const cliConfig = {
2284
2326
  from: args.find((a) => a.startsWith("--from="))?.split("=")[1],
2285
2327
  output: args.find((a) => a.startsWith("--output="))?.split("=")[1],
@@ -2362,10 +2404,8 @@ Options:`);
2362
2404
  }
2363
2405
  const generatedPaths = new Set(Object.keys(sdk.files).map((p) => join3(resolvedOutput, p)));
2364
2406
  const dirsToScan = await collectDirsRecursively(resolvedOutput);
2365
- const deleteResult = await deleteStaleFiles(generatedPaths, dirsToScan);
2366
- for (const f of deleteResult.filesDeleted) {
2367
- console.log(` ✗ ${f}`);
2368
- }
2407
+ const staleFiles = await findStaleFiles(generatedPaths, dirsToScan);
2408
+ const deleteResult = await confirmAndDeleteStaleFiles(staleFiles, force);
2369
2409
  const metadataPath = join3(resolvedOutput, ".postgresdk.json");
2370
2410
  const metadata = {
2371
2411
  version: sdk.version,
@@ -2381,7 +2421,7 @@ Options:`);
2381
2421
  if (metadataChanged) {
2382
2422
  await writeFile2(metadataPath, JSON.stringify(metadata, null, 2));
2383
2423
  }
2384
- if (filesWritten === 0 && !metadataChanged && deleteResult.deleted === 0) {
2424
+ if (filesWritten === 0 && !metadataChanged && deleteResult.deleted === 0 && deleteResult.skipped === 0) {
2385
2425
  console.log(`✅ SDK up-to-date (${filesUnchanged} files unchanged)`);
2386
2426
  } else {
2387
2427
  const parts = [];
@@ -2389,6 +2429,8 @@ Options:`);
2389
2429
  parts.push(`updated ${filesWritten} files`);
2390
2430
  if (deleteResult.deleted > 0)
2391
2431
  parts.push(`deleted ${deleteResult.deleted} stale files`);
2432
+ if (deleteResult.skipped > 0)
2433
+ parts.push(`skipped ${deleteResult.skipped} stale files`);
2392
2434
  if (filesUnchanged > 0)
2393
2435
  parts.push(`${filesUnchanged} unchanged`);
2394
2436
  console.log(`✅ SDK pulled successfully to ${config.output}`);
@@ -2401,6 +2443,7 @@ Options:`);
2401
2443
  }
2402
2444
  var init_cli_pull = __esm(() => {
2403
2445
  init_utils();
2446
+ init_cli_utils();
2404
2447
  });
2405
2448
 
2406
2449
  // src/index.ts
@@ -7111,6 +7154,7 @@ function generateTestCases(table, sampleData, updateData, hasForeignKeys = false
7111
7154
  // src/index.ts
7112
7155
  init_emit_sdk_contract();
7113
7156
  init_utils();
7157
+ init_cli_utils();
7114
7158
  var __filename2 = fileURLToPath(import.meta.url);
7115
7159
  var __dirname2 = dirname2(__filename2);
7116
7160
  var { version: CLI_VERSION } = JSON.parse(readFileSync(join2(__dirname2, "../package.json"), "utf-8"));
@@ -7120,7 +7164,7 @@ function resolveSoftDeleteColumn(cfg, tableName) {
7120
7164
  return overrides[tableName] ?? null;
7121
7165
  return cfg.softDeleteColumn ?? null;
7122
7166
  }
7123
- async function generate(configPath) {
7167
+ async function generate(configPath, options) {
7124
7168
  if (!existsSync2(configPath)) {
7125
7169
  throw new Error(`Config file not found: ${configPath}
7126
7170
 
@@ -7315,7 +7359,7 @@ async function generate(configPath) {
7315
7359
  }
7316
7360
  console.log("✍️ Writing files...");
7317
7361
  const writeResult = await writeFilesIfChanged(files);
7318
- let deleteResult = { deleted: 0, filesDeleted: [] };
7362
+ let deleteResult = { deleted: 0, skipped: 0, filesDeleted: [] };
7319
7363
  if (cfg.clean !== false) {
7320
7364
  const dirsToScan = [
7321
7365
  serverDir,
@@ -7331,9 +7375,10 @@ async function generate(configPath) {
7331
7375
  if (generateTests)
7332
7376
  dirsToScan.push(testDir);
7333
7377
  const generatedPaths = new Set(files.map((f) => f.path));
7334
- deleteResult = await deleteStaleFiles(generatedPaths, dirsToScan);
7378
+ const staleFiles = await findStaleFiles(generatedPaths, dirsToScan);
7379
+ deleteResult = await confirmAndDeleteStaleFiles(staleFiles, options?.force ?? false);
7335
7380
  }
7336
- if (writeResult.written === 0 && deleteResult.deleted === 0) {
7381
+ if (writeResult.written === 0 && deleteResult.deleted === 0 && deleteResult.skipped === 0) {
7337
7382
  console.log(`✅ All ${writeResult.unchanged} files up-to-date (no changes)`);
7338
7383
  } else {
7339
7384
  const parts = [];
@@ -7341,6 +7386,8 @@ async function generate(configPath) {
7341
7386
  parts.push(`updated ${writeResult.written} files`);
7342
7387
  if (deleteResult.deleted > 0)
7343
7388
  parts.push(`deleted ${deleteResult.deleted} stale files`);
7389
+ if (deleteResult.skipped > 0)
7390
+ parts.push(`skipped ${deleteResult.skipped} stale files`);
7344
7391
  if (writeResult.unchanged > 0)
7345
7392
  parts.push(`${writeResult.unchanged} unchanged`);
7346
7393
  console.log(`✅ ${parts.join(", ")}`);
@@ -7383,6 +7430,7 @@ import { resolve as resolve3 } from "node:path";
7383
7430
  import { readFileSync as readFileSync3 } from "node:fs";
7384
7431
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7385
7432
  import { dirname as dirname4, join as join4 } from "node:path";
7433
+ init_cli_utils();
7386
7434
  var __filename3 = fileURLToPath2(import.meta.url);
7387
7435
  var __dirname3 = dirname4(__filename3);
7388
7436
  var packageJson = JSON.parse(readFileSync3(join4(__dirname3, "../package.json"), "utf-8"));
@@ -7412,11 +7460,13 @@ Init Options:
7412
7460
 
7413
7461
  Generate Options:
7414
7462
  -c, --config <path> Path to config file (default: postgresdk.config.ts)
7463
+ --force, -y Delete stale files without prompting
7415
7464
 
7416
7465
  Pull Options:
7417
7466
  --from <url> API URL to pull SDK from
7418
7467
  --output <path> Output directory (default: ./src/sdk)
7419
7468
  --token <token> Authentication token
7469
+ --force, -y Delete stale files without prompting
7420
7470
  -c, --config <path> Path to config file with pull settings
7421
7471
 
7422
7472
  Examples:
@@ -7438,8 +7488,9 @@ if (command === "init") {
7438
7488
  if (configIndex !== -1 && args[configIndex + 1]) {
7439
7489
  configPath = args[configIndex + 1];
7440
7490
  }
7491
+ const force = parseForceFlag(args);
7441
7492
  try {
7442
- await generate(resolve3(process.cwd(), configPath));
7493
+ await generate(resolve3(process.cwd(), configPath), { force });
7443
7494
  } catch (err) {
7444
7495
  console.error("❌ Generation failed:", err);
7445
7496
  process.exit(1);
package/dist/index.d.ts CHANGED
@@ -2,4 +2,6 @@ import "dotenv/config";
2
2
  import type { Config } from "./types";
3
3
  /** Resolves the effective soft delete column for a given table, respecting per-table overrides. */
4
4
  export declare function resolveSoftDeleteColumn(cfg: Pick<Config, "softDeleteColumn" | "softDeleteColumnOverrides">, tableName: string): string | null;
5
- export declare function generate(configPath: string): Promise<void>;
5
+ export declare function generate(configPath: string, options?: {
6
+ force?: boolean;
7
+ }): Promise<void>;
package/dist/index.js CHANGED
@@ -527,9 +527,8 @@ async function collectDirsRecursively(root) {
527
527
  }
528
528
  return dirs;
529
529
  }
530
- async function deleteStaleFiles(generatedPaths, dirsToScan) {
531
- let deleted = 0;
532
- const filesDeleted = [];
530
+ async function findStaleFiles(generatedPaths, dirsToScan) {
531
+ const stale = [];
533
532
  for (const dir of dirsToScan) {
534
533
  if (!existsSync(dir))
535
534
  continue;
@@ -541,13 +540,11 @@ async function deleteStaleFiles(generatedPaths, dirsToScan) {
541
540
  continue;
542
541
  const fullPath = join(dir, entry.name);
543
542
  if (!generatedPaths.has(fullPath)) {
544
- await unlink(fullPath);
545
- deleted++;
546
- filesDeleted.push(fullPath);
543
+ stale.push(fullPath);
547
544
  }
548
545
  }
549
546
  }
550
- return { deleted, filesDeleted };
547
+ return stale;
551
548
  }
552
549
  var pascal = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
553
550
  var init_utils = () => {};
@@ -1426,6 +1423,50 @@ var init_emit_sdk_contract = __esm(() => {
1426
1423
  init_emit_include_methods();
1427
1424
  });
1428
1425
 
1426
+ // src/cli-utils.ts
1427
+ import { unlink as unlink2 } from "fs/promises";
1428
+ import prompts from "prompts";
1429
+ function parseForceFlag(args) {
1430
+ return args.includes("--force") || args.includes("-y") || args.includes("--yes");
1431
+ }
1432
+ async function confirmAndDeleteStaleFiles(staleFiles, force) {
1433
+ if (staleFiles.length === 0)
1434
+ return { deleted: 0, skipped: 0, filesDeleted: [] };
1435
+ if (!force && !process.stdout.isTTY) {
1436
+ console.log(`⚠️ ${staleFiles.length} stale file(s) not deleted (non-interactive shell). Re-run with --force to delete.`);
1437
+ return { deleted: 0, skipped: staleFiles.length, filesDeleted: [] };
1438
+ }
1439
+ let deleted = 0;
1440
+ let skipped = 0;
1441
+ const filesDeleted = [];
1442
+ for (const filePath of staleFiles) {
1443
+ let shouldDelete = force;
1444
+ if (!force) {
1445
+ const { confirmed } = await prompts({
1446
+ type: "confirm",
1447
+ name: "confirmed",
1448
+ message: `Delete stale file: ${filePath}?`,
1449
+ initial: false
1450
+ });
1451
+ if (confirmed === undefined) {
1452
+ console.log("Stale file deletion aborted.");
1453
+ break;
1454
+ }
1455
+ shouldDelete = confirmed;
1456
+ }
1457
+ if (shouldDelete) {
1458
+ await unlink2(filePath);
1459
+ console.log(` ✗ ${filePath}`);
1460
+ filesDeleted.push(filePath);
1461
+ deleted++;
1462
+ } else {
1463
+ skipped++;
1464
+ }
1465
+ }
1466
+ return { deleted, skipped, filesDeleted };
1467
+ }
1468
+ var init_cli_utils = () => {};
1469
+
1429
1470
  // src/index.ts
1430
1471
  var import_config = __toESM(require_config(), 1);
1431
1472
  import { join as join2, relative, dirname as dirname2 } from "node:path";
@@ -6134,6 +6175,7 @@ function generateTestCases(table, sampleData, updateData, hasForeignKeys = false
6134
6175
  // src/index.ts
6135
6176
  init_emit_sdk_contract();
6136
6177
  init_utils();
6178
+ init_cli_utils();
6137
6179
  var __filename2 = fileURLToPath(import.meta.url);
6138
6180
  var __dirname2 = dirname2(__filename2);
6139
6181
  var { version: CLI_VERSION } = JSON.parse(readFileSync(join2(__dirname2, "../package.json"), "utf-8"));
@@ -6143,7 +6185,7 @@ function resolveSoftDeleteColumn(cfg, tableName) {
6143
6185
  return overrides[tableName] ?? null;
6144
6186
  return cfg.softDeleteColumn ?? null;
6145
6187
  }
6146
- async function generate(configPath) {
6188
+ async function generate(configPath, options) {
6147
6189
  if (!existsSync2(configPath)) {
6148
6190
  throw new Error(`Config file not found: ${configPath}
6149
6191
 
@@ -6338,7 +6380,7 @@ async function generate(configPath) {
6338
6380
  }
6339
6381
  console.log("✍️ Writing files...");
6340
6382
  const writeResult = await writeFilesIfChanged(files);
6341
- let deleteResult = { deleted: 0, filesDeleted: [] };
6383
+ let deleteResult = { deleted: 0, skipped: 0, filesDeleted: [] };
6342
6384
  if (cfg.clean !== false) {
6343
6385
  const dirsToScan = [
6344
6386
  serverDir,
@@ -6354,9 +6396,10 @@ async function generate(configPath) {
6354
6396
  if (generateTests)
6355
6397
  dirsToScan.push(testDir);
6356
6398
  const generatedPaths = new Set(files.map((f) => f.path));
6357
- deleteResult = await deleteStaleFiles(generatedPaths, dirsToScan);
6399
+ const staleFiles = await findStaleFiles(generatedPaths, dirsToScan);
6400
+ deleteResult = await confirmAndDeleteStaleFiles(staleFiles, options?.force ?? false);
6358
6401
  }
6359
- if (writeResult.written === 0 && deleteResult.deleted === 0) {
6402
+ if (writeResult.written === 0 && deleteResult.deleted === 0 && deleteResult.skipped === 0) {
6360
6403
  console.log(`✅ All ${writeResult.unchanged} files up-to-date (no changes)`);
6361
6404
  } else {
6362
6405
  const parts = [];
@@ -6364,6 +6407,8 @@ async function generate(configPath) {
6364
6407
  parts.push(`updated ${writeResult.written} files`);
6365
6408
  if (deleteResult.deleted > 0)
6366
6409
  parts.push(`deleted ${deleteResult.deleted} stale files`);
6410
+ if (deleteResult.skipped > 0)
6411
+ parts.push(`skipped ${deleteResult.skipped} stale files`);
6367
6412
  if (writeResult.unchanged > 0)
6368
6413
  parts.push(`${writeResult.unchanged} unchanged`);
6369
6414
  console.log(`✅ ${parts.join(", ")}`);
package/dist/utils.d.ts CHANGED
@@ -25,6 +25,11 @@ export declare function ensureDirs(dirs: string[]): Promise<void>;
25
25
  * Returns an empty array if `root` does not exist.
26
26
  */
27
27
  export declare function collectDirsRecursively(root: string): Promise<string[]>;
28
+ /**
29
+ * Find files in the given directories that are not in the set of generated paths,
30
+ * without deleting them. Used to identify stale files before prompting for confirmation.
31
+ */
32
+ export declare function findStaleFiles(generatedPaths: Set<string>, dirsToScan: string[]): Promise<string[]>;
28
33
  /**
29
34
  * Delete files in the given directories that are not in the set of generated paths.
30
35
  * Used to remove stale files for tables that no longer exist in the schema.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postgresdk",
3
- "version": "0.18.27",
3
+ "version": "0.18.28",
4
4
  "description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
5
5
  "type": "module",
6
6
  "bin": {