@schemalens/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.
Files changed (50) hide show
  1. package/README.md +154 -0
  2. package/dist/commands/ci.d.ts +15 -0
  3. package/dist/commands/ci.js +78 -0
  4. package/dist/commands/ci.js.map +1 -0
  5. package/dist/commands/deploy.d.ts +8 -0
  6. package/dist/commands/deploy.js +212 -0
  7. package/dist/commands/deploy.js.map +1 -0
  8. package/dist/commands/diff.d.ts +1 -0
  9. package/dist/commands/diff.js +96 -0
  10. package/dist/commands/diff.js.map +1 -0
  11. package/dist/commands/init.d.ts +1 -0
  12. package/dist/commands/init.js +197 -0
  13. package/dist/commands/init.js.map +1 -0
  14. package/dist/commands/migrate.d.ts +1 -0
  15. package/dist/commands/migrate.js +50 -0
  16. package/dist/commands/migrate.js.map +1 -0
  17. package/dist/commands/pull.d.ts +1 -0
  18. package/dist/commands/pull.js +80 -0
  19. package/dist/commands/pull.js.map +1 -0
  20. package/dist/commands/status.d.ts +1 -0
  21. package/dist/commands/status.js +59 -0
  22. package/dist/commands/status.js.map +1 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +133 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/lib/config.d.ts +34 -0
  27. package/dist/lib/config.js +150 -0
  28. package/dist/lib/config.js.map +1 -0
  29. package/dist/lib/differ.d.ts +13 -0
  30. package/dist/lib/differ.js +130 -0
  31. package/dist/lib/differ.js.map +1 -0
  32. package/dist/lib/git.d.ts +16 -0
  33. package/dist/lib/git.js +65 -0
  34. package/dist/lib/git.js.map +1 -0
  35. package/dist/lib/introspector.d.ts +2 -0
  36. package/dist/lib/introspector.js +7 -0
  37. package/dist/lib/introspector.js.map +1 -0
  38. package/dist/lib/planner.d.ts +26 -0
  39. package/dist/lib/planner.js +501 -0
  40. package/dist/lib/planner.js.map +1 -0
  41. package/dist/lib/reader.d.ts +19 -0
  42. package/dist/lib/reader.js +106 -0
  43. package/dist/lib/reader.js.map +1 -0
  44. package/dist/lib/sync.d.ts +13 -0
  45. package/dist/lib/sync.js +46 -0
  46. package/dist/lib/sync.js.map +1 -0
  47. package/dist/lib/writer.d.ts +7 -0
  48. package/dist/lib/writer.js +191 -0
  49. package/dist/lib/writer.js.map +1 -0
  50. package/package.json +37 -0
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initCommand = initCommand;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const prompts_1 = require("@inquirer/prompts");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const js_yaml_1 = __importDefault(require("js-yaml"));
12
+ const config_1 = require("../lib/config");
13
+ const CONFIG_PATH = path_1.default.join('schema', '_meta', '.schemalens.yml');
14
+ /** Maximum number of environments the init wizard will prompt for. */
15
+ const MAX_ENVIRONMENTS = 5;
16
+ async function initCommand() {
17
+ const fullPath = path_1.default.resolve(CONFIG_PATH);
18
+ if (fs_1.default.existsSync(fullPath)) {
19
+ console.error(chalk_1.default.red(`\nConfig already exists at ${fullPath}\n`));
20
+ process.exit(1);
21
+ }
22
+ console.log(chalk_1.default.bold('\n SchemeLens — Project Setup\n'));
23
+ console.log(chalk_1.default.dim(' This creates schema/_meta/.schemalens.yml in your repo.\n'));
24
+ // --- Phase A: SaaS Linking (asked first) ---
25
+ console.log(chalk_1.default.dim(' Optional: link to SchemeLens SaaS for dashboard sync.\n'));
26
+ const linkToSaas = await (0, prompts_1.confirm)({
27
+ message: 'Link to SchemeLens SaaS project?',
28
+ default: true,
29
+ });
30
+ let projectId;
31
+ let apiKeyVarName;
32
+ let resolvedApiKey;
33
+ let useLinkedMode = false;
34
+ let remoteEnvNames = [];
35
+ if (linkToSaas) {
36
+ projectId = await (0, prompts_1.input)({
37
+ message: 'Project ID (copy from dashboard → Project Settings)',
38
+ validate: (v) => /^[0-9a-f-]{36}$/.test(v.trim()) || 'Must be a valid UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)',
39
+ });
40
+ projectId = projectId.trim();
41
+ const apiKeyInput = (await (0, prompts_1.input)({
42
+ message: 'API key or env var name (e.g. SCHEMALENS_API_KEY or slk_...)',
43
+ default: 'SCHEMALENS_API_KEY',
44
+ })).trim();
45
+ if (apiKeyInput.startsWith('slk_')) {
46
+ // User pasted the actual key — store the var name, use raw key for fetch
47
+ apiKeyVarName = 'SCHEMALENS_API_KEY';
48
+ resolvedApiKey = apiKeyInput;
49
+ console.log(chalk_1.default.yellow('\n ⚠ Detected a raw API key. It will be referenced as env(SCHEMALENS_API_KEY).\n') +
50
+ chalk_1.default.dim(` Set it in your shell:\n`) +
51
+ chalk_1.default.cyan(` export SCHEMALENS_API_KEY=${apiKeyInput}\n`));
52
+ }
53
+ else {
54
+ apiKeyVarName = apiKeyInput;
55
+ try {
56
+ resolvedApiKey = (0, config_1.resolveEnvVar)(`env(${apiKeyInput})`);
57
+ }
58
+ catch {
59
+ console.log(chalk_1.default.yellow(`\n ⚠ Env var "${apiKeyInput}" is not set. Cannot fetch environments from SaaS.\n`));
60
+ }
61
+ }
62
+ // --- Phase B: Fetch environments from SaaS ---
63
+ if (resolvedApiKey) {
64
+ try {
65
+ console.log(chalk_1.default.dim(' Fetching environments from SaaS...\n'));
66
+ const remoteEnvs = await (0, config_1.fetchEnvironmentsFromSaaS)(projectId, resolvedApiKey);
67
+ remoteEnvNames = remoteEnvs.map(e => e.name);
68
+ }
69
+ catch (err) {
70
+ console.log(chalk_1.default.yellow(` ⚠ ${err.message}\n`));
71
+ console.log(chalk_1.default.dim(' You can enter environments manually instead.\n'));
72
+ }
73
+ }
74
+ }
75
+ // --- Phase B/D: Environment selection ---
76
+ const environments = [];
77
+ if (remoteEnvNames.length > 0) {
78
+ // SaaS environments found — let user select
79
+ console.log(chalk_1.default.green(` Found ${remoteEnvNames.length} environment(s) in SaaS: ${remoteEnvNames.join(', ')}\n`));
80
+ const selected = await (0, prompts_1.checkbox)({
81
+ message: 'Select environments to configure locally',
82
+ choices: remoteEnvNames.map(name => ({
83
+ name,
84
+ value: name,
85
+ checked: true,
86
+ })),
87
+ validate: (v) => v.length > 0 || 'Select at least one environment',
88
+ });
89
+ for (const name of selected) {
90
+ environments.push({ name, connectionString: '' });
91
+ }
92
+ // Offer to add more local-only environments
93
+ if (environments.length < MAX_ENVIRONMENTS) {
94
+ const addMore = await (0, prompts_1.confirm)({
95
+ message: 'Add additional local-only environments?',
96
+ default: false,
97
+ });
98
+ if (addMore) {
99
+ await collectManualEnvironments(environments);
100
+ }
101
+ }
102
+ }
103
+ else {
104
+ // No SaaS environments — manual entry
105
+ await collectManualEnvironments(environments);
106
+ }
107
+ // --- Phase C: Linked mode decision ---
108
+ if (linkToSaas) {
109
+ useLinkedMode = await (0, prompts_1.confirm)({
110
+ message: 'Use SaaS credentials for DB connection? (no local DATABASE_URL needed)',
111
+ default: remoteEnvNames.length > 0,
112
+ });
113
+ }
114
+ // If not linked mode, collect connection strings for envs that don't have them
115
+ if (!useLinkedMode) {
116
+ for (const env of environments) {
117
+ if (!env.connectionString) {
118
+ const suffix = env.name === 'dev' ? '' : `_${env.name.toUpperCase()}`;
119
+ env.connectionString = await (0, prompts_1.input)({
120
+ message: `Connection string for "${env.name}"`,
121
+ default: `env(DATABASE_URL${suffix})`,
122
+ validate: (v) => v.trim().length > 0 || 'Required',
123
+ });
124
+ }
125
+ }
126
+ }
127
+ // --- Phase E: Build config + write file ---
128
+ const environmentsObj = {};
129
+ for (const env of environments) {
130
+ if (useLinkedMode) {
131
+ environmentsObj[env.name] = {};
132
+ }
133
+ else {
134
+ environmentsObj[env.name] = { connection_string: env.connectionString };
135
+ }
136
+ }
137
+ const config = {
138
+ version: 1,
139
+ schema_dir: 'schema',
140
+ allow_destructive: false,
141
+ environments: environmentsObj,
142
+ };
143
+ if (projectId) {
144
+ config.project_id = projectId;
145
+ }
146
+ if (apiKeyVarName) {
147
+ config.api_key = `env(${apiKeyVarName})`;
148
+ }
149
+ const dir = path_1.default.dirname(fullPath);
150
+ if (!fs_1.default.existsSync(dir)) {
151
+ fs_1.default.mkdirSync(dir, { recursive: true });
152
+ }
153
+ const yamlContent = js_yaml_1.default.dump(config, { lineWidth: 120 });
154
+ fs_1.default.writeFileSync(fullPath, yamlContent, 'utf-8');
155
+ // --- Success ---
156
+ console.log(chalk_1.default.green(`\n ✓ Created ${CONFIG_PATH}\n`));
157
+ if (useLinkedMode) {
158
+ console.log(chalk_1.default.dim(' Connection credentials will be fetched from SchemeLens SaaS.\n'));
159
+ console.log(chalk_1.default.dim(' Make sure your API key is set:\n') +
160
+ chalk_1.default.cyan(` export ${apiKeyVarName}=slk_...\n`));
161
+ }
162
+ else {
163
+ console.log(chalk_1.default.dim(' Make sure your database connection env vars are set.\n'));
164
+ }
165
+ const firstEnv = environments[0].name;
166
+ console.log(chalk_1.default.bold(' Next steps:\n'));
167
+ console.log(` ${chalk_1.default.cyan(`schemalens pull --env ${firstEnv}`)} # snapshot your live database`);
168
+ console.log(` ${chalk_1.default.cyan(`schemalens status --env ${firstEnv}`)} # see what changed\n`);
169
+ }
170
+ /** Collects environments manually via interactive prompts. */
171
+ async function collectManualEnvironments(environments) {
172
+ let addingEnvs = true;
173
+ while (addingEnvs) {
174
+ const isFirst = environments.length === 0;
175
+ const envName = await (0, prompts_1.input)({
176
+ message: 'Environment name',
177
+ default: isFirst ? 'dev' : undefined,
178
+ validate: (v) => v.trim().length > 0 || 'Required',
179
+ });
180
+ const connString = await (0, prompts_1.input)({
181
+ message: `Connection string for "${envName}"`,
182
+ default: `env(DATABASE_URL${isFirst ? '' : `_${envName.toUpperCase()}`})`,
183
+ validate: (v) => v.trim().length > 0 || 'Required',
184
+ });
185
+ environments.push({ name: envName.trim(), connectionString: connString.trim() });
186
+ if (environments.length < MAX_ENVIRONMENTS) {
187
+ addingEnvs = await (0, prompts_1.confirm)({
188
+ message: 'Add another environment?',
189
+ default: false,
190
+ });
191
+ }
192
+ else {
193
+ addingEnvs = false;
194
+ }
195
+ }
196
+ }
197
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function migrateCommand(): Promise<void>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.migrateCommand = migrateCommand;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const ora_1 = __importDefault(require("ora"));
11
+ const config_1 = require("../lib/config");
12
+ const SCHEMA_DIR = 'schema';
13
+ const OBJECT_DIRS = ['tables', 'views', 'functions', 'enums', 'extensions'];
14
+ function isLegacyLayout() {
15
+ for (const dir of OBJECT_DIRS) {
16
+ if (fs_1.default.existsSync(path_1.default.resolve(SCHEMA_DIR, dir))) {
17
+ return true;
18
+ }
19
+ }
20
+ return false;
21
+ }
22
+ async function migrateCommand() {
23
+ console.log(chalk_1.default.bold('\n SchemeLens Migrate — Schema Directory Layout\n'));
24
+ if (!isLegacyLayout()) {
25
+ console.log(chalk_1.default.green(' Already using environment-scoped layout. Nothing to do.\n'));
26
+ return;
27
+ }
28
+ const config = (0, config_1.loadConfig)();
29
+ const envNames = Object.keys(config.environments);
30
+ const defaultEnv = envNames[0] || 'dev';
31
+ console.log(chalk_1.default.yellow(` Detected legacy flat layout (schema/tables/...).`));
32
+ console.log(chalk_1.default.dim(` Moving schema files into schema/${defaultEnv}/\n`));
33
+ const spinner = (0, ora_1.default)('Migrating...').start();
34
+ const targetDir = path_1.default.resolve(SCHEMA_DIR, defaultEnv);
35
+ if (!fs_1.default.existsSync(targetDir)) {
36
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
37
+ }
38
+ let moved = 0;
39
+ for (const dir of OBJECT_DIRS) {
40
+ const srcDir = path_1.default.resolve(SCHEMA_DIR, dir);
41
+ if (!fs_1.default.existsSync(srcDir))
42
+ continue;
43
+ const destDir = path_1.default.join(targetDir, dir);
44
+ fs_1.default.renameSync(srcDir, destDir);
45
+ moved++;
46
+ }
47
+ spinner.succeed(chalk_1.default.green(`Moved ${moved} directories into schema/${defaultEnv}/`));
48
+ console.log(chalk_1.default.dim(`\n Run ${chalk_1.default.cyan(`schemalens pull --env ${defaultEnv}`)} to verify.\n`));
49
+ }
50
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":";;;;;AAkBA,wCAkCC;AApDD,4CAAoB;AACpB,gDAAwB;AACxB,kDAA0B;AAC1B,8CAAsB;AACtB,0CAA2C;AAE3C,MAAM,UAAU,GAAG,QAAQ,CAAC;AAC5B,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;AAE5E,SAAS,cAAc;IACrB,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,YAAE,CAAC,UAAU,CAAC,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAEM,KAAK,UAAU,cAAc;IAClC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC,CAAC;IAE9E,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC,CAAC;QACxF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,qCAAqC,UAAU,KAAK,CAAC,CAAC,CAAC;IAE7E,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,cAAc,CAAC,CAAC,KAAK,EAAE,CAAC;IAE5C,MAAM,SAAS,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,YAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS;QAErC,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC1C,YAAE,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,KAAK,EAAE,CAAC;IACV,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,eAAK,CAAC,KAAK,CAAC,SAAS,KAAK,4BAA4B,UAAU,GAAG,CAAC,CAAC,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,WAAW,eAAK,CAAC,IAAI,CAAC,yBAAyB,UAAU,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;AACtG,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function pullCommand(env: string): Promise<void>;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pullCommand = pullCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const config_1 = require("../lib/config");
10
+ const introspector_1 = require("../lib/introspector");
11
+ const writer_1 = require("../lib/writer");
12
+ const sync_1 = require("../lib/sync");
13
+ const git_1 = require("../lib/git");
14
+ async function pullCommand(env) {
15
+ console.log(chalk_1.default.bold(`\nSchemaLens Pull — env: ${chalk_1.default.cyan(env)}\n`));
16
+ // 1. Load config
17
+ const config = (0, config_1.loadConfig)();
18
+ const connectionString = await (0, config_1.resolveConnectionString)(config, env);
19
+ // Detect git context
20
+ const gitContext = (0, git_1.detectGitContext)();
21
+ if (gitContext) {
22
+ const branch = gitContext.branch ?? 'detached HEAD';
23
+ const sha = gitContext.commit_sha.substring(0, 7);
24
+ const dirty = gitContext.dirty ? chalk_1.default.yellow(' (dirty)') : '';
25
+ console.log(chalk_1.default.dim(` git: ${branch} @ ${sha}${dirty}`));
26
+ }
27
+ // 2. Introspect
28
+ const spinner = (0, ora_1.default)('Connecting to database...').start();
29
+ let snapshot;
30
+ try {
31
+ snapshot = await (0, introspector_1.introspectSchema)(connectionString);
32
+ spinner.succeed(chalk_1.default.green('Schema introspected successfully'));
33
+ }
34
+ catch (err) {
35
+ spinner.fail(chalk_1.default.red('Failed to introspect schema'));
36
+ throw err;
37
+ }
38
+ console.log(chalk_1.default.dim(` ${snapshot.tables.length} tables, ` +
39
+ `${snapshot.views.length} views, ` +
40
+ `${snapshot.functions.length} functions, ` +
41
+ `${snapshot.enums.length} enums, ` +
42
+ `${snapshot.extensions.length} extensions`));
43
+ // 3. Write schema files
44
+ const writeSpinner = (0, ora_1.default)('Writing schema files...').start();
45
+ const result = (0, writer_1.writeSchemaFiles)(snapshot, env);
46
+ writeSpinner.succeed(chalk_1.default.green('Schema files written'));
47
+ // 4. Summary
48
+ console.log('');
49
+ if (result.created.length > 0) {
50
+ console.log(chalk_1.default.green.bold(` + ${result.created.length} created`));
51
+ for (const f of result.created) {
52
+ console.log(chalk_1.default.green(` + ${f}`));
53
+ }
54
+ }
55
+ if (result.updated.length > 0) {
56
+ console.log(chalk_1.default.yellow.bold(` ~ ${result.updated.length} updated`));
57
+ for (const f of result.updated) {
58
+ console.log(chalk_1.default.yellow(` ~ ${f}`));
59
+ }
60
+ }
61
+ if (result.unchanged.length > 0) {
62
+ console.log(chalk_1.default.dim(` = ${result.unchanged.length} unchanged`));
63
+ }
64
+ const total = result.created.length + result.updated.length + result.unchanged.length;
65
+ console.log(chalk_1.default.bold(`\n Total: ${total} files\n`));
66
+ // Auto-sync to SchemeLens cloud if configured
67
+ const projectId = config.project_id;
68
+ const apiKey = (0, config_1.resolveEnvVar)(config.api_key);
69
+ if (projectId && apiKey) {
70
+ const syncSpinner = (0, ora_1.default)('Syncing snapshot to SchemeLens...').start();
71
+ const syncResult = await (0, sync_1.syncToCloud)(projectId, apiKey, 'pull', env, gitContext);
72
+ if (syncResult) {
73
+ syncSpinner.succeed(chalk_1.default.green(`Snapshot synced to SchemeLens cloud (${syncResult.object_count} objects, ${syncResult.changed_count} changed)`));
74
+ }
75
+ else {
76
+ syncSpinner.warn(chalk_1.default.yellow('SchemeLens sync skipped (see warning above)'));
77
+ }
78
+ }
79
+ }
80
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function statusCommand(env: string): Promise<void>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.statusCommand = statusCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const config_1 = require("../lib/config");
10
+ const introspector_1 = require("../lib/introspector");
11
+ const differ_1 = require("../lib/differ");
12
+ async function statusCommand(env) {
13
+ console.log(chalk_1.default.bold(`\nSchemaLens Status — env: ${chalk_1.default.cyan(env)}\n`));
14
+ // 1. Load config
15
+ const config = (0, config_1.loadConfig)();
16
+ const connectionString = await (0, config_1.resolveConnectionString)(config, env);
17
+ // 2. Introspect
18
+ const spinner = (0, ora_1.default)('Connecting to database...').start();
19
+ let snapshot;
20
+ try {
21
+ snapshot = await (0, introspector_1.introspectSchema)(connectionString);
22
+ spinner.succeed(chalk_1.default.green('Schema introspected successfully'));
23
+ }
24
+ catch (err) {
25
+ spinner.fail(chalk_1.default.red('Failed to introspect schema'));
26
+ throw err;
27
+ }
28
+ // 3. Diff against disk
29
+ const entries = (0, differ_1.diffSchema)(snapshot, env);
30
+ const newItems = entries.filter(e => e.status === 'new');
31
+ const changed = entries.filter(e => e.status === 'changed');
32
+ const deleted = entries.filter(e => e.status === 'deleted');
33
+ const unchanged = entries.filter(e => e.status === 'unchanged');
34
+ console.log('');
35
+ if (newItems.length > 0) {
36
+ console.log(chalk_1.default.green.bold(` + ${newItems.length} new objects`));
37
+ for (const e of newItems) {
38
+ console.log(chalk_1.default.green(` + [${e.type}] ${e.schema}.${e.name}`));
39
+ }
40
+ }
41
+ if (changed.length > 0) {
42
+ console.log(chalk_1.default.yellow.bold(` ~ ${changed.length} changed objects`));
43
+ for (const e of changed) {
44
+ console.log(chalk_1.default.yellow(` ~ [${e.type}] ${e.schema}.${e.name}`));
45
+ }
46
+ }
47
+ if (deleted.length > 0) {
48
+ console.log(chalk_1.default.red.bold(` - ${deleted.length} deleted objects`));
49
+ for (const e of deleted) {
50
+ console.log(chalk_1.default.red(` - [${e.type}] ${e.schema}.${e.name}`));
51
+ }
52
+ }
53
+ if (newItems.length === 0 && changed.length === 0 && deleted.length === 0) {
54
+ console.log(chalk_1.default.green(' Schema is up to date — no differences found.'));
55
+ }
56
+ console.log(chalk_1.default.dim(`\n ${unchanged.length} objects unchanged`));
57
+ console.log('');
58
+ }
59
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
package/dist/index.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ require("dotenv/config");
8
+ const commander_1 = require("commander");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const init_1 = require("./commands/init");
11
+ const pull_1 = require("./commands/pull");
12
+ const status_1 = require("./commands/status");
13
+ const diff_1 = require("./commands/diff");
14
+ const deploy_1 = require("./commands/deploy");
15
+ const migrate_1 = require("./commands/migrate");
16
+ const ci_1 = require("./commands/ci");
17
+ const program = new commander_1.Command();
18
+ program
19
+ .name('schemalens')
20
+ .description('Schema version control for PostgreSQL / Supabase')
21
+ .version('0.1.0');
22
+ program
23
+ .command('init')
24
+ .description('Set up SchemeLens in this repository (creates schema/_meta/.schemalens.yml)')
25
+ .action(async () => {
26
+ try {
27
+ await (0, init_1.initCommand)();
28
+ }
29
+ catch (err) {
30
+ // Handle Ctrl+C from inquirer gracefully
31
+ if (err.name === 'ExitPromptError') {
32
+ console.log(chalk_1.default.dim('\n Setup cancelled.\n'));
33
+ process.exit(0);
34
+ }
35
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
36
+ process.exit(1);
37
+ }
38
+ });
39
+ program
40
+ .command('pull')
41
+ .description('Pull the live database schema into local files')
42
+ .requiredOption('--env <env>', 'Target environment (dev, staging, prod)')
43
+ .action(async (opts) => {
44
+ try {
45
+ await (0, pull_1.pullCommand)(opts.env);
46
+ }
47
+ catch (err) {
48
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
49
+ process.exit(1);
50
+ }
51
+ });
52
+ program
53
+ .command('status')
54
+ .description('Show diff between live DB and local schema files')
55
+ .requiredOption('--env <env>', 'Target environment (dev, staging, prod)')
56
+ .action(async (opts) => {
57
+ try {
58
+ await (0, status_1.statusCommand)(opts.env);
59
+ }
60
+ catch (err) {
61
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
62
+ process.exit(1);
63
+ }
64
+ });
65
+ program
66
+ .command('diff')
67
+ .description('Compare schema files between two environments')
68
+ .requiredOption('--from <env>', 'Source environment')
69
+ .requiredOption('--to <env>', 'Target environment')
70
+ .action(async (opts) => {
71
+ try {
72
+ await (0, diff_1.diffCommand)(opts.from, opts.to);
73
+ }
74
+ catch (err) {
75
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
76
+ process.exit(1);
77
+ }
78
+ });
79
+ program
80
+ .command('deploy')
81
+ .description('Deploy local schema changes to the target environment')
82
+ .requiredOption('--env <env>', 'Target environment')
83
+ .option('--confirm', 'Actually apply changes (default is dry-run)', false)
84
+ .option('--dry-run', 'Print the plan without executing (default)', true)
85
+ .option('--rename <renames...>', 'Confirm column renames: table.oldCol:newCol')
86
+ .option('--allow-destructive', 'Allow destructive operations (DROP COLUMN, etc.)', false)
87
+ .action(async (opts) => {
88
+ try {
89
+ await (0, deploy_1.deployCommand)({
90
+ env: opts.env,
91
+ confirm: opts.confirm,
92
+ dryRun: !opts.confirm,
93
+ rename: opts.rename || [],
94
+ allowDestructive: opts.allowDestructive,
95
+ });
96
+ }
97
+ catch (err) {
98
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
99
+ process.exit(1);
100
+ }
101
+ });
102
+ program
103
+ .command('ci')
104
+ .description('Non-interactive CI mode: pull schema, sync to cloud, and check for issues')
105
+ .requiredOption('--env <env>', 'Target environment (dev, staging, prod)')
106
+ .option('--block-destructive', 'Exit with code 2 if destructive changes are detected', false)
107
+ .action(async (opts) => {
108
+ try {
109
+ await (0, ci_1.ciCommand)(opts);
110
+ }
111
+ catch (err) {
112
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
113
+ process.exit(1);
114
+ }
115
+ });
116
+ program
117
+ .command('migrate')
118
+ .description('Migrate legacy flat schema/ layout to environment-scoped schema/<env>/ layout')
119
+ .action(async () => {
120
+ try {
121
+ await (0, migrate_1.migrateCommand)();
122
+ }
123
+ catch (err) {
124
+ if (err.name === 'ExitPromptError') {
125
+ console.log(chalk_1.default.dim('\n Migration cancelled.\n'));
126
+ process.exit(0);
127
+ }
128
+ console.error(chalk_1.default.red(`\nError: ${err.message}\n`));
129
+ process.exit(1);
130
+ }
131
+ });
132
+ program.parse();
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface EnvConfig {
2
+ /** Direct connection string or env(VAR_NAME) reference. Optional when project is linked to SaaS. */
3
+ connection_string?: string;
4
+ }
5
+ export interface SchemaLensConfig {
6
+ version: number;
7
+ schema_dir: string;
8
+ allow_destructive: boolean;
9
+ environments: Record<string, EnvConfig>;
10
+ /** SaaS project UUID — copied from Project Settings in the web UI */
11
+ project_id?: string;
12
+ /** API key for auto-syncing snapshots after pull/deploy. Use env(SCHEMALENS_API_KEY). */
13
+ api_key?: string;
14
+ }
15
+ /**
16
+ * Resolve `env(VAR_NAME)` placeholders to process.env values.
17
+ * Returns undefined if the value itself is undefined.
18
+ */
19
+ export declare function resolveEnvVar(value: string | undefined): string | undefined;
20
+ export declare function loadConfig(): SchemaLensConfig;
21
+ /**
22
+ * Returns the resolved connection string for the given environment.
23
+ *
24
+ * Resolution order:
25
+ * 1. connection_string from config (resolved env vars) — existing behaviour
26
+ * 2. Fetch from SaaS using project_id + api_key — passwordless linked mode
27
+ * 3. Throw with a clear message
28
+ */
29
+ export declare function resolveConnectionString(config: SchemaLensConfig, env: string): Promise<string>;
30
+ export declare function fetchEnvironmentsFromSaaS(projectId: string, apiKey: string): Promise<{
31
+ name: string;
32
+ }[]>;
33
+ /** @deprecated Use resolveConnectionString() instead */
34
+ export declare function getConnectionString(config: SchemaLensConfig, env: string): string;