@drzl/cli 1.0.0 → 2.0.0

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.cjs CHANGED
@@ -26,14 +26,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/cli.ts
27
27
  var import_analyzer = require("@drzl/analyzer");
28
28
  var import_generator_orpc = require("@drzl/generator-orpc");
29
- var import_chalk = __toESM(require("chalk"), 1);
29
+ var import_chalk2 = __toESM(require("chalk"), 1);
30
30
  var import_chokidar = __toESM(require("chokidar"), 1);
31
31
  var import_cli_progress = __toESM(require("cli-progress"), 1);
32
32
  var import_commander = require("commander");
33
- var path2 = __toESM(require("path"), 1);
33
+ var path3 = __toESM(require("path"), 1);
34
34
  var import_ora = __toESM(require("ora"), 1);
35
35
 
36
36
  // src/config.ts
37
+ var import_validation_core = require("@drzl/validation-core");
37
38
  var fs = __toESM(require("fs"), 1);
38
39
  var import_node_module = require("module");
39
40
  var path = __toESM(require("path"), 1);
@@ -42,8 +43,41 @@ var NamingSchema = import_zod.z.object({
42
43
  routerSuffix: import_zod.z.string().default("Router"),
43
44
  procedureCase: import_zod.z.enum(["camel", "kebab", "snake"]).default("camel")
44
45
  }).partial();
46
+ var AffixValueSchema = import_zod.z.union(
47
+ [
48
+ import_zod.z.string(),
49
+ import_zod.z.object({
50
+ insert: import_zod.z.string().optional(),
51
+ update: import_zod.z.string().optional(),
52
+ select: import_zod.z.string().optional()
53
+ }).strict()
54
+ ],
55
+ {
56
+ error: 'Expected a string to use for every mode, or an object with any of the keys "insert", "update" and "select". Those keys are lowercase, matching the mode names drzl uses everywhere else.'
57
+ }
58
+ );
59
+ var AffixPartSchema = import_zod.z.object({
60
+ prefix: AffixValueSchema.optional(),
61
+ suffix: AffixValueSchema.optional()
62
+ }).strict();
63
+ var AffixSchema = import_zod.z.object({
64
+ /**
65
+ * `preserve` (default) keeps today's output: the Drizzle export name goes into the
66
+ * identifier verbatim, so `export const users` yields `InsertusersSchema`. `pascal`
67
+ * upper-camels it first, yielding `InsertUsersSchema`.
68
+ */
69
+ tableCase: import_zod.z.enum(["preserve", "pascal"]).optional(),
70
+ schema: AffixPartSchema.optional(),
71
+ type: AffixPartSchema.optional()
72
+ }).strict();
73
+ var ImportExtensionSchema = import_zod.z.enum(import_validation_core.IMPORT_EXTENSIONS);
45
74
  var GeneratorSchema = import_zod.z.object({
46
75
  kind: import_zod.z.enum(["orpc", "service", "zod", "valibot", "arktype"]),
76
+ /**
77
+ * Overrides the top-level `importExtension` for this generator alone, for a project whose
78
+ * generated directories are compiled by different tsconfigs.
79
+ */
80
+ importExtension: ImportExtensionSchema.optional(),
47
81
  template: import_zod.z.string().optional(),
48
82
  includeRelations: import_zod.z.boolean().optional(),
49
83
  naming: NamingSchema.optional(),
@@ -64,12 +98,22 @@ var GeneratorSchema = import_zod.z.object({
64
98
  // zod/valibot/arktype generator specific options
65
99
  schemaSuffix: import_zod.z.string().optional(),
66
100
  fileSuffix: import_zod.z.string().optional(),
101
+ /**
102
+ * Prefixes, suffixes and table casing for generated identifiers (zod/valibot/arktype).
103
+ * Omitting it reproduces the output of every previous release exactly.
104
+ */
105
+ affix: AffixSchema.optional(),
67
106
  // orpc validation sharing
68
107
  validation: import_zod.z.object({
69
108
  useShared: import_zod.z.boolean().default(false).optional(),
70
109
  library: import_zod.z.enum(["zod", "valibot", "arktype"]).default("zod").optional(),
71
110
  importPath: import_zod.z.string().optional(),
72
- schemaSuffix: import_zod.z.string().optional()
111
+ schemaSuffix: import_zod.z.string().optional(),
112
+ /**
113
+ * How the validation generator named its exports. Usually left unset: the CLI copies
114
+ * it from the sibling generator whose `kind` matches `library`.
115
+ */
116
+ affix: AffixSchema.optional()
73
117
  }).optional(),
74
118
  // template options
75
119
  templateOptions: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional()
@@ -82,13 +126,95 @@ var AnalyzerSchema = import_zod.z.object({
82
126
  var ConfigSchema = import_zod.z.object({
83
127
  schema: import_zod.z.string(),
84
128
  outDir: import_zod.z.string().default("src/api"),
129
+ /**
130
+ * How every relative specifier drzl invents spells its extension, for every generator.
131
+ * A generator may override it. Defaults to `js`, which is the only form that resolves
132
+ * under every `moduleResolution` without a compiler flag.
133
+ */
134
+ importExtension: ImportExtensionSchema.default(import_validation_core.DEFAULT_IMPORT_EXTENSION),
85
135
  analyzer: AnalyzerSchema.default({
86
136
  includeRelations: true,
87
137
  validateConstraints: true,
88
138
  includeHeuristicRelations: false
89
139
  }),
90
140
  generators: import_zod.z.array(GeneratorSchema).min(1).default([{ kind: "orpc" }])
141
+ }).superRefine((cfg, ctx) => {
142
+ cfg.generators.forEach((g, i) => {
143
+ const report = (base, affix, schemaSuffix) => {
144
+ for (const issue of (0, import_validation_core.validateAffix)(affix, schemaSuffix)) {
145
+ ctx.addIssue({
146
+ code: "custom",
147
+ path: ["generators", i, ...base, ...issue.path],
148
+ message: issue.message
149
+ });
150
+ }
151
+ };
152
+ report(["affix"], g.affix, g.schemaSuffix);
153
+ report(
154
+ ["validation", "affix"],
155
+ g.validation?.affix,
156
+ g.validation?.schemaSuffix
157
+ );
158
+ });
91
159
  });
160
+ function sharedSchemaNames(opts) {
161
+ const resolved = (0, import_validation_core.resolveAffix)(opts);
162
+ return import_validation_core.NAME_MODES.map((mode) => (0, import_validation_core.schemaName)(mode, import_validation_core.AFFIX_PROBE_TABLE, resolved));
163
+ }
164
+ function resolveConfig(cfg) {
165
+ const warnings = [];
166
+ const generators = cfg.generators.map((g) => ({
167
+ ...g,
168
+ importExtension: g.importExtension ?? cfg.importExtension
169
+ }));
170
+ for (const g of generators) {
171
+ if (g.kind !== "orpc") continue;
172
+ const v = g.validation;
173
+ if (!v?.useShared) continue;
174
+ const library = v.library ?? "zod";
175
+ const siblings = generators.filter((s) => s.kind === library);
176
+ if (siblings.length !== 1) continue;
177
+ const sibling = siblings[0];
178
+ const theirs = sharedSchemaNames({
179
+ affix: sibling.affix,
180
+ schemaSuffix: sibling.schemaSuffix
181
+ });
182
+ if (!v.affix) {
183
+ if (sibling.affix) {
184
+ g.validation = {
185
+ ...v,
186
+ affix: (0, import_validation_core.resolveAffix)({
187
+ affix: sibling.affix,
188
+ schemaSuffix: sibling.schemaSuffix
189
+ })
190
+ };
191
+ continue;
192
+ }
193
+ const mine2 = sharedSchemaNames({ schemaSuffix: v.schemaSuffix });
194
+ if (mine2.join(",") !== theirs.join(",")) {
195
+ warnings.push(
196
+ `drzl config: the "orpc" generator's validation.schemaSuffix (${JSON.stringify(v.schemaSuffix ?? "Schema")}) does not match the "${library}" generator's schemaSuffix (${JSON.stringify(sibling.schemaSuffix ?? "Schema")}). The router will import ${mine2.join(", ")} but the "${library}" generator exports ${theirs.join(", ")}, so the generated router will not compile. Set both to the same value, or move to "affix", which is inherited automatically.`
197
+ );
198
+ }
199
+ continue;
200
+ }
201
+ const mine = sharedSchemaNames({
202
+ affix: v.affix,
203
+ schemaSuffix: v.schemaSuffix
204
+ });
205
+ if (mine.join(",") !== theirs.join(",")) {
206
+ throw new Error(
207
+ `drzl config: the "orpc" generator imports shared ${library} schemas, but its validation.affix disagrees with the "${library}" generator's own naming. The router would import ${mine.join(", ")} while the "${library}" generator exports ${theirs.join(", ")}. Make them match, or drop validation.affix and let it be inherited from the "${library}" generator.`
208
+ );
209
+ }
210
+ }
211
+ return { config: { ...cfg, generators }, warnings };
212
+ }
213
+ function finalize(raw) {
214
+ const { config, warnings } = resolveConfig(ConfigSchema.parse(raw));
215
+ for (const w of warnings) console.warn(w);
216
+ return config;
217
+ }
92
218
  async function loadConfig(customPath) {
93
219
  const fsp = await import("fs/promises");
94
220
  const candidates = customPath ? [customPath] : [
@@ -108,7 +234,7 @@ async function loadConfig(customPath) {
108
234
  const ext = path.extname(p).toLowerCase();
109
235
  if (ext === ".json") {
110
236
  const raw2 = JSON.parse(await fsp.readFile(p, "utf8"));
111
- return ConfigSchema.parse(raw2);
237
+ return finalize(raw2);
112
238
  }
113
239
  const { createJiti } = await import("jiti");
114
240
  const stat = await fsp.stat(p);
@@ -122,12 +248,12 @@ async function loadConfig(customPath) {
122
248
  // bump on edit
123
249
  interopDefault: true,
124
250
  tryNative: false
125
- // <— prevent native import of .ts
251
+ // <-- prevent native import of .ts
126
252
  // debug: true,
127
253
  });
128
254
  const mod = await jiti.import(p);
129
255
  const raw = mod?.default ?? mod;
130
- return ConfigSchema.parse(raw);
256
+ return finalize(raw);
131
257
  }
132
258
  return null;
133
259
  }
@@ -182,9 +308,84 @@ function computeWatchTargets(cfg, cwd = process.cwd()) {
182
308
  return [...targets];
183
309
  }
184
310
 
311
+ // src/sponsor.ts
312
+ var import_chalk = __toESM(require("chalk"), 1);
313
+ var import_node_fs = require("fs");
314
+ var import_node_path = __toESM(require("path"), 1);
315
+ var CACHE_DIR = import_node_path.default.join(process.cwd(), "node_modules", ".cache", "@drzl");
316
+ var CACHE_FILE = import_node_path.default.join(CACHE_DIR, "sponsor-message.json");
317
+ var DEFAULT_INTERVAL_MS = 1e3 * 60 * 15;
318
+ var shownThisProcess = false;
319
+ var tips = [
320
+ "Pair DRZL watch mode with drizzle-kit to keep schema & API synced.",
321
+ "Templatize your ORPC routers to roll out new endpoints safely.",
322
+ "Need typed validators? Enable the zod, valibot, or arktype generators.",
323
+ "Use output headers to track generated files and trim noisy diffs."
324
+ ];
325
+ var green = (msg) => import_chalk.default.hex("#6ee7b7")(msg);
326
+ var cyan = (msg) => import_chalk.default.cyan(msg);
327
+ var gray = (msg) => import_chalk.default.gray(msg);
328
+ function maybeShowSponsorMessage({
329
+ reason = "generate",
330
+ minIntervalMs = DEFAULT_INTERVAL_MS,
331
+ force = false
332
+ } = {}) {
333
+ const hideViaEnv = process.env.DRZL_HIDE_SPONSOR?.toLowerCase();
334
+ const hideRequested = hideViaEnv === "1" || hideViaEnv === "true";
335
+ if (hideRequested || process.env.CI && !force || shownThisProcess && !force) return;
336
+ try {
337
+ (0, import_node_fs.mkdirSync)(CACHE_DIR, { recursive: true });
338
+ const payload = readCache();
339
+ payload.runs += 1;
340
+ const now = Date.now();
341
+ const shouldShow = force || now - (payload.lastShownAt ?? 0) >= minIntervalMs;
342
+ if (shouldShow) {
343
+ payload.lastShownAt = now;
344
+ payload.lastReason = reason;
345
+ }
346
+ writeCache(payload);
347
+ if (!shouldShow) return;
348
+ shownThisProcess = true;
349
+ const tip = tips[payload.runs % tips.length];
350
+ console.log(
351
+ `
352
+ ${cyan(`\u{1F680} DRZL finished a ${reason} run (#${payload.runs.toLocaleString()}).`)}
353
+
354
+ ${green("\u2728 Sponsors keep DRZL shipping. Consider supporting ongoing dev:")}
355
+ ${green("GitHub Sponsors")} ${gray("\u2192 https://github.com/sponsors/omar-dulaimi")}
356
+
357
+ ${green("Pro tip:")} ${tip}
358
+ `
359
+ );
360
+ } catch {
361
+ }
362
+ }
363
+ function readCache() {
364
+ if (!(0, import_node_fs.existsSync)(CACHE_FILE)) {
365
+ return { runs: 0 };
366
+ }
367
+ try {
368
+ const data = JSON.parse((0, import_node_fs.readFileSync)(CACHE_FILE, "utf8"));
369
+ if (typeof data.runs !== "number") return { runs: 0 };
370
+ return data;
371
+ } catch {
372
+ return { runs: 0 };
373
+ }
374
+ }
375
+ function writeCache(payload) {
376
+ (0, import_node_fs.writeFileSync)(CACHE_FILE, JSON.stringify(payload, null, 2), "utf8");
377
+ }
378
+
185
379
  // src/cli.ts
186
380
  var program = new import_commander.Command();
187
381
  program.name("drzl").description("DRZL - Drizzle Developer Toolkit").version("0.0.1");
382
+ program.addHelpText(
383
+ "afterAll",
384
+ `
385
+ Need a template, adapter, or generator DRZL doesn't ship yet?
386
+ \u2192 DM @omardulaimidev on X: https://x.com/omardulaimidev
387
+ `
388
+ );
188
389
  program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").option("--relations", "include relations", true).option("--validate", "validate constraints", true).option("--out <file>", "write analysis JSON to file").option("--json", "print JSON to stdout (overrides --out)", false).action(async (schema, opts) => {
189
390
  try {
190
391
  const analyzer = new import_analyzer.SchemaAnalyzer(schema);
@@ -201,9 +402,9 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
201
402
  } else if (opts.out) {
202
403
  const fs2 = await import("fs/promises");
203
404
  await fs2.writeFile(opts.out, json, "utf8");
204
- spinner?.succeed(import_chalk.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
405
+ spinner?.succeed(import_chalk2.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
205
406
  } else {
206
- spinner?.succeed(import_chalk.default.green(`Analyzed in ${ms}ms`));
407
+ spinner?.succeed(import_chalk2.default.green(`Analyzed in ${ms}ms`));
207
408
  console.log(json);
208
409
  }
209
410
  process.exit(res.issues.some((i) => i.level === "error") ? 2 : 0);
@@ -213,7 +414,7 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
213
414
  console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_ANALYZE", message: msg }));
214
415
  else
215
416
  console.error(
216
- import_chalk.default.red("Analyze failed (DRZL_CLI_ANALYZE):"),
417
+ import_chalk2.default.red("Analyze failed (DRZL_CLI_ANALYZE):"),
217
418
  msg,
218
419
  "\nTip: run with --json for structured output."
219
420
  );
@@ -225,7 +426,7 @@ program.command("generate").description("Run configured generators (drzl.config.
225
426
  const cfg = await loadConfig(opts.config);
226
427
  if (!cfg) {
227
428
  console.error(
228
- import_chalk.default.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
429
+ import_chalk2.default.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
229
430
  );
230
431
  process.exit(2);
231
432
  return;
@@ -256,12 +457,13 @@ program.command("generate").description("Run configured generators (drzl.config.
256
457
  outputHeader: g.outputHeader,
257
458
  format: g.format,
258
459
  templateOptions: g.templateOptions,
460
+ importExtension: g.importExtension,
259
461
  validation: g.validation,
260
462
  onProgress: ({ index }) => progress.update(index)
261
463
  });
262
464
  progress.stop();
263
- (0, import_ora.default)().succeed(import_chalk.default.green(`Generated (${g.kind}): ${files.length} files`));
264
- files.forEach((f) => console.log(" -", import_chalk.default.cyan(f)));
465
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (${g.kind}): ${files.length} files`));
466
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
265
467
  } else if (g.kind === "service") {
266
468
  try {
267
469
  const { ServiceGenerator } = await import("@drzl/generator-service");
@@ -273,18 +475,19 @@ program.command("generate").description("Run configured generators (drzl.config.
273
475
  format: g.format,
274
476
  dataAccess: g.dataAccess,
275
477
  dbImportPath: g.dbImportPath,
276
- schemaImportPath: g.schemaImportPath
478
+ schemaImportPath: g.schemaImportPath,
479
+ importExtension: g.importExtension
277
480
  });
278
481
  progress.stop();
279
- (0, import_ora.default)().succeed(import_chalk.default.green(`Generated (service): ${files.length} files`));
280
- files.forEach((f) => console.log(" -", import_chalk.default.cyan(f)));
482
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (service): ${files.length} files`));
483
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
281
484
  } catch (e) {
282
485
  progress.stop();
283
486
  console.error(
284
- import_chalk.default.red("Service generator missing."),
285
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-service")
487
+ import_chalk2.default.red("Service generator missing."),
488
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-service")
286
489
  );
287
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
490
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
288
491
  process.exit(1);
289
492
  }
290
493
  } else if (g.kind === "zod") {
@@ -297,18 +500,20 @@ program.command("generate").description("Run configured generators (drzl.config.
297
500
  outputHeader: g.outputHeader,
298
501
  format: g.format,
299
502
  schemaSuffix: g.schemaSuffix,
300
- fileSuffix: g.fileSuffix
503
+ fileSuffix: g.fileSuffix,
504
+ importExtension: g.importExtension,
505
+ affix: g.affix
301
506
  });
302
507
  progress.stop();
303
- (0, import_ora.default)().succeed(import_chalk.default.green(`Generated (zod): ${files.length} files`));
304
- files.forEach((f) => console.log(" -", import_chalk.default.cyan(f)));
508
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (zod): ${files.length} files`));
509
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
305
510
  } catch (e) {
306
511
  progress.stop();
307
512
  console.error(
308
- import_chalk.default.red("Zod generator missing."),
309
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-zod")
513
+ import_chalk2.default.red("Zod generator missing."),
514
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-zod")
310
515
  );
311
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
516
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
312
517
  process.exit(1);
313
518
  }
314
519
  } else if (g.kind === "valibot") {
@@ -321,18 +526,20 @@ program.command("generate").description("Run configured generators (drzl.config.
321
526
  outputHeader: g.outputHeader,
322
527
  format: g.format,
323
528
  schemaSuffix: g.schemaSuffix,
324
- fileSuffix: g.fileSuffix
529
+ fileSuffix: g.fileSuffix,
530
+ importExtension: g.importExtension,
531
+ affix: g.affix
325
532
  });
326
533
  progress.stop();
327
- (0, import_ora.default)().succeed(import_chalk.default.green(`Generated (valibot): ${files.length} files`));
328
- files.forEach((f) => console.log(" -", import_chalk.default.cyan(f)));
534
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (valibot): ${files.length} files`));
535
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
329
536
  } catch (e) {
330
537
  progress.stop();
331
538
  console.error(
332
- import_chalk.default.red("Valibot generator missing."),
333
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-valibot")
539
+ import_chalk2.default.red("Valibot generator missing."),
540
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-valibot")
334
541
  );
335
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
542
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
336
543
  process.exit(1);
337
544
  }
338
545
  } else if (g.kind === "arktype") {
@@ -345,25 +552,30 @@ program.command("generate").description("Run configured generators (drzl.config.
345
552
  outputHeader: g.outputHeader,
346
553
  format: g.format,
347
554
  schemaSuffix: g.schemaSuffix,
348
- fileSuffix: g.fileSuffix
555
+ fileSuffix: g.fileSuffix,
556
+ importExtension: g.importExtension,
557
+ affix: g.affix
349
558
  });
350
559
  progress.stop();
351
- (0, import_ora.default)().succeed(import_chalk.default.green(`Generated (arktype): ${files.length} files`));
352
- files.forEach((f) => console.log(" -", import_chalk.default.cyan(f)));
560
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (arktype): ${files.length} files`));
561
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
353
562
  } catch (e) {
354
563
  progress.stop();
355
564
  console.error(
356
- import_chalk.default.red("ArkType generator missing."),
357
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-arktype")
565
+ import_chalk2.default.red("ArkType generator missing."),
566
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-arktype")
358
567
  );
359
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
568
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
360
569
  process.exit(1);
361
570
  }
362
571
  }
363
572
  }
573
+ if (cfg.generators.length) {
574
+ maybeShowSponsorMessage({ reason: "generate" });
575
+ }
364
576
  } catch (e) {
365
577
  console.error(
366
- import_chalk.default.red("Generate failed (DRZL_GEN_001):"),
578
+ import_chalk2.default.red("Generate failed (DRZL_GEN_001):"),
367
579
  e?.message ?? e,
368
580
  "\nTip: check your drzl.config.ts and template path."
369
581
  );
@@ -383,23 +595,24 @@ program.command("generate:orpc").argument("<schema>", "path to drizzle schema (T
383
595
  template: opts.template,
384
596
  includeRelations: !!opts.includeRelations
385
597
  });
386
- console.log(import_chalk.default.green(`Generated:`), files.map((f) => import_chalk.default.cyan(f)).join(", "));
598
+ console.log(import_chalk2.default.green(`Generated:`), files.map((f) => import_chalk2.default.cyan(f)).join(", "));
599
+ maybeShowSponsorMessage({ reason: "generate:orpc" });
387
600
  } catch (e) {
388
- console.error(import_chalk.default.red("Generate orpc failed:"), e?.message ?? e);
601
+ console.error(import_chalk2.default.red("Generate orpc failed:"), e?.message ?? e);
389
602
  process.exit(1);
390
603
  }
391
604
  });
392
605
  program.command("watch").description("Watch schema and regenerate on changes").option("-c, --config <path>", "path to drzl.config").option("--pipeline <name>", "all | analyze | generate-orpc", "all").option("--debounce <ms>", "debounce ms", "200").option("--json", "emit JSON logs", false).option("--poll", "force polling (helps WSL/Docker/remote FS)", false).action(async (opts) => {
393
606
  let cfg = await loadConfig(opts.config);
394
607
  if (!cfg) {
395
- console.error(import_chalk.default.red("No config found. Create drzl.config.ts or pass --config."));
608
+ console.error(import_chalk2.default.red("No config found. Create drzl.config.ts or pass --config."));
396
609
  process.exit(2);
397
610
  return;
398
611
  }
399
- const abs = (p) => path2.resolve(process.cwd(), p);
612
+ const abs = (p) => path3.resolve(process.cwd(), p);
400
613
  const isInside = (child, parent) => {
401
- const rel = path2.relative(parent, child);
402
- return !!rel && !rel.startsWith("..") && !path2.isAbsolute(rel);
614
+ const rel = path3.relative(parent, child);
615
+ return !!rel && !rel.startsWith("..") && !path3.isAbsolute(rel);
403
616
  };
404
617
  const ignoredOutDirs = new Set(computeGeneratorOutputDirs(cfg).map(abs));
405
618
  const currentTargets = new Set(computeWatchTargets(cfg).map(abs));
@@ -478,7 +691,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
478
691
  })
479
692
  );
480
693
  } else {
481
- console.log(import_chalk.default.green("Analyze complete."));
694
+ console.log(import_chalk2.default.green("Analyze complete."));
482
695
  }
483
696
  return;
484
697
  }
@@ -497,11 +710,12 @@ program.command("watch").description("Watch schema and regenerate on changes").o
497
710
  outputHeader: g.outputHeader,
498
711
  format: g.format,
499
712
  templateOptions: g.templateOptions,
713
+ importExtension: g.importExtension,
500
714
  validation: g.validation
501
715
  });
502
716
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
503
- import_chalk.default.green(`Generated (${g.kind}):`),
504
- files.map((f) => import_chalk.default.cyan(f)).join(", ")
717
+ import_chalk2.default.green(`Generated (${g.kind}):`),
718
+ files.map((f) => import_chalk2.default.cyan(f)).join(", ")
505
719
  );
506
720
  newFiles.push(...files);
507
721
  } else if (g.kind === "service") {
@@ -515,19 +729,20 @@ program.command("watch").description("Watch schema and regenerate on changes").o
515
729
  format: g.format,
516
730
  dataAccess: g.dataAccess,
517
731
  dbImportPath: g.dbImportPath,
518
- schemaImportPath: g.schemaImportPath
732
+ schemaImportPath: g.schemaImportPath,
733
+ importExtension: g.importExtension
519
734
  });
520
735
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
521
- import_chalk.default.green(`Generated (service): ${files.length} files`),
522
- files.map((f) => import_chalk.default.cyan(f)).join(", ")
736
+ import_chalk2.default.green(`Generated (service): ${files.length} files`),
737
+ files.map((f) => import_chalk2.default.cyan(f)).join(", ")
523
738
  );
524
739
  newFiles.push(...files);
525
740
  } catch (e) {
526
741
  console.error(
527
- import_chalk.default.red("Service generator missing."),
528
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-service")
742
+ import_chalk2.default.red("Service generator missing."),
743
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-service")
529
744
  );
530
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
745
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
531
746
  return;
532
747
  }
533
748
  } else if (g.kind === "zod") {
@@ -540,19 +755,21 @@ program.command("watch").description("Watch schema and regenerate on changes").o
540
755
  outputHeader: g.outputHeader,
541
756
  format: g.format,
542
757
  schemaSuffix: g.schemaSuffix,
543
- fileSuffix: g.fileSuffix
758
+ fileSuffix: g.fileSuffix,
759
+ importExtension: g.importExtension,
760
+ affix: g.affix
544
761
  });
545
762
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
546
- import_chalk.default.green(`Generated (zod): ${files.length} files`),
547
- files.map((f) => import_chalk.default.cyan(f)).join(", ")
763
+ import_chalk2.default.green(`Generated (zod): ${files.length} files`),
764
+ files.map((f) => import_chalk2.default.cyan(f)).join(", ")
548
765
  );
549
766
  newFiles.push(...files);
550
767
  } catch (e) {
551
768
  console.error(
552
- import_chalk.default.red("Zod generator missing."),
553
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-zod")
769
+ import_chalk2.default.red("Zod generator missing."),
770
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-zod")
554
771
  );
555
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
772
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
556
773
  return;
557
774
  }
558
775
  } else if (g.kind === "valibot") {
@@ -565,19 +782,21 @@ program.command("watch").description("Watch schema and regenerate on changes").o
565
782
  outputHeader: g.outputHeader,
566
783
  format: g.format,
567
784
  schemaSuffix: g.schemaSuffix,
568
- fileSuffix: g.fileSuffix
785
+ fileSuffix: g.fileSuffix,
786
+ importExtension: g.importExtension,
787
+ affix: g.affix
569
788
  });
570
789
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
571
- import_chalk.default.green(`Generated (valibot): ${files.length} files`),
572
- files.map((f) => import_chalk.default.cyan(f)).join(", ")
790
+ import_chalk2.default.green(`Generated (valibot): ${files.length} files`),
791
+ files.map((f) => import_chalk2.default.cyan(f)).join(", ")
573
792
  );
574
793
  newFiles.push(...files);
575
794
  } catch (e) {
576
795
  console.error(
577
- import_chalk.default.red("Valibot generator missing."),
578
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-valibot")
796
+ import_chalk2.default.red("Valibot generator missing."),
797
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-valibot")
579
798
  );
580
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
799
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
581
800
  return;
582
801
  }
583
802
  } else if (g.kind === "arktype") {
@@ -590,19 +809,21 @@ program.command("watch").description("Watch schema and regenerate on changes").o
590
809
  outputHeader: g.outputHeader,
591
810
  format: g.format,
592
811
  schemaSuffix: g.schemaSuffix,
593
- fileSuffix: g.fileSuffix
812
+ fileSuffix: g.fileSuffix,
813
+ importExtension: g.importExtension,
814
+ affix: g.affix
594
815
  });
595
816
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
596
- import_chalk.default.green(`Generated (arktype): ${files.length} files`),
597
- files.map((f) => import_chalk.default.cyan(f)).join(", ")
817
+ import_chalk2.default.green(`Generated (arktype): ${files.length} files`),
818
+ files.map((f) => import_chalk2.default.cyan(f)).join(", ")
598
819
  );
599
820
  newFiles.push(...files);
600
821
  } catch (e) {
601
822
  console.error(
602
- import_chalk.default.red("ArkType generator missing."),
603
- import_chalk.default.yellow("\nInstall with: npm install @drzl/generator-arktype")
823
+ import_chalk2.default.red("ArkType generator missing."),
824
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-arktype")
604
825
  );
605
- console.error(import_chalk.default.gray("Error details:"), e?.message ?? e);
826
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
606
827
  return;
607
828
  }
608
829
  }
@@ -610,12 +831,16 @@ program.command("watch").description("Watch schema and regenerate on changes").o
610
831
  const added = newFiles.filter((f) => !lastFiles.includes(f));
611
832
  const removed = lastFiles.filter((f) => !newFiles.includes(f));
612
833
  opts.json ? console.log(JSON.stringify({ event: "diff", added, removed })) : (() => {
613
- if (added.length) console.log(import_chalk.default.blue(`Added: ${added.join(", ")}`));
614
- if (removed.length) console.log(import_chalk.default.yellow(`Removed: ${removed.join(", ")}`));
834
+ if (added.length) console.log(import_chalk2.default.blue(`Added: ${added.join(", ")}`));
835
+ if (removed.length) console.log(import_chalk2.default.yellow(`Removed: ${removed.join(", ")}`));
615
836
  })();
837
+ if (newFiles.length && !opts.json) {
838
+ const reason = opts.pipeline && opts.pipeline !== "all" ? `watch:${opts.pipeline}` : "watch";
839
+ maybeShowSponsorMessage({ reason });
840
+ }
616
841
  lastFiles = newFiles;
617
842
  } catch (e) {
618
- opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(import_chalk.default.red("Watch pipeline failed:"), e?.message ?? e);
843
+ opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(import_chalk2.default.red("Watch pipeline failed:"), e?.message ?? e);
619
844
  }
620
845
  };
621
846
  const debounced = Number(opts.debounce) || 200;
@@ -640,18 +865,18 @@ program.command("watch").description("Watch schema and regenerate on changes").o
640
865
  );
641
866
  } else {
642
867
  console.log(
643
- import_chalk.default.gray(
644
- "Watching:\n " + Array.from(currentTargets).map((p) => path2.relative(process.cwd(), p)).join("\n ")
868
+ import_chalk2.default.gray(
869
+ "Watching:\n " + Array.from(currentTargets).map((p) => path3.relative(process.cwd(), p)).join("\n ")
645
870
  )
646
871
  );
647
872
  }
648
- watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(import_chalk.default.red("Watcher error:"), err));
873
+ watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(import_chalk2.default.red("Watcher error:"), err));
649
874
  await run();
650
875
  });
651
876
  program.command("init").description("Scaffold a drzl.config.ts").option("-y, --yes", "accept defaults").action(async (_opts) => {
652
877
  const fs2 = await import("fs/promises");
653
- const path3 = await import("path");
654
- const target = path3.resolve(process.cwd(), "drzl.config.ts");
878
+ const path4 = await import("path");
879
+ const target = path4.resolve(process.cwd(), "drzl.config.ts");
655
880
  const template = `export default {
656
881
  schema: 'src/db/schema.ts',
657
882
  outDir: 'src/api',
@@ -663,9 +888,9 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
663
888
  `;
664
889
  try {
665
890
  await fs2.writeFile(target, template, { flag: "wx" });
666
- console.log(import_chalk.default.green(`Created ${target}`));
891
+ console.log(import_chalk2.default.green(`Created ${target}`));
667
892
  } catch (e) {
668
- console.error(import_chalk.default.red("Init failed:"), e?.message ?? e);
893
+ console.error(import_chalk2.default.red("Init failed:"), e?.message ?? e);
669
894
  process.exit(1);
670
895
  }
671
896
  });