postgresdk 0.18.17 → 0.18.18
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/dist/cli.js +100 -50
- package/dist/index.js +95 -45
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +8 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -489,8 +489,8 @@ var require_config = __commonJS(() => {
|
|
|
489
489
|
});
|
|
490
490
|
|
|
491
491
|
// src/utils.ts
|
|
492
|
-
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
493
|
-
import { dirname } from "path";
|
|
492
|
+
import { mkdir, writeFile, readFile, readdir, unlink } from "fs/promises";
|
|
493
|
+
import { dirname, join } from "path";
|
|
494
494
|
import { existsSync } from "fs";
|
|
495
495
|
async function writeFilesIfChanged(files) {
|
|
496
496
|
let written = 0;
|
|
@@ -515,6 +515,28 @@ async function ensureDirs(dirs) {
|
|
|
515
515
|
for (const d of dirs)
|
|
516
516
|
await mkdir(d, { recursive: true });
|
|
517
517
|
}
|
|
518
|
+
async function deleteStaleFiles(generatedPaths, dirsToScan) {
|
|
519
|
+
let deleted = 0;
|
|
520
|
+
const filesDeleted = [];
|
|
521
|
+
for (const dir of dirsToScan) {
|
|
522
|
+
if (!existsSync(dir))
|
|
523
|
+
continue;
|
|
524
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
525
|
+
for (const entry of entries) {
|
|
526
|
+
if (!entry.isFile())
|
|
527
|
+
continue;
|
|
528
|
+
if (!/\.(ts|md|yml|sh)$/.test(entry.name))
|
|
529
|
+
continue;
|
|
530
|
+
const fullPath = join(dir, entry.name);
|
|
531
|
+
if (!generatedPaths.has(fullPath)) {
|
|
532
|
+
await unlink(fullPath);
|
|
533
|
+
deleted++;
|
|
534
|
+
filesDeleted.push(fullPath);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return { deleted, filesDeleted };
|
|
539
|
+
}
|
|
518
540
|
var pascal = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
|
|
519
541
|
var init_utils = () => {};
|
|
520
542
|
|
|
@@ -2559,7 +2581,7 @@ __export(exports_cli_pull, {
|
|
|
2559
2581
|
pullCommand: () => pullCommand
|
|
2560
2582
|
});
|
|
2561
2583
|
import { writeFile as writeFile2, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
2562
|
-
import { join as
|
|
2584
|
+
import { join as join3, dirname as dirname3, resolve as resolve2 } from "path";
|
|
2563
2585
|
import { existsSync as existsSync4 } from "fs";
|
|
2564
2586
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2565
2587
|
async function pullCommand(args) {
|
|
@@ -2645,7 +2667,7 @@ Options:`);
|
|
|
2645
2667
|
let filesUnchanged = 0;
|
|
2646
2668
|
const changedFiles = [];
|
|
2647
2669
|
for (const [path, content] of Object.entries(sdk.files)) {
|
|
2648
|
-
const fullPath =
|
|
2670
|
+
const fullPath = join3(config.output, path);
|
|
2649
2671
|
await mkdir2(dirname3(fullPath), { recursive: true });
|
|
2650
2672
|
let shouldWrite = true;
|
|
2651
2673
|
if (existsSync4(fullPath)) {
|
|
@@ -2662,7 +2684,7 @@ Options:`);
|
|
|
2662
2684
|
console.log(` ✓ ${path}`);
|
|
2663
2685
|
}
|
|
2664
2686
|
}
|
|
2665
|
-
const metadataPath =
|
|
2687
|
+
const metadataPath = join3(config.output, ".postgresdk.json");
|
|
2666
2688
|
const metadata = {
|
|
2667
2689
|
version: sdk.version,
|
|
2668
2690
|
pulledFrom: config.from
|
|
@@ -2692,7 +2714,7 @@ var init_cli_pull = () => {};
|
|
|
2692
2714
|
|
|
2693
2715
|
// src/index.ts
|
|
2694
2716
|
var import_config = __toESM(require_config(), 1);
|
|
2695
|
-
import { join, relative, dirname as dirname2 } from "node:path";
|
|
2717
|
+
import { join as join2, relative, dirname as dirname2 } from "node:path";
|
|
2696
2718
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
2697
2719
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
2698
2720
|
|
|
@@ -3607,6 +3629,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
3607
3629
|
where?: Where<Select${Type}>;
|
|
3608
3630
|
orderBy?: string | string[];
|
|
3609
3631
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
3632
|
+
distinctOn?: string | string[];
|
|
3610
3633
|
${paramName}?: {
|
|
3611
3634
|
select?: string[];
|
|
3612
3635
|
exclude?: string[];
|
|
@@ -3639,6 +3662,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
3639
3662
|
where?: Where<Select${Type}>;
|
|
3640
3663
|
orderBy?: string | string[];
|
|
3641
3664
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
3665
|
+
distinctOn?: string | string[];
|
|
3642
3666
|
${includeParams};
|
|
3643
3667
|
}`;
|
|
3644
3668
|
} else if (pattern.type === "nested" && pattern.nestedKey) {
|
|
@@ -3654,6 +3678,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
3654
3678
|
where?: Where<Select${Type}>;
|
|
3655
3679
|
orderBy?: string | string[];
|
|
3656
3680
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
3681
|
+
distinctOn?: string | string[];
|
|
3657
3682
|
${paramName}?: {
|
|
3658
3683
|
select?: string[];
|
|
3659
3684
|
exclude?: string[];
|
|
@@ -7247,7 +7272,7 @@ init_emit_sdk_contract();
|
|
|
7247
7272
|
init_utils();
|
|
7248
7273
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
7249
7274
|
var __dirname2 = dirname2(__filename2);
|
|
7250
|
-
var { version: CLI_VERSION } = JSON.parse(readFileSync(
|
|
7275
|
+
var { version: CLI_VERSION } = JSON.parse(readFileSync(join2(__dirname2, "../package.json"), "utf-8"));
|
|
7251
7276
|
async function generate(configPath) {
|
|
7252
7277
|
if (!existsSync2(configPath)) {
|
|
7253
7278
|
throw new Error(`Config file not found: ${configPath}
|
|
@@ -7280,26 +7305,26 @@ async function generate(configPath) {
|
|
|
7280
7305
|
const sameDirectory = serverDir === originalClientDir;
|
|
7281
7306
|
let clientDir = originalClientDir;
|
|
7282
7307
|
if (sameDirectory) {
|
|
7283
|
-
clientDir =
|
|
7308
|
+
clientDir = join2(originalClientDir, "sdk");
|
|
7284
7309
|
}
|
|
7285
7310
|
const serverFramework = cfg.serverFramework || "hono";
|
|
7286
7311
|
const generateTests = cfg.tests?.generate ?? false;
|
|
7287
7312
|
const originalTestDir = cfg.tests?.output || "./api/tests";
|
|
7288
7313
|
let testDir = originalTestDir;
|
|
7289
7314
|
if (generateTests && (originalTestDir === serverDir || originalTestDir === originalClientDir)) {
|
|
7290
|
-
testDir =
|
|
7315
|
+
testDir = join2(originalTestDir, "tests");
|
|
7291
7316
|
}
|
|
7292
7317
|
const testFramework = cfg.tests?.framework || "vitest";
|
|
7293
7318
|
console.log("\uD83D\uDCC1 Creating directories...");
|
|
7294
7319
|
const dirs = [
|
|
7295
7320
|
serverDir,
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7321
|
+
join2(serverDir, "types"),
|
|
7322
|
+
join2(serverDir, "zod"),
|
|
7323
|
+
join2(serverDir, "routes"),
|
|
7299
7324
|
clientDir,
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7325
|
+
join2(clientDir, "types"),
|
|
7326
|
+
join2(clientDir, "zod"),
|
|
7327
|
+
join2(clientDir, "params")
|
|
7303
7328
|
];
|
|
7304
7329
|
if (generateTests) {
|
|
7305
7330
|
dirs.push(testDir);
|
|
@@ -7307,28 +7332,28 @@ async function generate(configPath) {
|
|
|
7307
7332
|
await ensureDirs(dirs);
|
|
7308
7333
|
const files = [];
|
|
7309
7334
|
const includeSpec = emitIncludeSpec(graph);
|
|
7310
|
-
files.push({ path:
|
|
7311
|
-
files.push({ path:
|
|
7335
|
+
files.push({ path: join2(serverDir, "include-spec.ts"), content: includeSpec });
|
|
7336
|
+
files.push({ path: join2(clientDir, "include-spec.ts"), content: includeSpec });
|
|
7312
7337
|
const includeResolver = emitIncludeResolver(graph, cfg.useJsExtensions);
|
|
7313
|
-
files.push({ path:
|
|
7314
|
-
files.push({ path:
|
|
7315
|
-
files.push({ path:
|
|
7316
|
-
files.push({ path:
|
|
7317
|
-
files.push({ path:
|
|
7338
|
+
files.push({ path: join2(clientDir, "include-resolver.ts"), content: includeResolver });
|
|
7339
|
+
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod() });
|
|
7340
|
+
files.push({ path: join2(clientDir, "types", "shared.ts"), content: emitSharedTypes() });
|
|
7341
|
+
files.push({ path: join2(clientDir, "base-client.ts"), content: emitBaseClient() });
|
|
7342
|
+
files.push({ path: join2(clientDir, "where-types.ts"), content: emitWhereTypes() });
|
|
7318
7343
|
files.push({
|
|
7319
|
-
path:
|
|
7344
|
+
path: join2(serverDir, "include-builder.ts"),
|
|
7320
7345
|
content: emitIncludeBuilder(graph, cfg.includeMethodsDepth || 2)
|
|
7321
7346
|
});
|
|
7322
7347
|
files.push({
|
|
7323
|
-
path:
|
|
7348
|
+
path: join2(serverDir, "include-loader.ts"),
|
|
7324
7349
|
content: emitIncludeLoader(graph, model, cfg.includeMethodsDepth || 2, cfg.useJsExtensions)
|
|
7325
7350
|
});
|
|
7326
|
-
files.push({ path:
|
|
7351
|
+
files.push({ path: join2(serverDir, "logger.ts"), content: emitLogger() });
|
|
7327
7352
|
if (getAuthStrategy(normalizedAuth) !== "none") {
|
|
7328
|
-
files.push({ path:
|
|
7353
|
+
files.push({ path: join2(serverDir, "auth.ts"), content: emitAuth(normalizedAuth) });
|
|
7329
7354
|
}
|
|
7330
7355
|
files.push({
|
|
7331
|
-
path:
|
|
7356
|
+
path: join2(serverDir, "core", "operations.ts"),
|
|
7332
7357
|
content: emitCoreOperations()
|
|
7333
7358
|
});
|
|
7334
7359
|
if (process.env.SDK_DEBUG) {
|
|
@@ -7337,13 +7362,13 @@ async function generate(configPath) {
|
|
|
7337
7362
|
for (const table of Object.values(model.tables)) {
|
|
7338
7363
|
const numericMode = cfg.numericMode ?? "auto";
|
|
7339
7364
|
const typesSrc = emitTypes(table, { numericMode }, model.enums);
|
|
7340
|
-
files.push({ path:
|
|
7341
|
-
files.push({ path:
|
|
7365
|
+
files.push({ path: join2(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
7366
|
+
files.push({ path: join2(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
7342
7367
|
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
7343
|
-
files.push({ path:
|
|
7344
|
-
files.push({ path:
|
|
7368
|
+
files.push({ path: join2(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
7369
|
+
files.push({ path: join2(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
7345
7370
|
const paramsZodSrc = emitParamsZod(table, graph);
|
|
7346
|
-
files.push({ path:
|
|
7371
|
+
files.push({ path: join2(clientDir, "params", `${table.name}.ts`), content: paramsZodSrc });
|
|
7347
7372
|
let routeContent;
|
|
7348
7373
|
if (serverFramework === "hono") {
|
|
7349
7374
|
routeContent = emitHonoRoutes(table, graph, {
|
|
@@ -7357,11 +7382,11 @@ async function generate(configPath) {
|
|
|
7357
7382
|
throw new Error(`Framework "${serverFramework}" is not yet supported. Currently only "hono" is available.`);
|
|
7358
7383
|
}
|
|
7359
7384
|
files.push({
|
|
7360
|
-
path:
|
|
7385
|
+
path: join2(serverDir, "routes", `${table.name}.ts`),
|
|
7361
7386
|
content: routeContent
|
|
7362
7387
|
});
|
|
7363
7388
|
files.push({
|
|
7364
|
-
path:
|
|
7389
|
+
path: join2(clientDir, `${table.name}.ts`),
|
|
7365
7390
|
content: emitClient(table, graph, {
|
|
7366
7391
|
useJsExtensions: cfg.useJsExtensionsClient,
|
|
7367
7392
|
includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
|
|
@@ -7370,12 +7395,12 @@ async function generate(configPath) {
|
|
|
7370
7395
|
});
|
|
7371
7396
|
}
|
|
7372
7397
|
files.push({
|
|
7373
|
-
path:
|
|
7398
|
+
path: join2(clientDir, "index.ts"),
|
|
7374
7399
|
content: emitClientIndex(Object.values(model.tables), cfg.useJsExtensionsClient, graph, { maxDepth: cfg.includeMethodsDepth ?? 2, skipJunctionTables: cfg.skipJunctionTables ?? true })
|
|
7375
7400
|
});
|
|
7376
7401
|
if (serverFramework === "hono") {
|
|
7377
7402
|
files.push({
|
|
7378
|
-
path:
|
|
7403
|
+
path: join2(serverDir, "router.ts"),
|
|
7379
7404
|
content: emitHonoRouter(Object.values(model.tables), getAuthStrategy(normalizedAuth) !== "none", cfg.useJsExtensions, cfg.pullToken)
|
|
7380
7405
|
});
|
|
7381
7406
|
}
|
|
@@ -7385,63 +7410,88 @@ async function generate(configPath) {
|
|
|
7385
7410
|
}
|
|
7386
7411
|
const contract = generateUnifiedContract2(model, cfg, graph);
|
|
7387
7412
|
files.push({
|
|
7388
|
-
path:
|
|
7413
|
+
path: join2(serverDir, "CONTRACT.md"),
|
|
7389
7414
|
content: generateUnifiedContractMarkdown2(contract)
|
|
7390
7415
|
});
|
|
7391
7416
|
files.push({
|
|
7392
|
-
path:
|
|
7417
|
+
path: join2(clientDir, "CONTRACT.md"),
|
|
7393
7418
|
content: generateUnifiedContractMarkdown2(contract)
|
|
7394
7419
|
});
|
|
7395
7420
|
const contractCode = emitUnifiedContract(model, cfg, graph);
|
|
7396
7421
|
files.push({
|
|
7397
|
-
path:
|
|
7422
|
+
path: join2(serverDir, "contract.ts"),
|
|
7398
7423
|
content: contractCode
|
|
7399
7424
|
});
|
|
7400
7425
|
const clientFiles = files.filter((f) => {
|
|
7401
7426
|
return f.path.includes(clientDir);
|
|
7402
7427
|
});
|
|
7403
7428
|
files.push({
|
|
7404
|
-
path:
|
|
7429
|
+
path: join2(serverDir, "sdk-bundle.ts"),
|
|
7405
7430
|
content: emitSdkBundle(clientFiles, clientDir, CLI_VERSION)
|
|
7406
7431
|
});
|
|
7407
7432
|
if (generateTests) {
|
|
7408
7433
|
console.log("\uD83E\uDDEA Generating tests...");
|
|
7409
7434
|
const relativeClientPath = relative(testDir, clientDir);
|
|
7410
7435
|
files.push({
|
|
7411
|
-
path:
|
|
7436
|
+
path: join2(testDir, "setup.ts"),
|
|
7412
7437
|
content: emitTestSetup(relativeClientPath, testFramework)
|
|
7413
7438
|
});
|
|
7414
7439
|
files.push({
|
|
7415
|
-
path:
|
|
7440
|
+
path: join2(testDir, "docker-compose.yml"),
|
|
7416
7441
|
content: emitDockerCompose()
|
|
7417
7442
|
});
|
|
7418
7443
|
files.push({
|
|
7419
|
-
path:
|
|
7444
|
+
path: join2(testDir, "run-tests.sh"),
|
|
7420
7445
|
content: emitTestScript(testFramework, testDir)
|
|
7421
7446
|
});
|
|
7422
7447
|
files.push({
|
|
7423
|
-
path:
|
|
7448
|
+
path: join2(testDir, ".gitignore"),
|
|
7424
7449
|
content: emitTestGitignore()
|
|
7425
7450
|
});
|
|
7426
7451
|
if (testFramework === "vitest") {
|
|
7427
7452
|
files.push({
|
|
7428
|
-
path:
|
|
7453
|
+
path: join2(testDir, "vitest.config.ts"),
|
|
7429
7454
|
content: emitVitestConfig()
|
|
7430
7455
|
});
|
|
7431
7456
|
}
|
|
7432
7457
|
for (const table of Object.values(model.tables)) {
|
|
7433
7458
|
files.push({
|
|
7434
|
-
path:
|
|
7459
|
+
path: join2(testDir, `${table.name}.test.ts`),
|
|
7435
7460
|
content: emitTableTest(table, model, relativeClientPath, testFramework)
|
|
7436
7461
|
});
|
|
7437
7462
|
}
|
|
7438
7463
|
}
|
|
7439
7464
|
console.log("✍️ Writing files...");
|
|
7440
7465
|
const writeResult = await writeFilesIfChanged(files);
|
|
7441
|
-
|
|
7466
|
+
let deleteResult = { deleted: 0, filesDeleted: [] };
|
|
7467
|
+
if (cfg.clean !== false) {
|
|
7468
|
+
const dirsToScan = [
|
|
7469
|
+
serverDir,
|
|
7470
|
+
join2(serverDir, "types"),
|
|
7471
|
+
join2(serverDir, "zod"),
|
|
7472
|
+
join2(serverDir, "routes"),
|
|
7473
|
+
join2(serverDir, "core"),
|
|
7474
|
+
clientDir,
|
|
7475
|
+
join2(clientDir, "types"),
|
|
7476
|
+
join2(clientDir, "zod"),
|
|
7477
|
+
join2(clientDir, "params")
|
|
7478
|
+
];
|
|
7479
|
+
if (generateTests)
|
|
7480
|
+
dirsToScan.push(testDir);
|
|
7481
|
+
const generatedPaths = new Set(files.map((f) => f.path));
|
|
7482
|
+
deleteResult = await deleteStaleFiles(generatedPaths, dirsToScan);
|
|
7483
|
+
}
|
|
7484
|
+
if (writeResult.written === 0 && deleteResult.deleted === 0) {
|
|
7442
7485
|
console.log(`✅ All ${writeResult.unchanged} files up-to-date (no changes)`);
|
|
7443
7486
|
} else {
|
|
7444
|
-
|
|
7487
|
+
const parts = [];
|
|
7488
|
+
if (writeResult.written > 0)
|
|
7489
|
+
parts.push(`updated ${writeResult.written} files`);
|
|
7490
|
+
if (deleteResult.deleted > 0)
|
|
7491
|
+
parts.push(`deleted ${deleteResult.deleted} stale files`);
|
|
7492
|
+
if (writeResult.unchanged > 0)
|
|
7493
|
+
parts.push(`${writeResult.unchanged} unchanged`);
|
|
7494
|
+
console.log(`✅ ${parts.join(", ")}`);
|
|
7445
7495
|
}
|
|
7446
7496
|
console.log(` Server: ${serverDir}`);
|
|
7447
7497
|
console.log(` Client: ${sameDirectory ? clientDir + " (in sdk subdir due to same output dir)" : clientDir}`);
|
|
@@ -7480,10 +7530,10 @@ var import_config2 = __toESM(require_config(), 1);
|
|
|
7480
7530
|
import { resolve as resolve3 } from "node:path";
|
|
7481
7531
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7482
7532
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7483
|
-
import { dirname as dirname4, join as
|
|
7533
|
+
import { dirname as dirname4, join as join4 } from "node:path";
|
|
7484
7534
|
var __filename3 = fileURLToPath2(import.meta.url);
|
|
7485
7535
|
var __dirname3 = dirname4(__filename3);
|
|
7486
|
-
var packageJson = JSON.parse(readFileSync3(
|
|
7536
|
+
var packageJson = JSON.parse(readFileSync3(join4(__dirname3, "../package.json"), "utf-8"));
|
|
7487
7537
|
var VERSION = packageJson.version;
|
|
7488
7538
|
var args = process.argv.slice(2);
|
|
7489
7539
|
var command = args[0];
|
package/dist/index.js
CHANGED
|
@@ -488,8 +488,8 @@ var require_config = __commonJS(() => {
|
|
|
488
488
|
});
|
|
489
489
|
|
|
490
490
|
// src/utils.ts
|
|
491
|
-
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
492
|
-
import { dirname } from "path";
|
|
491
|
+
import { mkdir, writeFile, readFile, readdir, unlink } from "fs/promises";
|
|
492
|
+
import { dirname, join } from "path";
|
|
493
493
|
import { existsSync } from "fs";
|
|
494
494
|
async function writeFilesIfChanged(files) {
|
|
495
495
|
let written = 0;
|
|
@@ -514,6 +514,28 @@ async function ensureDirs(dirs) {
|
|
|
514
514
|
for (const d of dirs)
|
|
515
515
|
await mkdir(d, { recursive: true });
|
|
516
516
|
}
|
|
517
|
+
async function deleteStaleFiles(generatedPaths, dirsToScan) {
|
|
518
|
+
let deleted = 0;
|
|
519
|
+
const filesDeleted = [];
|
|
520
|
+
for (const dir of dirsToScan) {
|
|
521
|
+
if (!existsSync(dir))
|
|
522
|
+
continue;
|
|
523
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
524
|
+
for (const entry of entries) {
|
|
525
|
+
if (!entry.isFile())
|
|
526
|
+
continue;
|
|
527
|
+
if (!/\.(ts|md|yml|sh)$/.test(entry.name))
|
|
528
|
+
continue;
|
|
529
|
+
const fullPath = join(dir, entry.name);
|
|
530
|
+
if (!generatedPaths.has(fullPath)) {
|
|
531
|
+
await unlink(fullPath);
|
|
532
|
+
deleted++;
|
|
533
|
+
filesDeleted.push(fullPath);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return { deleted, filesDeleted };
|
|
538
|
+
}
|
|
517
539
|
var pascal = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
|
|
518
540
|
var init_utils = () => {};
|
|
519
541
|
|
|
@@ -1731,7 +1753,7 @@ var init_emit_sdk_contract = __esm(() => {
|
|
|
1731
1753
|
|
|
1732
1754
|
// src/index.ts
|
|
1733
1755
|
var import_config = __toESM(require_config(), 1);
|
|
1734
|
-
import { join, relative, dirname as dirname2 } from "node:path";
|
|
1756
|
+
import { join as join2, relative, dirname as dirname2 } from "node:path";
|
|
1735
1757
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
1736
1758
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
1737
1759
|
|
|
@@ -2646,6 +2668,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
2646
2668
|
where?: Where<Select${Type}>;
|
|
2647
2669
|
orderBy?: string | string[];
|
|
2648
2670
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
2671
|
+
distinctOn?: string | string[];
|
|
2649
2672
|
${paramName}?: {
|
|
2650
2673
|
select?: string[];
|
|
2651
2674
|
exclude?: string[];
|
|
@@ -2678,6 +2701,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
2678
2701
|
where?: Where<Select${Type}>;
|
|
2679
2702
|
orderBy?: string | string[];
|
|
2680
2703
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
2704
|
+
distinctOn?: string | string[];
|
|
2681
2705
|
${includeParams};
|
|
2682
2706
|
}`;
|
|
2683
2707
|
} else if (pattern.type === "nested" && pattern.nestedKey) {
|
|
@@ -2693,6 +2717,7 @@ function emitClient(table, graph, opts, model) {
|
|
|
2693
2717
|
where?: Where<Select${Type}>;
|
|
2694
2718
|
orderBy?: string | string[];
|
|
2695
2719
|
order?: "asc" | "desc" | ("asc" | "desc")[];
|
|
2720
|
+
distinctOn?: string | string[];
|
|
2696
2721
|
${paramName}?: {
|
|
2697
2722
|
select?: string[];
|
|
2698
2723
|
exclude?: string[];
|
|
@@ -6286,7 +6311,7 @@ init_emit_sdk_contract();
|
|
|
6286
6311
|
init_utils();
|
|
6287
6312
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
6288
6313
|
var __dirname2 = dirname2(__filename2);
|
|
6289
|
-
var { version: CLI_VERSION } = JSON.parse(readFileSync(
|
|
6314
|
+
var { version: CLI_VERSION } = JSON.parse(readFileSync(join2(__dirname2, "../package.json"), "utf-8"));
|
|
6290
6315
|
async function generate(configPath) {
|
|
6291
6316
|
if (!existsSync2(configPath)) {
|
|
6292
6317
|
throw new Error(`Config file not found: ${configPath}
|
|
@@ -6319,26 +6344,26 @@ async function generate(configPath) {
|
|
|
6319
6344
|
const sameDirectory = serverDir === originalClientDir;
|
|
6320
6345
|
let clientDir = originalClientDir;
|
|
6321
6346
|
if (sameDirectory) {
|
|
6322
|
-
clientDir =
|
|
6347
|
+
clientDir = join2(originalClientDir, "sdk");
|
|
6323
6348
|
}
|
|
6324
6349
|
const serverFramework = cfg.serverFramework || "hono";
|
|
6325
6350
|
const generateTests = cfg.tests?.generate ?? false;
|
|
6326
6351
|
const originalTestDir = cfg.tests?.output || "./api/tests";
|
|
6327
6352
|
let testDir = originalTestDir;
|
|
6328
6353
|
if (generateTests && (originalTestDir === serverDir || originalTestDir === originalClientDir)) {
|
|
6329
|
-
testDir =
|
|
6354
|
+
testDir = join2(originalTestDir, "tests");
|
|
6330
6355
|
}
|
|
6331
6356
|
const testFramework = cfg.tests?.framework || "vitest";
|
|
6332
6357
|
console.log("\uD83D\uDCC1 Creating directories...");
|
|
6333
6358
|
const dirs = [
|
|
6334
6359
|
serverDir,
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6360
|
+
join2(serverDir, "types"),
|
|
6361
|
+
join2(serverDir, "zod"),
|
|
6362
|
+
join2(serverDir, "routes"),
|
|
6338
6363
|
clientDir,
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6364
|
+
join2(clientDir, "types"),
|
|
6365
|
+
join2(clientDir, "zod"),
|
|
6366
|
+
join2(clientDir, "params")
|
|
6342
6367
|
];
|
|
6343
6368
|
if (generateTests) {
|
|
6344
6369
|
dirs.push(testDir);
|
|
@@ -6346,28 +6371,28 @@ async function generate(configPath) {
|
|
|
6346
6371
|
await ensureDirs(dirs);
|
|
6347
6372
|
const files = [];
|
|
6348
6373
|
const includeSpec = emitIncludeSpec(graph);
|
|
6349
|
-
files.push({ path:
|
|
6350
|
-
files.push({ path:
|
|
6374
|
+
files.push({ path: join2(serverDir, "include-spec.ts"), content: includeSpec });
|
|
6375
|
+
files.push({ path: join2(clientDir, "include-spec.ts"), content: includeSpec });
|
|
6351
6376
|
const includeResolver = emitIncludeResolver(graph, cfg.useJsExtensions);
|
|
6352
|
-
files.push({ path:
|
|
6353
|
-
files.push({ path:
|
|
6354
|
-
files.push({ path:
|
|
6355
|
-
files.push({ path:
|
|
6356
|
-
files.push({ path:
|
|
6377
|
+
files.push({ path: join2(clientDir, "include-resolver.ts"), content: includeResolver });
|
|
6378
|
+
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod() });
|
|
6379
|
+
files.push({ path: join2(clientDir, "types", "shared.ts"), content: emitSharedTypes() });
|
|
6380
|
+
files.push({ path: join2(clientDir, "base-client.ts"), content: emitBaseClient() });
|
|
6381
|
+
files.push({ path: join2(clientDir, "where-types.ts"), content: emitWhereTypes() });
|
|
6357
6382
|
files.push({
|
|
6358
|
-
path:
|
|
6383
|
+
path: join2(serverDir, "include-builder.ts"),
|
|
6359
6384
|
content: emitIncludeBuilder(graph, cfg.includeMethodsDepth || 2)
|
|
6360
6385
|
});
|
|
6361
6386
|
files.push({
|
|
6362
|
-
path:
|
|
6387
|
+
path: join2(serverDir, "include-loader.ts"),
|
|
6363
6388
|
content: emitIncludeLoader(graph, model, cfg.includeMethodsDepth || 2, cfg.useJsExtensions)
|
|
6364
6389
|
});
|
|
6365
|
-
files.push({ path:
|
|
6390
|
+
files.push({ path: join2(serverDir, "logger.ts"), content: emitLogger() });
|
|
6366
6391
|
if (getAuthStrategy(normalizedAuth) !== "none") {
|
|
6367
|
-
files.push({ path:
|
|
6392
|
+
files.push({ path: join2(serverDir, "auth.ts"), content: emitAuth(normalizedAuth) });
|
|
6368
6393
|
}
|
|
6369
6394
|
files.push({
|
|
6370
|
-
path:
|
|
6395
|
+
path: join2(serverDir, "core", "operations.ts"),
|
|
6371
6396
|
content: emitCoreOperations()
|
|
6372
6397
|
});
|
|
6373
6398
|
if (process.env.SDK_DEBUG) {
|
|
@@ -6376,13 +6401,13 @@ async function generate(configPath) {
|
|
|
6376
6401
|
for (const table of Object.values(model.tables)) {
|
|
6377
6402
|
const numericMode = cfg.numericMode ?? "auto";
|
|
6378
6403
|
const typesSrc = emitTypes(table, { numericMode }, model.enums);
|
|
6379
|
-
files.push({ path:
|
|
6380
|
-
files.push({ path:
|
|
6404
|
+
files.push({ path: join2(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
6405
|
+
files.push({ path: join2(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
6381
6406
|
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
6382
|
-
files.push({ path:
|
|
6383
|
-
files.push({ path:
|
|
6407
|
+
files.push({ path: join2(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6408
|
+
files.push({ path: join2(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6384
6409
|
const paramsZodSrc = emitParamsZod(table, graph);
|
|
6385
|
-
files.push({ path:
|
|
6410
|
+
files.push({ path: join2(clientDir, "params", `${table.name}.ts`), content: paramsZodSrc });
|
|
6386
6411
|
let routeContent;
|
|
6387
6412
|
if (serverFramework === "hono") {
|
|
6388
6413
|
routeContent = emitHonoRoutes(table, graph, {
|
|
@@ -6396,11 +6421,11 @@ async function generate(configPath) {
|
|
|
6396
6421
|
throw new Error(`Framework "${serverFramework}" is not yet supported. Currently only "hono" is available.`);
|
|
6397
6422
|
}
|
|
6398
6423
|
files.push({
|
|
6399
|
-
path:
|
|
6424
|
+
path: join2(serverDir, "routes", `${table.name}.ts`),
|
|
6400
6425
|
content: routeContent
|
|
6401
6426
|
});
|
|
6402
6427
|
files.push({
|
|
6403
|
-
path:
|
|
6428
|
+
path: join2(clientDir, `${table.name}.ts`),
|
|
6404
6429
|
content: emitClient(table, graph, {
|
|
6405
6430
|
useJsExtensions: cfg.useJsExtensionsClient,
|
|
6406
6431
|
includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
|
|
@@ -6409,12 +6434,12 @@ async function generate(configPath) {
|
|
|
6409
6434
|
});
|
|
6410
6435
|
}
|
|
6411
6436
|
files.push({
|
|
6412
|
-
path:
|
|
6437
|
+
path: join2(clientDir, "index.ts"),
|
|
6413
6438
|
content: emitClientIndex(Object.values(model.tables), cfg.useJsExtensionsClient, graph, { maxDepth: cfg.includeMethodsDepth ?? 2, skipJunctionTables: cfg.skipJunctionTables ?? true })
|
|
6414
6439
|
});
|
|
6415
6440
|
if (serverFramework === "hono") {
|
|
6416
6441
|
files.push({
|
|
6417
|
-
path:
|
|
6442
|
+
path: join2(serverDir, "router.ts"),
|
|
6418
6443
|
content: emitHonoRouter(Object.values(model.tables), getAuthStrategy(normalizedAuth) !== "none", cfg.useJsExtensions, cfg.pullToken)
|
|
6419
6444
|
});
|
|
6420
6445
|
}
|
|
@@ -6424,63 +6449,88 @@ async function generate(configPath) {
|
|
|
6424
6449
|
}
|
|
6425
6450
|
const contract = generateUnifiedContract2(model, cfg, graph);
|
|
6426
6451
|
files.push({
|
|
6427
|
-
path:
|
|
6452
|
+
path: join2(serverDir, "CONTRACT.md"),
|
|
6428
6453
|
content: generateUnifiedContractMarkdown2(contract)
|
|
6429
6454
|
});
|
|
6430
6455
|
files.push({
|
|
6431
|
-
path:
|
|
6456
|
+
path: join2(clientDir, "CONTRACT.md"),
|
|
6432
6457
|
content: generateUnifiedContractMarkdown2(contract)
|
|
6433
6458
|
});
|
|
6434
6459
|
const contractCode = emitUnifiedContract(model, cfg, graph);
|
|
6435
6460
|
files.push({
|
|
6436
|
-
path:
|
|
6461
|
+
path: join2(serverDir, "contract.ts"),
|
|
6437
6462
|
content: contractCode
|
|
6438
6463
|
});
|
|
6439
6464
|
const clientFiles = files.filter((f) => {
|
|
6440
6465
|
return f.path.includes(clientDir);
|
|
6441
6466
|
});
|
|
6442
6467
|
files.push({
|
|
6443
|
-
path:
|
|
6468
|
+
path: join2(serverDir, "sdk-bundle.ts"),
|
|
6444
6469
|
content: emitSdkBundle(clientFiles, clientDir, CLI_VERSION)
|
|
6445
6470
|
});
|
|
6446
6471
|
if (generateTests) {
|
|
6447
6472
|
console.log("\uD83E\uDDEA Generating tests...");
|
|
6448
6473
|
const relativeClientPath = relative(testDir, clientDir);
|
|
6449
6474
|
files.push({
|
|
6450
|
-
path:
|
|
6475
|
+
path: join2(testDir, "setup.ts"),
|
|
6451
6476
|
content: emitTestSetup(relativeClientPath, testFramework)
|
|
6452
6477
|
});
|
|
6453
6478
|
files.push({
|
|
6454
|
-
path:
|
|
6479
|
+
path: join2(testDir, "docker-compose.yml"),
|
|
6455
6480
|
content: emitDockerCompose()
|
|
6456
6481
|
});
|
|
6457
6482
|
files.push({
|
|
6458
|
-
path:
|
|
6483
|
+
path: join2(testDir, "run-tests.sh"),
|
|
6459
6484
|
content: emitTestScript(testFramework, testDir)
|
|
6460
6485
|
});
|
|
6461
6486
|
files.push({
|
|
6462
|
-
path:
|
|
6487
|
+
path: join2(testDir, ".gitignore"),
|
|
6463
6488
|
content: emitTestGitignore()
|
|
6464
6489
|
});
|
|
6465
6490
|
if (testFramework === "vitest") {
|
|
6466
6491
|
files.push({
|
|
6467
|
-
path:
|
|
6492
|
+
path: join2(testDir, "vitest.config.ts"),
|
|
6468
6493
|
content: emitVitestConfig()
|
|
6469
6494
|
});
|
|
6470
6495
|
}
|
|
6471
6496
|
for (const table of Object.values(model.tables)) {
|
|
6472
6497
|
files.push({
|
|
6473
|
-
path:
|
|
6498
|
+
path: join2(testDir, `${table.name}.test.ts`),
|
|
6474
6499
|
content: emitTableTest(table, model, relativeClientPath, testFramework)
|
|
6475
6500
|
});
|
|
6476
6501
|
}
|
|
6477
6502
|
}
|
|
6478
6503
|
console.log("✍️ Writing files...");
|
|
6479
6504
|
const writeResult = await writeFilesIfChanged(files);
|
|
6480
|
-
|
|
6505
|
+
let deleteResult = { deleted: 0, filesDeleted: [] };
|
|
6506
|
+
if (cfg.clean !== false) {
|
|
6507
|
+
const dirsToScan = [
|
|
6508
|
+
serverDir,
|
|
6509
|
+
join2(serverDir, "types"),
|
|
6510
|
+
join2(serverDir, "zod"),
|
|
6511
|
+
join2(serverDir, "routes"),
|
|
6512
|
+
join2(serverDir, "core"),
|
|
6513
|
+
clientDir,
|
|
6514
|
+
join2(clientDir, "types"),
|
|
6515
|
+
join2(clientDir, "zod"),
|
|
6516
|
+
join2(clientDir, "params")
|
|
6517
|
+
];
|
|
6518
|
+
if (generateTests)
|
|
6519
|
+
dirsToScan.push(testDir);
|
|
6520
|
+
const generatedPaths = new Set(files.map((f) => f.path));
|
|
6521
|
+
deleteResult = await deleteStaleFiles(generatedPaths, dirsToScan);
|
|
6522
|
+
}
|
|
6523
|
+
if (writeResult.written === 0 && deleteResult.deleted === 0) {
|
|
6481
6524
|
console.log(`✅ All ${writeResult.unchanged} files up-to-date (no changes)`);
|
|
6482
6525
|
} else {
|
|
6483
|
-
|
|
6526
|
+
const parts = [];
|
|
6527
|
+
if (writeResult.written > 0)
|
|
6528
|
+
parts.push(`updated ${writeResult.written} files`);
|
|
6529
|
+
if (deleteResult.deleted > 0)
|
|
6530
|
+
parts.push(`deleted ${deleteResult.deleted} stale files`);
|
|
6531
|
+
if (writeResult.unchanged > 0)
|
|
6532
|
+
parts.push(`${writeResult.unchanged} unchanged`);
|
|
6533
|
+
console.log(`✅ ${parts.join(", ")}`);
|
|
6484
6534
|
}
|
|
6485
6535
|
console.log(` Server: ${serverDir}`);
|
|
6486
6536
|
console.log(` Client: ${sameDirectory ? clientDir + " (in sdk subdir due to same output dir)" : clientDir}`);
|
package/dist/types.d.ts
CHANGED
package/dist/utils.d.ts
CHANGED
|
@@ -20,3 +20,11 @@ export declare function writeFilesIfChanged(files: Array<{
|
|
|
20
20
|
*/
|
|
21
21
|
export declare function hashContent(content: string): string;
|
|
22
22
|
export declare function ensureDirs(dirs: string[]): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Delete files in the given directories that are not in the set of generated paths.
|
|
25
|
+
* Used to remove stale files for tables that no longer exist in the schema.
|
|
26
|
+
*/
|
|
27
|
+
export declare function deleteStaleFiles(generatedPaths: Set<string>, dirsToScan: string[]): Promise<{
|
|
28
|
+
deleted: number;
|
|
29
|
+
filesDeleted: string[];
|
|
30
|
+
}>;
|