@billsdk/cli 0.1.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.
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,662 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command as Command3 } from "commander";
5
+
6
+ // src/commands/generate.ts
7
+ import fs from "fs/promises";
8
+ import path2 from "path";
9
+ import * as p from "@clack/prompts";
10
+ import chalk from "chalk";
11
+ import { Command } from "commander";
12
+
13
+ // src/generators/drizzle.ts
14
+ import * as prettier from "prettier";
15
+ function toSnakeCase(str) {
16
+ return str.replace(/([A-Z])/g, "_$1").toLowerCase();
17
+ }
18
+ function getColumnType(field, provider) {
19
+ const { type } = field;
20
+ switch (type) {
21
+ case "string":
22
+ if (provider === "pg") return "text";
23
+ if (provider === "mysql") return "varchar";
24
+ return "text";
25
+ case "number":
26
+ return "integer";
27
+ case "boolean":
28
+ if (provider === "sqlite") return "integer";
29
+ return "boolean";
30
+ case "date":
31
+ if (provider === "pg") return "timestamp";
32
+ if (provider === "mysql") return "datetime";
33
+ return "integer";
34
+ case "json":
35
+ if (provider === "pg") return "jsonb";
36
+ if (provider === "mysql") return "json";
37
+ return "text";
38
+ case "string[]":
39
+ if (provider === "pg") return "text";
40
+ return "text";
41
+ case "number[]":
42
+ if (provider === "pg") return "integer";
43
+ return "text";
44
+ default:
45
+ return "text";
46
+ }
47
+ }
48
+ function getProviderImport(provider) {
49
+ switch (provider) {
50
+ case "pg":
51
+ return { importPath: "drizzle-orm/pg-core", tableFunction: "pgTable" };
52
+ case "mysql":
53
+ return {
54
+ importPath: "drizzle-orm/mysql-core",
55
+ tableFunction: "mysqlTable"
56
+ };
57
+ case "sqlite":
58
+ return {
59
+ importPath: "drizzle-orm/sqlite-core",
60
+ tableFunction: "sqliteTable"
61
+ };
62
+ }
63
+ }
64
+ function getColumnDefinition(fieldName, field, provider, _schema) {
65
+ const columnType = getColumnType(field, provider);
66
+ const columnName = toSnakeCase(fieldName);
67
+ const parts = [];
68
+ if (provider === "mysql" && columnType === "varchar") {
69
+ parts.push(`${fieldName}: ${columnType}("${columnName}", { length: 255 })`);
70
+ } else {
71
+ parts.push(`${fieldName}: ${columnType}("${columnName}")`);
72
+ }
73
+ if (field.primaryKey) {
74
+ parts.push(".primaryKey()");
75
+ }
76
+ if (field.unique) {
77
+ parts.push(".unique()");
78
+ }
79
+ if (field.references) {
80
+ const refTable = field.references.model;
81
+ const onDelete = field.references.onDelete === "cascade" ? ', { onDelete: "cascade" }' : "";
82
+ parts.push(
83
+ `.references(() => ${refTable}.${field.references.field}${onDelete})`
84
+ );
85
+ }
86
+ if (field.defaultValue !== void 0) {
87
+ if (typeof field.defaultValue === "function") {
88
+ const fnString = field.defaultValue.toString();
89
+ if (fnString.includes("randomUUID") || fnString.includes("crypto")) {
90
+ parts.push(".$defaultFn(() => crypto.randomUUID())");
91
+ } else if (fnString.includes("new Date")) {
92
+ parts.push(".defaultNow()");
93
+ }
94
+ } else if (typeof field.defaultValue === "string") {
95
+ parts.push(`.default("${field.defaultValue}")`);
96
+ } else if (typeof field.defaultValue === "number") {
97
+ parts.push(`.default(${field.defaultValue})`);
98
+ } else if (typeof field.defaultValue === "boolean") {
99
+ parts.push(
100
+ `.default(${provider === "sqlite" ? field.defaultValue ? 1 : 0 : field.defaultValue})`
101
+ );
102
+ }
103
+ }
104
+ if (field.required !== false && !field.primaryKey) {
105
+ parts.push(".notNull()");
106
+ }
107
+ return parts.join("");
108
+ }
109
+ function generateTableDefinition(tableName, table, provider, tableFunction, schema) {
110
+ const columns = [];
111
+ for (const [fieldName, field] of Object.entries(table.fields)) {
112
+ columns.push(getColumnDefinition(fieldName, field, provider, schema));
113
+ }
114
+ return `export const ${tableName} = ${tableFunction}("${tableName}", {
115
+ ${columns.join(",\n ")},
116
+ });`;
117
+ }
118
+ function generateRelations(schema) {
119
+ const result = [];
120
+ for (const [tableName, table] of Object.entries(schema)) {
121
+ const oneRels = [];
122
+ const manyRels = [];
123
+ for (const [fieldName, field] of Object.entries(table.fields)) {
124
+ if (field.references) {
125
+ const refTable = field.references.model;
126
+ oneRels.push(`${refTable}: one(${refTable}, {
127
+ fields: [${tableName}.${fieldName}],
128
+ references: [${refTable}.${field.references.field}],
129
+ })`);
130
+ }
131
+ }
132
+ for (const [otherTable, otherSchema] of Object.entries(schema)) {
133
+ if (otherTable === tableName) continue;
134
+ for (const field of Object.values(otherSchema.fields)) {
135
+ if (field.references?.model === tableName) {
136
+ manyRels.push(`${otherTable}s: many(${otherTable})`);
137
+ }
138
+ }
139
+ }
140
+ const allRels = [...oneRels, ...manyRels];
141
+ if (allRels.length > 0) {
142
+ const helpers = [];
143
+ if (oneRels.length > 0) helpers.push("one");
144
+ if (manyRels.length > 0) helpers.push("many");
145
+ result.push(`export const ${tableName}Relations = relations(${tableName}, ({ ${helpers.join(", ")} }) => ({
146
+ ${allRels.join(",\n ")},
147
+ }));`);
148
+ }
149
+ }
150
+ return result;
151
+ }
152
+ function collectColumnTypes(schema, provider) {
153
+ const types = /* @__PURE__ */ new Set();
154
+ for (const table of Object.values(schema)) {
155
+ for (const field of Object.values(table.fields)) {
156
+ types.add(getColumnType(field, provider));
157
+ }
158
+ }
159
+ return types;
160
+ }
161
+ async function generateDrizzleSchema(options) {
162
+ const { schema, provider } = options;
163
+ const { importPath, tableFunction } = getProviderImport(provider);
164
+ const columnTypes = collectColumnTypes(schema, provider);
165
+ const coreImports = [tableFunction, ...Array.from(columnTypes)].join(", ");
166
+ const imports = [
167
+ `import { ${coreImports} } from "${importPath}";`,
168
+ `import { relations } from "drizzle-orm";`
169
+ ];
170
+ const tables = [];
171
+ for (const [tableName, table] of Object.entries(schema)) {
172
+ tables.push(
173
+ generateTableDefinition(
174
+ tableName,
175
+ table,
176
+ provider,
177
+ tableFunction,
178
+ schema
179
+ )
180
+ );
181
+ }
182
+ const rels = generateRelations(schema);
183
+ const code = `${imports.join("\n")}
184
+
185
+ ${tables.join("\n\n")}
186
+
187
+ ${rels.join("\n\n")}
188
+ `;
189
+ const formatted = await prettier.format(code, {
190
+ parser: "typescript",
191
+ semi: true,
192
+ singleQuote: false,
193
+ tabWidth: 2,
194
+ trailingComma: "all"
195
+ });
196
+ return {
197
+ code: formatted,
198
+ fileName: options.output || "billing-schema.ts"
199
+ };
200
+ }
201
+
202
+ // src/generators/index.ts
203
+ var generators = {
204
+ drizzle: async (opts) => {
205
+ const provider = opts.provider || "pg";
206
+ return generateDrizzleSchema({
207
+ schema: opts.schema,
208
+ provider,
209
+ output: opts.output
210
+ });
211
+ }
212
+ // Future: add more generators
213
+ // prisma: generatePrismaSchema,
214
+ // kysely: generateKyselySchema,
215
+ };
216
+ async function generateSchema(options) {
217
+ const generator = generators[options.adapterId];
218
+ if (!generator) {
219
+ throw new Error(
220
+ `No schema generator found for adapter "${options.adapterId}".
221
+ Available generators: ${Object.keys(generators).join(", ")}`
222
+ );
223
+ }
224
+ return generator(options);
225
+ }
226
+ function getSupportedAdapters() {
227
+ return Object.keys(generators);
228
+ }
229
+
230
+ // src/utils/get-config.ts
231
+ import path from "path";
232
+ import { createJiti } from "jiti";
233
+ var CONFIG_FILES = [
234
+ "billing.ts",
235
+ "billing.js",
236
+ "src/billing.ts",
237
+ "src/billing.js",
238
+ "lib/billing.ts",
239
+ "lib/billing.js"
240
+ ];
241
+ async function findConfigFile(cwd) {
242
+ const fs3 = await import("fs/promises");
243
+ for (const file of CONFIG_FILES) {
244
+ const configPath = path.join(cwd, file);
245
+ try {
246
+ await fs3.access(configPath);
247
+ return configPath;
248
+ } catch {
249
+ }
250
+ }
251
+ return null;
252
+ }
253
+ async function loadConfig(configPath) {
254
+ const jiti = createJiti(import.meta.url, {
255
+ interopDefault: true,
256
+ moduleCache: false,
257
+ fsCache: false
258
+ });
259
+ try {
260
+ const module = await jiti.import(configPath);
261
+ const config = module.billing || module.default || module;
262
+ return {
263
+ config,
264
+ configPath
265
+ };
266
+ } catch (error) {
267
+ throw new Error(
268
+ `Failed to load config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`
269
+ );
270
+ }
271
+ }
272
+ async function getConfig(configPath, cwd = process.cwd()) {
273
+ let resolvedPath;
274
+ if (configPath) {
275
+ resolvedPath = path.isAbsolute(configPath) ? configPath : path.join(cwd, configPath);
276
+ } else {
277
+ const found = await findConfigFile(cwd);
278
+ if (!found) {
279
+ throw new Error(
280
+ "Config file not found. Run:\n\n npx @billsdk/cli init\n"
281
+ );
282
+ }
283
+ resolvedPath = found;
284
+ }
285
+ return loadConfig(resolvedPath);
286
+ }
287
+
288
+ // src/utils/get-schema.ts
289
+ import { billingSchema } from "@billsdk/core";
290
+ function getMergedSchema(config) {
291
+ let schema = { ...billingSchema };
292
+ const cfg = config;
293
+ let plugins;
294
+ if (cfg.$context && typeof cfg.$context === "object") {
295
+ const ctx = cfg.$context;
296
+ plugins = ctx.plugins;
297
+ }
298
+ if (!plugins && Array.isArray(cfg.plugins)) {
299
+ plugins = cfg.plugins;
300
+ }
301
+ if (!plugins && cfg.options && typeof cfg.options === "object") {
302
+ const opts = cfg.options;
303
+ plugins = opts.plugins;
304
+ }
305
+ if (plugins) {
306
+ for (const plugin of plugins) {
307
+ if (plugin.schema) {
308
+ schema = { ...schema, ...plugin.schema };
309
+ }
310
+ }
311
+ }
312
+ return schema;
313
+ }
314
+ function getAdapterInfo(config) {
315
+ const cfg = config;
316
+ if (cfg.$context && typeof cfg.$context === "object") {
317
+ const ctx = cfg.$context;
318
+ if (ctx.database?.id) {
319
+ return {
320
+ adapterId: ctx.database.id
321
+ };
322
+ }
323
+ }
324
+ if (cfg.database) {
325
+ const db = cfg.database;
326
+ if (typeof db === "function") {
327
+ try {
328
+ const adapter = db({});
329
+ return {
330
+ adapterId: adapter.id
331
+ };
332
+ } catch {
333
+ }
334
+ }
335
+ if (db.id) {
336
+ return {
337
+ adapterId: db.id,
338
+ provider: db.options?.provider
339
+ };
340
+ }
341
+ }
342
+ if (cfg.options && typeof cfg.options === "object") {
343
+ const opts = cfg.options;
344
+ if (opts.database?.id) {
345
+ return {
346
+ adapterId: opts.database.id
347
+ };
348
+ }
349
+ }
350
+ return null;
351
+ }
352
+
353
+ // src/commands/generate.ts
354
+ var generateCommand = new Command("generate").description("Generate database schema from your billing configuration").option("-c, --config <path>", "Path to billing config file").option("-o, --output <path>", "Output file path", "billing-schema.ts").option(
355
+ "-p, --provider <provider>",
356
+ "Database provider (pg, mysql, sqlite)",
357
+ "pg"
358
+ ).option("-y, --yes", "Skip confirmation prompts", false).action(async (options) => {
359
+ const cwd = process.cwd();
360
+ p.intro(chalk.cyan("@billsdk/cli generate"));
361
+ const spinner3 = p.spinner();
362
+ try {
363
+ spinner3.start("Loading billing configuration\u2026");
364
+ const { config, configPath } = await getConfig(options.config, cwd);
365
+ spinner3.stop(
366
+ chalk.green("\u2713") + ` Found ${chalk.dim(path2.relative(cwd, configPath))}`
367
+ );
368
+ const adapterInfo = getAdapterInfo(config);
369
+ const adapterId = adapterInfo?.adapterId ?? "drizzle";
370
+ const provider = options.provider || adapterInfo?.provider || "pg";
371
+ if (!adapterInfo) {
372
+ p.log.warn(
373
+ `Could not detect adapter from config. Using default: ${adapterId} with ${provider}`
374
+ );
375
+ }
376
+ const supportedAdapters = getSupportedAdapters();
377
+ if (!supportedAdapters.includes(adapterId)) {
378
+ p.log.error(
379
+ `Adapter "${adapterId}" is not supported for schema generation.
380
+ Supported adapters: ${supportedAdapters.join(", ")}`
381
+ );
382
+ process.exit(1);
383
+ }
384
+ p.log.info(
385
+ `Detected adapter: ${chalk.cyan(adapterId)}, provider: ${chalk.cyan(provider)}`
386
+ );
387
+ spinner3.start("Analyzing schema\u2026");
388
+ const schema = getMergedSchema(config);
389
+ const tableCount = Object.keys(schema).length;
390
+ spinner3.stop(`${chalk.green("\u2713")} Found ${tableCount} tables`);
391
+ const outputPath = path2.isAbsolute(options.output) ? options.output : path2.join(cwd, options.output);
392
+ try {
393
+ await fs.access(outputPath);
394
+ if (!options.yes) {
395
+ const overwrite = await p.confirm({
396
+ message: `File ${chalk.dim(options.output)} already exists. Overwrite?`,
397
+ initialValue: true
398
+ });
399
+ if (p.isCancel(overwrite) || !overwrite) {
400
+ p.log.warn("Generation cancelled.");
401
+ process.exit(0);
402
+ }
403
+ }
404
+ } catch {
405
+ }
406
+ spinner3.start("Generating schema\u2026");
407
+ const result = await generateSchema({
408
+ schema,
409
+ adapterId,
410
+ provider,
411
+ output: options.output
412
+ });
413
+ spinner3.stop(`${chalk.green("\u2713")} Schema generated`);
414
+ spinner3.start("Writing file\u2026");
415
+ await fs.mkdir(path2.dirname(outputPath), { recursive: true });
416
+ await fs.writeFile(outputPath, result.code, "utf-8");
417
+ spinner3.stop(
418
+ `${chalk.green("\u2713")} Written to ${chalk.dim(options.output)}`
419
+ );
420
+ p.log.success(
421
+ `Generated ${chalk.cyan(result.fileName)} with ${tableCount} tables`
422
+ );
423
+ p.note(
424
+ "Run migrations:\n" + chalk.dim(" npx drizzle-kit generate\n") + chalk.dim(" npx drizzle-kit migrate"),
425
+ "Next steps"
426
+ );
427
+ p.outro(chalk.green("Done!"));
428
+ } catch (error) {
429
+ spinner3.stop(`${chalk.red("\u2717")} Failed`);
430
+ p.log.error(error instanceof Error ? error.message : String(error));
431
+ process.exit(1);
432
+ }
433
+ });
434
+
435
+ // src/commands/init.ts
436
+ import fs2 from "fs/promises";
437
+ import path3 from "path";
438
+ import * as p2 from "@clack/prompts";
439
+ import chalk2 from "chalk";
440
+ import { Command as Command2 } from "commander";
441
+ import * as prettier2 from "prettier";
442
+ var initCommand = new Command2("init").description("Initialize BillSDK in your project").option("-y, --yes", "Skip confirmation prompts and use defaults", false).action(async (options) => {
443
+ const cwd = process.cwd();
444
+ p2.intro(chalk2.cyan("@billsdk/cli init"));
445
+ try {
446
+ const configPath = path3.join(cwd, "billing.ts");
447
+ try {
448
+ await fs2.access(configPath);
449
+ p2.log.warn("billing.ts already exists. Skipping initialization.");
450
+ p2.outro(chalk2.yellow("Already initialized"));
451
+ return;
452
+ } catch {
453
+ }
454
+ let provider = "pg";
455
+ let adapter = "drizzle";
456
+ let installDeps = true;
457
+ if (!options.yes) {
458
+ const adapterChoice = await p2.select({
459
+ message: "Which database adapter do you want to use?",
460
+ options: [
461
+ { value: "drizzle", label: "Drizzle ORM", hint: "recommended" },
462
+ { value: "memory", label: "In-Memory", hint: "for testing" }
463
+ ]
464
+ });
465
+ if (p2.isCancel(adapterChoice)) {
466
+ p2.log.warn("Initialization cancelled.");
467
+ process.exit(0);
468
+ }
469
+ adapter = adapterChoice;
470
+ if (adapter === "drizzle") {
471
+ const providerChoice = await p2.select({
472
+ message: "Which database provider?",
473
+ options: [
474
+ { value: "pg", label: "PostgreSQL", hint: "recommended" },
475
+ { value: "mysql", label: "MySQL" },
476
+ { value: "sqlite", label: "SQLite" }
477
+ ]
478
+ });
479
+ if (p2.isCancel(providerChoice)) {
480
+ p2.log.warn("Initialization cancelled.");
481
+ process.exit(0);
482
+ }
483
+ provider = providerChoice;
484
+ }
485
+ const shouldInstall = await p2.confirm({
486
+ message: "Install dependencies?",
487
+ initialValue: true
488
+ });
489
+ if (p2.isCancel(shouldInstall)) {
490
+ p2.log.warn("Initialization cancelled.");
491
+ process.exit(0);
492
+ }
493
+ installDeps = shouldInstall;
494
+ }
495
+ const spinner3 = p2.spinner();
496
+ const configContent = generateConfigContent(adapter, provider);
497
+ spinner3.start("Creating billing.ts\u2026");
498
+ const formatted = await prettier2.format(configContent, {
499
+ parser: "typescript",
500
+ semi: true,
501
+ singleQuote: false,
502
+ tabWidth: 2
503
+ });
504
+ await fs2.writeFile(configPath, formatted, "utf-8");
505
+ spinner3.stop(`${chalk2.green("\u2713")} Created billing.ts`);
506
+ if (installDeps) {
507
+ spinner3.start("Installing dependencies\u2026");
508
+ const deps = getDependencies(adapter, provider);
509
+ const packageManager = await detectPackageManager(cwd);
510
+ try {
511
+ const { execSync } = await import("child_process");
512
+ const installCmd = getInstallCommand(packageManager, deps);
513
+ execSync(installCmd, { cwd, stdio: "pipe" });
514
+ spinner3.stop(`${chalk2.green("\u2713")} Installed dependencies`);
515
+ } catch (_error) {
516
+ spinner3.stop(`${chalk2.yellow("\u26A0")} Failed to install dependencies`);
517
+ p2.log.warn(
518
+ `Install manually:
519
+ ${chalk2.dim(
520
+ ` ${packageManager} install ${deps.join(" ")}`
521
+ )}`
522
+ );
523
+ }
524
+ }
525
+ p2.log.success("BillSDK initialized!");
526
+ const nextSteps = [
527
+ "1. Update your database connection in billing.ts",
528
+ "2. Configure your plans",
529
+ "3. Run: npx @billsdk/cli generate",
530
+ "4. Run: npx drizzle-kit generate && npx drizzle-kit migrate"
531
+ ];
532
+ p2.note(nextSteps.join("\n"), "Next steps");
533
+ p2.outro(chalk2.green("Done!"));
534
+ } catch (error) {
535
+ p2.log.error(error instanceof Error ? error.message : String(error));
536
+ process.exit(1);
537
+ }
538
+ });
539
+ function generateConfigContent(adapter, provider) {
540
+ if (adapter === "memory") {
541
+ return `import { billsdk, memoryAdapter } from "billsdk";
542
+
543
+ export const billing = billsdk({
544
+ database: memoryAdapter(),
545
+ plans: [
546
+ {
547
+ code: "free",
548
+ name: "Free",
549
+ description: "Get started for free",
550
+ price: { monthly: 0, yearly: 0 },
551
+ features: {
552
+ projects: { type: "limit", value: 3 },
553
+ },
554
+ },
555
+ {
556
+ code: "pro",
557
+ name: "Pro",
558
+ description: "For growing teams",
559
+ price: { monthly: 1900, yearly: 19000 }, // in cents
560
+ features: {
561
+ projects: { type: "limit", value: 100 },
562
+ analytics: { type: "boolean", value: true },
563
+ },
564
+ },
565
+ ],
566
+ });
567
+ `;
568
+ }
569
+ return `import { billsdk } from "billsdk";
570
+ import { drizzleAdapter } from "@billsdk/drizzle-adapter";
571
+ import { db } from "./db"; // Your Drizzle DB instance
572
+ import * as schema from "./billing-schema"; // Generated by CLI
573
+
574
+ export const billing = billsdk({
575
+ database: drizzleAdapter(db, {
576
+ schema,
577
+ provider: "${provider}",
578
+ }),
579
+ plans: [
580
+ {
581
+ code: "free",
582
+ name: "Free",
583
+ description: "Get started for free",
584
+ price: { monthly: 0, yearly: 0 },
585
+ features: {
586
+ projects: { type: "limit", value: 3 },
587
+ },
588
+ },
589
+ {
590
+ code: "pro",
591
+ name: "Pro",
592
+ description: "For growing teams",
593
+ price: { monthly: 1900, yearly: 19000 }, // in cents
594
+ features: {
595
+ projects: { type: "limit", value: 100 },
596
+ analytics: { type: "boolean", value: true },
597
+ },
598
+ },
599
+ ],
600
+ });
601
+ `;
602
+ }
603
+ function getDependencies(adapter, provider) {
604
+ const deps = ["billsdk"];
605
+ if (adapter === "drizzle") {
606
+ deps.push("@billsdk/drizzle-adapter", "drizzle-orm", "drizzle-kit");
607
+ switch (provider) {
608
+ case "pg":
609
+ deps.push("postgres");
610
+ break;
611
+ case "mysql":
612
+ deps.push("mysql2");
613
+ break;
614
+ case "sqlite":
615
+ deps.push("better-sqlite3");
616
+ break;
617
+ }
618
+ } else if (adapter === "memory") {
619
+ deps.push("@billsdk/memory-adapter");
620
+ }
621
+ return deps;
622
+ }
623
+ async function detectPackageManager(cwd) {
624
+ try {
625
+ await fs2.access(path3.join(cwd, "pnpm-lock.yaml"));
626
+ return "pnpm";
627
+ } catch {
628
+ }
629
+ try {
630
+ await fs2.access(path3.join(cwd, "yarn.lock"));
631
+ return "yarn";
632
+ } catch {
633
+ }
634
+ try {
635
+ await fs2.access(path3.join(cwd, "bun.lockb"));
636
+ return "bun";
637
+ } catch {
638
+ }
639
+ return "npm";
640
+ }
641
+ function getInstallCommand(packageManager, deps) {
642
+ switch (packageManager) {
643
+ case "pnpm":
644
+ return `pnpm add ${deps.join(" ")}`;
645
+ case "yarn":
646
+ return `yarn add ${deps.join(" ")}`;
647
+ case "bun":
648
+ return `bun add ${deps.join(" ")}`;
649
+ default:
650
+ return `npm install ${deps.join(" ")}`;
651
+ }
652
+ }
653
+
654
+ // src/index.ts
655
+ var program = new Command3();
656
+ program.name("@billsdk/cli").description(
657
+ "CLI for BillSDK - Generate schemas and manage billing configuration"
658
+ ).version("0.1.0");
659
+ program.addCommand(generateCommand);
660
+ program.addCommand(initCommand);
661
+ program.parse();
662
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/generate.ts","../src/generators/drizzle.ts","../src/generators/index.ts","../src/utils/get-config.ts","../src/utils/get-schema.ts","../src/commands/init.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { generateCommand } from \"./commands/generate\";\nimport { initCommand } from \"./commands/init\";\n\nconst program = new Command();\n\nprogram\n .name(\"@billsdk/cli\")\n .description(\n \"CLI for BillSDK - Generate schemas and manage billing configuration\",\n )\n .version(\"0.1.0\");\n\n// Add commands\nprogram.addCommand(generateCommand);\nprogram.addCommand(initCommand);\n\n// Parse command line arguments\nprogram.parse();\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { generateSchema, getSupportedAdapters } from \"../generators\";\nimport { getAdapterInfo, getConfig, getMergedSchema } from \"../utils\";\n\nexport const generateCommand = new Command(\"generate\")\n .description(\"Generate database schema from your billing configuration\")\n .option(\"-c, --config <path>\", \"Path to billing config file\")\n .option(\"-o, --output <path>\", \"Output file path\", \"billing-schema.ts\")\n .option(\n \"-p, --provider <provider>\",\n \"Database provider (pg, mysql, sqlite)\",\n \"pg\",\n )\n .option(\"-y, --yes\", \"Skip confirmation prompts\", false)\n .action(async (options) => {\n const cwd = process.cwd();\n\n p.intro(chalk.cyan(\"@billsdk/cli generate\"));\n\n const spinner = p.spinner();\n\n try {\n // Load config\n spinner.start(\"Loading billing configuration…\");\n const { config, configPath } = await getConfig(options.config, cwd);\n spinner.stop(\n chalk.green(\"✓\") +\n ` Found ${chalk.dim(path.relative(cwd, configPath))}`,\n );\n\n // Get adapter info (or use defaults)\n const adapterInfo = getAdapterInfo(config);\n\n // Default to drizzle if adapter couldn't be detected\n const adapterId = adapterInfo?.adapterId ?? \"drizzle\";\n const provider = options.provider || adapterInfo?.provider || \"pg\";\n\n if (!adapterInfo) {\n p.log.warn(\n `Could not detect adapter from config. Using default: ${adapterId} with ${provider}`,\n );\n }\n\n // Check if adapter is supported\n const supportedAdapters = getSupportedAdapters();\n if (!supportedAdapters.includes(adapterId)) {\n p.log.error(\n `Adapter \"${adapterId}\" is not supported for schema generation.\\n` +\n `Supported adapters: ${supportedAdapters.join(\", \")}`,\n );\n process.exit(1);\n }\n\n p.log.info(\n `Detected adapter: ${chalk.cyan(adapterId)}, provider: ${chalk.cyan(provider)}`,\n );\n\n // Get merged schema\n spinner.start(\"Analyzing schema…\");\n const schema = getMergedSchema(config);\n const tableCount = Object.keys(schema).length;\n spinner.stop(`${chalk.green(\"✓\")} Found ${tableCount} tables`);\n\n // Check for existing file\n const outputPath = path.isAbsolute(options.output)\n ? options.output\n : path.join(cwd, options.output);\n\n try {\n await fs.access(outputPath);\n // File exists - ask for confirmation unless --yes flag\n if (!options.yes) {\n const overwrite = await p.confirm({\n message: `File ${chalk.dim(options.output)} already exists. Overwrite?`,\n initialValue: true,\n });\n\n if (p.isCancel(overwrite) || !overwrite) {\n p.log.warn(\"Generation cancelled.\");\n process.exit(0);\n }\n }\n } catch {\n // File doesn't exist, continue\n }\n\n // Generate schema\n spinner.start(\"Generating schema…\");\n const result = await generateSchema({\n schema,\n adapterId,\n provider,\n output: options.output,\n });\n spinner.stop(`${chalk.green(\"✓\")} Schema generated`);\n\n // Write file\n spinner.start(\"Writing file…\");\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, result.code, \"utf-8\");\n spinner.stop(\n `${chalk.green(\"✓\")} Written to ${chalk.dim(options.output)}`,\n );\n\n // Success message\n p.log.success(\n `Generated ${chalk.cyan(result.fileName)} with ${tableCount} tables`,\n );\n\n // Next steps\n p.note(\n \"Run migrations:\\n\" +\n chalk.dim(\" npx drizzle-kit generate\\n\") +\n chalk.dim(\" npx drizzle-kit migrate\"),\n \"Next steps\",\n );\n\n p.outro(chalk.green(\"Done!\"));\n } catch (error) {\n spinner.stop(`${chalk.red(\"✗\")} Failed`);\n p.log.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n","import type { DBFieldAttribute, DBSchema, DBTableSchema } from \"@billsdk/core\";\nimport * as prettier from \"prettier\";\n\nexport interface DrizzleGeneratorOptions {\n schema: DBSchema;\n provider: \"pg\" | \"mysql\" | \"sqlite\";\n output?: string;\n}\n\n/**\n * Convert camelCase to snake_case\n */\nfunction toSnakeCase(str: string): string {\n return str.replace(/([A-Z])/g, \"_$1\").toLowerCase();\n}\n\n/**\n * Map BillSDK field types to Drizzle column types\n */\nfunction getColumnType(\n field: DBFieldAttribute,\n provider: \"pg\" | \"mysql\" | \"sqlite\",\n): string {\n const { type } = field;\n\n switch (type) {\n case \"string\":\n if (provider === \"pg\") return \"text\";\n if (provider === \"mysql\") return \"varchar\";\n return \"text\";\n case \"number\":\n return \"integer\";\n case \"boolean\":\n if (provider === \"sqlite\") return \"integer\";\n return \"boolean\";\n case \"date\":\n if (provider === \"pg\") return \"timestamp\";\n if (provider === \"mysql\") return \"datetime\";\n return \"integer\";\n case \"json\":\n if (provider === \"pg\") return \"jsonb\";\n if (provider === \"mysql\") return \"json\";\n return \"text\";\n case \"string[]\":\n if (provider === \"pg\") return \"text\";\n return \"text\";\n case \"number[]\":\n if (provider === \"pg\") return \"integer\";\n return \"text\";\n default:\n return \"text\";\n }\n}\n\nfunction getProviderImport(provider: \"pg\" | \"mysql\" | \"sqlite\"): {\n importPath: string;\n tableFunction: string;\n} {\n switch (provider) {\n case \"pg\":\n return { importPath: \"drizzle-orm/pg-core\", tableFunction: \"pgTable\" };\n case \"mysql\":\n return {\n importPath: \"drizzle-orm/mysql-core\",\n tableFunction: \"mysqlTable\",\n };\n case \"sqlite\":\n return {\n importPath: \"drizzle-orm/sqlite-core\",\n tableFunction: \"sqliteTable\",\n };\n }\n}\n\n/**\n * Generate column definition\n */\nfunction getColumnDefinition(\n fieldName: string,\n field: DBFieldAttribute,\n provider: \"pg\" | \"mysql\" | \"sqlite\",\n _schema: DBSchema,\n): string {\n const columnType = getColumnType(field, provider);\n const columnName = toSnakeCase(fieldName);\n const parts: string[] = [];\n\n // Column with name\n if (provider === \"mysql\" && columnType === \"varchar\") {\n parts.push(`${fieldName}: ${columnType}(\"${columnName}\", { length: 255 })`);\n } else {\n parts.push(`${fieldName}: ${columnType}(\"${columnName}\")`);\n }\n\n // Primary key\n if (field.primaryKey) {\n parts.push(\".primaryKey()\");\n }\n\n // Unique\n if (field.unique) {\n parts.push(\".unique()\");\n }\n\n // Foreign key reference (inline)\n if (field.references) {\n const refTable = field.references.model;\n const onDelete =\n field.references.onDelete === \"cascade\"\n ? ', { onDelete: \"cascade\" }'\n : \"\";\n parts.push(\n `.references(() => ${refTable}.${field.references.field}${onDelete})`,\n );\n }\n\n // Default value\n if (field.defaultValue !== undefined) {\n if (typeof field.defaultValue === \"function\") {\n const fnString = field.defaultValue.toString();\n if (fnString.includes(\"randomUUID\") || fnString.includes(\"crypto\")) {\n // For text IDs, use $defaultFn\n parts.push(\".$defaultFn(() => crypto.randomUUID())\");\n } else if (fnString.includes(\"new Date\")) {\n parts.push(\".defaultNow()\");\n }\n } else if (typeof field.defaultValue === \"string\") {\n parts.push(`.default(\"${field.defaultValue}\")`);\n } else if (typeof field.defaultValue === \"number\") {\n parts.push(`.default(${field.defaultValue})`);\n } else if (typeof field.defaultValue === \"boolean\") {\n parts.push(\n `.default(${provider === \"sqlite\" ? (field.defaultValue ? 1 : 0) : field.defaultValue})`,\n );\n }\n }\n\n // NotNull (after defaults, before references usually, but Drizzle is flexible)\n if (field.required !== false && !field.primaryKey) {\n parts.push(\".notNull()\");\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Generate table definition\n */\nfunction generateTableDefinition(\n tableName: string,\n table: DBTableSchema,\n provider: \"pg\" | \"mysql\" | \"sqlite\",\n tableFunction: string,\n schema: DBSchema,\n): string {\n const columns: string[] = [];\n\n for (const [fieldName, field] of Object.entries(table.fields)) {\n columns.push(getColumnDefinition(fieldName, field, provider, schema));\n }\n\n return `export const ${tableName} = ${tableFunction}(\"${tableName}\", {\n ${columns.join(\",\\n \")},\n});`;\n}\n\n/**\n * Generate relations\n */\nfunction generateRelations(schema: DBSchema): string[] {\n const result: string[] = [];\n\n for (const [tableName, table] of Object.entries(schema)) {\n const oneRels: string[] = [];\n const manyRels: string[] = [];\n\n // \"one\" relations (this table has FK to another)\n for (const [fieldName, field] of Object.entries(table.fields)) {\n if (field.references) {\n const refTable = field.references.model;\n oneRels.push(`${refTable}: one(${refTable}, {\n fields: [${tableName}.${fieldName}],\n references: [${refTable}.${field.references.field}],\n })`);\n }\n }\n\n // \"many\" relations (other tables have FK to this one)\n for (const [otherTable, otherSchema] of Object.entries(schema)) {\n if (otherTable === tableName) continue;\n for (const field of Object.values(otherSchema.fields)) {\n if (field.references?.model === tableName) {\n manyRels.push(`${otherTable}s: many(${otherTable})`);\n }\n }\n }\n\n const allRels = [...oneRels, ...manyRels];\n if (allRels.length > 0) {\n // Only include helpers that are actually used\n const helpers: string[] = [];\n if (oneRels.length > 0) helpers.push(\"one\");\n if (manyRels.length > 0) helpers.push(\"many\");\n\n result.push(`export const ${tableName}Relations = relations(${tableName}, ({ ${helpers.join(\", \")} }) => ({\n ${allRels.join(\",\\n \")},\n}));`);\n }\n }\n\n return result;\n}\n\n/**\n * Collect column types for imports\n */\nfunction collectColumnTypes(\n schema: DBSchema,\n provider: \"pg\" | \"mysql\" | \"sqlite\",\n): Set<string> {\n const types = new Set<string>();\n for (const table of Object.values(schema)) {\n for (const field of Object.values(table.fields)) {\n types.add(getColumnType(field, provider));\n }\n }\n return types;\n}\n\n/**\n * Generate Drizzle schema\n */\nexport async function generateDrizzleSchema(\n options: DrizzleGeneratorOptions,\n): Promise<{ code: string; fileName: string }> {\n const { schema, provider } = options;\n const { importPath, tableFunction } = getProviderImport(provider);\n const columnTypes = collectColumnTypes(schema, provider);\n\n // Imports\n const coreImports = [tableFunction, ...Array.from(columnTypes)].join(\", \");\n const imports = [\n `import { ${coreImports} } from \"${importPath}\";`,\n `import { relations } from \"drizzle-orm\";`,\n ];\n\n // Tables\n const tables: string[] = [];\n for (const [tableName, table] of Object.entries(schema)) {\n tables.push(\n generateTableDefinition(\n tableName,\n table,\n provider,\n tableFunction,\n schema,\n ),\n );\n }\n\n // Relations\n const rels = generateRelations(schema);\n\n // Combine (clean, no section comments)\n const code = `${imports.join(\"\\n\")}\n\n${tables.join(\"\\n\\n\")}\n\n${rels.join(\"\\n\\n\")}\n`;\n\n const formatted = await prettier.format(code, {\n parser: \"typescript\",\n semi: true,\n singleQuote: false,\n tabWidth: 2,\n trailingComma: \"all\",\n });\n\n return {\n code: formatted,\n fileName: options.output || \"billing-schema.ts\",\n };\n}\n","import type { DBSchema } from \"@billsdk/core\";\nimport { generateDrizzleSchema } from \"./drizzle\";\n\n/**\n * Options for schema generation\n */\nexport interface GenerateSchemaOptions {\n schema: DBSchema;\n adapterId: string;\n provider?: string;\n output?: string;\n}\n\n/**\n * Result of schema generation\n */\nexport interface GenerateSchemaResult {\n code: string;\n fileName: string;\n overwrite?: boolean;\n}\n\n/**\n * Map of adapter IDs to their generator functions\n */\nconst generators: Record<\n string,\n (options: GenerateSchemaOptions) => Promise<GenerateSchemaResult>\n> = {\n drizzle: async (opts) => {\n const provider = (opts.provider as \"pg\" | \"mysql\" | \"sqlite\") || \"pg\";\n return generateDrizzleSchema({\n schema: opts.schema,\n provider,\n output: opts.output,\n });\n },\n // Future: add more generators\n // prisma: generatePrismaSchema,\n // kysely: generateKyselySchema,\n};\n\n/**\n * Generate schema based on adapter type\n */\nexport async function generateSchema(\n options: GenerateSchemaOptions,\n): Promise<GenerateSchemaResult> {\n const generator = generators[options.adapterId];\n\n if (!generator) {\n throw new Error(\n `No schema generator found for adapter \"${options.adapterId}\".\\n` +\n `Available generators: ${Object.keys(generators).join(\", \")}`,\n );\n }\n\n return generator(options);\n}\n\n/**\n * Get list of supported adapters\n */\nexport function getSupportedAdapters(): string[] {\n return Object.keys(generators);\n}\n\nexport type { DrizzleGeneratorOptions } from \"./drizzle\";\nexport { generateDrizzleSchema } from \"./drizzle\";\n","import path from \"node:path\";\nimport { createJiti } from \"jiti\";\n\n/**\n * Default config file names to search for\n */\nconst CONFIG_FILES = [\n \"billing.ts\",\n \"billing.js\",\n \"src/billing.ts\",\n \"src/billing.js\",\n \"lib/billing.ts\",\n \"lib/billing.js\",\n];\n\n/**\n * Result of loading the billing config\n */\nexport interface ConfigResult {\n config: unknown;\n configPath: string;\n}\n\n/**\n * Find the billing config file in the current directory\n */\nexport async function findConfigFile(cwd: string): Promise<string | null> {\n const fs = await import(\"node:fs/promises\");\n\n for (const file of CONFIG_FILES) {\n const configPath = path.join(cwd, file);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n // File doesn't exist, try next\n }\n }\n\n return null;\n}\n\n/**\n * Load the billing config from a file\n */\nexport async function loadConfig(configPath: string): Promise<ConfigResult> {\n // Create jiti instance for loading TypeScript files\n const jiti = createJiti(import.meta.url, {\n interopDefault: true,\n moduleCache: false,\n fsCache: false,\n });\n\n try {\n const module = await jiti.import(configPath);\n\n // Look for common export names\n const config =\n (module as Record<string, unknown>).billing ||\n (module as Record<string, unknown>).default ||\n module;\n\n return {\n config,\n configPath,\n };\n } catch (error) {\n throw new Error(\n `Failed to load config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Get the billing config, searching for it if no path is provided\n */\nexport async function getConfig(\n configPath?: string,\n cwd = process.cwd(),\n): Promise<ConfigResult> {\n let resolvedPath: string;\n\n if (configPath) {\n // Use provided path\n resolvedPath = path.isAbsolute(configPath)\n ? configPath\n : path.join(cwd, configPath);\n } else {\n // Search for config file\n const found = await findConfigFile(cwd);\n if (!found) {\n throw new Error(\n \"Config file not found. Run:\\n\\n npx @billsdk/cli init\\n\",\n );\n }\n resolvedPath = found;\n }\n\n return loadConfig(resolvedPath);\n}\n","import type { DBSchema } from \"@billsdk/core\";\nimport { billingSchema } from \"@billsdk/core\";\n\n/**\n * Plugin interface for schema extraction\n */\ninterface Plugin {\n id: string;\n schema?: DBSchema;\n}\n\n/**\n * Get the merged schema (core + plugins)\n */\nexport function getMergedSchema(config: unknown): DBSchema {\n // Start with the base billing schema\n let schema = { ...billingSchema };\n\n const cfg = config as Record<string, unknown>;\n\n // Try to get plugins from different possible locations\n let plugins: Plugin[] | undefined;\n\n // Check if it's a billsdk instance with $context\n if (cfg.$context && typeof cfg.$context === \"object\") {\n const ctx = cfg.$context as { plugins?: Plugin[] };\n plugins = ctx.plugins;\n }\n\n // Check for plugins directly (raw options)\n if (!plugins && Array.isArray(cfg.plugins)) {\n plugins = cfg.plugins as Plugin[];\n }\n\n // Check for options property\n if (!plugins && cfg.options && typeof cfg.options === \"object\") {\n const opts = cfg.options as { plugins?: Plugin[] };\n plugins = opts.plugins;\n }\n\n // Merge plugin schemas\n if (plugins) {\n for (const plugin of plugins) {\n if (plugin.schema) {\n schema = { ...schema, ...plugin.schema };\n }\n }\n }\n\n return schema;\n}\n\n/**\n * Get adapter info from the config\n */\nexport function getAdapterInfo(config: unknown): {\n adapterId: string;\n provider?: string;\n} | null {\n // The config could be:\n // 1. A billsdk instance (result of billsdk({...}))\n // 2. The raw options object with a database property\n // 3. A module with both billing and billingConfig exports\n\n const cfg = config as Record<string, unknown>;\n\n // Check if this is a billsdk instance with $context\n // The context contains the resolved database adapter\n if (cfg.$context && typeof cfg.$context === \"object\") {\n const ctx = cfg.$context as { database?: { id?: string } };\n if (ctx.database?.id) {\n return {\n adapterId: ctx.database.id,\n };\n }\n }\n\n // Check for database property directly (raw options)\n if (cfg.database) {\n const db = cfg.database as { id?: string; options?: { provider?: string } };\n\n // If it's a function that returns an adapter (factory pattern)\n if (typeof db === \"function\") {\n try {\n const adapter = (db as (opts: unknown) => { id: string })({});\n return {\n adapterId: adapter.id,\n };\n } catch {\n // Fall through\n }\n }\n\n // If it's already an adapter object\n if (db.id) {\n return {\n adapterId: db.id,\n provider: db.options?.provider,\n };\n }\n }\n\n // Check for options property (might be exposed on billsdk instance)\n if (cfg.options && typeof cfg.options === \"object\") {\n const opts = cfg.options as { database?: { id?: string } };\n if (opts.database?.id) {\n return {\n adapterId: opts.database.id,\n };\n }\n }\n\n // Couldn't detect - will rely on CLI flags\n return null;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport * as prettier from \"prettier\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Initialize BillSDK in your project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts and use defaults\", false)\n .action(async (options) => {\n const cwd = process.cwd();\n\n p.intro(chalk.cyan(\"@billsdk/cli init\"));\n\n try {\n // Check if billing.ts already exists\n const configPath = path.join(cwd, \"billing.ts\");\n try {\n await fs.access(configPath);\n p.log.warn(\"billing.ts already exists. Skipping initialization.\");\n p.outro(chalk.yellow(\"Already initialized\"));\n return;\n } catch {\n // File doesn't exist, we can continue\n }\n\n let provider = \"pg\";\n let adapter = \"drizzle\";\n let installDeps = true;\n\n if (!options.yes) {\n // Ask for adapter\n const adapterChoice = await p.select({\n message: \"Which database adapter do you want to use?\",\n options: [\n { value: \"drizzle\", label: \"Drizzle ORM\", hint: \"recommended\" },\n { value: \"memory\", label: \"In-Memory\", hint: \"for testing\" },\n ],\n });\n\n if (p.isCancel(adapterChoice)) {\n p.log.warn(\"Initialization cancelled.\");\n process.exit(0);\n }\n\n adapter = adapterChoice as string;\n\n // Ask for provider if using drizzle\n if (adapter === \"drizzle\") {\n const providerChoice = await p.select({\n message: \"Which database provider?\",\n options: [\n { value: \"pg\", label: \"PostgreSQL\", hint: \"recommended\" },\n { value: \"mysql\", label: \"MySQL\" },\n { value: \"sqlite\", label: \"SQLite\" },\n ],\n });\n\n if (p.isCancel(providerChoice)) {\n p.log.warn(\"Initialization cancelled.\");\n process.exit(0);\n }\n\n provider = providerChoice as string;\n }\n\n // Ask about installing dependencies\n const shouldInstall = await p.confirm({\n message: \"Install dependencies?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall)) {\n p.log.warn(\"Initialization cancelled.\");\n process.exit(0);\n }\n\n installDeps = shouldInstall;\n }\n\n const spinner = p.spinner();\n\n // Generate billing.ts content\n const configContent = generateConfigContent(adapter, provider);\n\n // Write config file\n spinner.start(\"Creating billing.ts…\");\n const formatted = await prettier.format(configContent, {\n parser: \"typescript\",\n semi: true,\n singleQuote: false,\n tabWidth: 2,\n });\n await fs.writeFile(configPath, formatted, \"utf-8\");\n spinner.stop(`${chalk.green(\"✓\")} Created billing.ts`);\n\n // Install dependencies\n if (installDeps) {\n spinner.start(\"Installing dependencies…\");\n const deps = getDependencies(adapter, provider);\n const packageManager = await detectPackageManager(cwd);\n\n try {\n const { execSync } = await import(\"node:child_process\");\n const installCmd = getInstallCommand(packageManager, deps);\n execSync(installCmd, { cwd, stdio: \"pipe\" });\n spinner.stop(`${chalk.green(\"✓\")} Installed dependencies`);\n } catch (_error) {\n spinner.stop(`${chalk.yellow(\"⚠\")} Failed to install dependencies`);\n p.log.warn(\n `Install manually:\\n${chalk.dim(\n ` ${packageManager} install ${deps.join(\" \")}`,\n )}`,\n );\n }\n }\n\n // Success message\n p.log.success(\"BillSDK initialized!\");\n\n // Next steps\n const nextSteps = [\n \"1. Update your database connection in billing.ts\",\n \"2. Configure your plans\",\n \"3. Run: npx @billsdk/cli generate\",\n \"4. Run: npx drizzle-kit generate && npx drizzle-kit migrate\",\n ];\n\n p.note(nextSteps.join(\"\\n\"), \"Next steps\");\n\n p.outro(chalk.green(\"Done!\"));\n } catch (error) {\n p.log.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n\n/**\n * Generate the billing.ts config content\n */\nfunction generateConfigContent(adapter: string, provider: string): string {\n if (adapter === \"memory\") {\n return `import { billsdk, memoryAdapter } from \"billsdk\";\n\nexport const billing = billsdk({\n database: memoryAdapter(),\n plans: [\n {\n code: \"free\",\n name: \"Free\",\n description: \"Get started for free\",\n price: { monthly: 0, yearly: 0 },\n features: {\n projects: { type: \"limit\", value: 3 },\n },\n },\n {\n code: \"pro\",\n name: \"Pro\",\n description: \"For growing teams\",\n price: { monthly: 1900, yearly: 19000 }, // in cents\n features: {\n projects: { type: \"limit\", value: 100 },\n analytics: { type: \"boolean\", value: true },\n },\n },\n ],\n});\n`;\n }\n\n // Drizzle adapter\n return `import { billsdk } from \"billsdk\";\nimport { drizzleAdapter } from \"@billsdk/drizzle-adapter\";\nimport { db } from \"./db\"; // Your Drizzle DB instance\nimport * as schema from \"./billing-schema\"; // Generated by CLI\n\nexport const billing = billsdk({\n database: drizzleAdapter(db, {\n schema,\n provider: \"${provider}\",\n }),\n plans: [\n {\n code: \"free\",\n name: \"Free\",\n description: \"Get started for free\",\n price: { monthly: 0, yearly: 0 },\n features: {\n projects: { type: \"limit\", value: 3 },\n },\n },\n {\n code: \"pro\",\n name: \"Pro\",\n description: \"For growing teams\",\n price: { monthly: 1900, yearly: 19000 }, // in cents\n features: {\n projects: { type: \"limit\", value: 100 },\n analytics: { type: \"boolean\", value: true },\n },\n },\n ],\n});\n`;\n}\n\n/**\n * Get dependencies to install\n */\nfunction getDependencies(adapter: string, provider: string): string[] {\n const deps = [\"billsdk\"];\n\n if (adapter === \"drizzle\") {\n deps.push(\"@billsdk/drizzle-adapter\", \"drizzle-orm\", \"drizzle-kit\");\n\n switch (provider) {\n case \"pg\":\n deps.push(\"postgres\");\n break;\n case \"mysql\":\n deps.push(\"mysql2\");\n break;\n case \"sqlite\":\n deps.push(\"better-sqlite3\");\n break;\n }\n } else if (adapter === \"memory\") {\n deps.push(\"@billsdk/memory-adapter\");\n }\n\n return deps;\n}\n\n/**\n * Detect package manager\n */\nasync function detectPackageManager(\n cwd: string,\n): Promise<\"npm\" | \"pnpm\" | \"yarn\" | \"bun\"> {\n try {\n await fs.access(path.join(cwd, \"pnpm-lock.yaml\"));\n return \"pnpm\";\n } catch {}\n\n try {\n await fs.access(path.join(cwd, \"yarn.lock\"));\n return \"yarn\";\n } catch {}\n\n try {\n await fs.access(path.join(cwd, \"bun.lockb\"));\n return \"bun\";\n } catch {}\n\n return \"npm\";\n}\n\n/**\n * Get install command for package manager\n */\nfunction getInstallCommand(\n packageManager: \"npm\" | \"pnpm\" | \"yarn\" | \"bun\",\n deps: string[],\n): string {\n switch (packageManager) {\n case \"pnpm\":\n return `pnpm add ${deps.join(\" \")}`;\n case \"yarn\":\n return `yarn add ${deps.join(\" \")}`;\n case \"bun\":\n return `bun add ${deps.join(\" \")}`;\n default:\n return `npm install ${deps.join(\" \")}`;\n }\n}\n"],"mappings":"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","names":["Command","path","fs","spinner","path","fs","path","p","chalk","Command","prettier","spinner","Command"]}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@billsdk/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for BillSDK - Generate schemas and manage billing configuration",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "decker",
9
+ "url": "https://github.com/decker-dev"
10
+ },
11
+ "homepage": "https://billsdk.com/docs/concepts/cli",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/commet-labs/billsdk.git",
15
+ "directory": "packages/cli"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/commet-labs/billsdk/issues"
19
+ },
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "bin": "./dist/index.js",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ }
29
+ },
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "test": "vitest run --passWithNoTests",
40
+ "test:watch": "vitest",
41
+ "typecheck": "tsc --noEmit",
42
+ "lint": "biome check .",
43
+ "lint:fix": "biome check . --write",
44
+ "clean": "rm -rf dist .turbo node_modules"
45
+ },
46
+ "dependencies": {
47
+ "@billsdk/core": "workspace:*",
48
+ "@clack/prompts": "1.0.0",
49
+ "c12": "3.3.3",
50
+ "chalk": "5.6.2",
51
+ "commander": "14.0.3",
52
+ "dotenv": "17.2.3",
53
+ "prettier": "3.8.1"
54
+ },
55
+ "devDependencies": {
56
+ "@babel/core": "7.29.0",
57
+ "@babel/preset-react": "7.28.5",
58
+ "@babel/preset-typescript": "7.28.5",
59
+ "@biomejs/biome": "2.3.11",
60
+ "@types/node": "22.15.29",
61
+ "billsdk": "workspace:*",
62
+ "drizzle-orm": "0.45.1",
63
+ "jiti": "2.6.1",
64
+ "tsup": "8.5.1",
65
+ "tsx": "4.21.0",
66
+ "typescript": "5.9.3",
67
+ "vitest": "4.0.17"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ },
72
+ "keywords": [
73
+ "billing",
74
+ "sdk",
75
+ "cli",
76
+ "schema",
77
+ "generator",
78
+ "drizzle",
79
+ "prisma"
80
+ ]
81
+ }