netlify-cli 24.9.0 → 24.11.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,7 @@
1
+ import BaseCommand from '../base-command.js';
2
+ export interface ConnectOptions {
3
+ query?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare const connect: (options: ConnectOptions, command: BaseCommand) => Promise<void>;
7
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/commands/database/connect.ts"],"names":[],"mappings":"AAGA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAK5C,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAaD,eAAO,MAAM,OAAO,GAAU,SAAS,cAAc,EAAE,SAAS,WAAW,KAAG,OAAO,CAAC,IAAI,CAuHzF,CAAA"}
@@ -0,0 +1,130 @@
1
+ import readline from 'readline';
2
+ import { log, logJson } from '../../utils/command-helpers.js';
3
+ import { connectRawClient } from './db-connection.js';
4
+ import { executeMetaCommand } from './meta-commands.js';
5
+ import { formatQueryResult } from './psql-formatter.js';
6
+ function redactConnectionString(connectionString) {
7
+ try {
8
+ const url = new URL(connectionString);
9
+ url.username = '';
10
+ url.password = '';
11
+ return url.toString();
12
+ }
13
+ catch {
14
+ return 'database';
15
+ }
16
+ }
17
+ export const connect = async (options, command) => {
18
+ const buildDir = command.netlify.site.root ?? command.project.root ?? command.project.baseDirectory;
19
+ if (!buildDir) {
20
+ throw new Error('Could not determine the project root directory.');
21
+ }
22
+ const { client, connectionString, cleanup } = await connectRawClient(buildDir);
23
+ // --json without --query: print connection details
24
+ if (options.json && !options.query) {
25
+ logJson({ connection_string: connectionString, context: 'dev' });
26
+ await cleanup();
27
+ return;
28
+ }
29
+ log(`Connected to ${redactConnectionString(connectionString)}`);
30
+ // --query: one-shot mode
31
+ if (options.query) {
32
+ try {
33
+ const result = await client.query(options.query);
34
+ if (options.json) {
35
+ logJson(result.rows);
36
+ }
37
+ else {
38
+ log(formatQueryResult(result.fields, result.rows, result.rowCount, result.command));
39
+ }
40
+ }
41
+ finally {
42
+ await cleanup();
43
+ }
44
+ return;
45
+ }
46
+ // Interactive REPL
47
+ const rl = readline.createInterface({
48
+ input: process.stdin,
49
+ output: process.stdout,
50
+ prompt: 'netlifydb=> ',
51
+ });
52
+ let buffer = '';
53
+ const handleCleanup = async () => {
54
+ rl.close();
55
+ await cleanup();
56
+ };
57
+ process.on('SIGINT', () => {
58
+ if (buffer) {
59
+ // Cancel current multi-line input
60
+ buffer = '';
61
+ process.stdout.write('\n');
62
+ rl.setPrompt('netlifydb=> ');
63
+ rl.prompt();
64
+ }
65
+ else {
66
+ log('');
67
+ void handleCleanup();
68
+ }
69
+ });
70
+ rl.on('close', () => {
71
+ void handleCleanup();
72
+ });
73
+ rl.on('line', (line) => {
74
+ // Meta-commands are only recognized at the start of input (not mid-statement)
75
+ if (buffer === '' && line.trimStart().startsWith('\\')) {
76
+ rl.pause();
77
+ void (async () => {
78
+ try {
79
+ const result = await executeMetaCommand(line, client);
80
+ switch (result.type) {
81
+ case 'quit':
82
+ await handleCleanup();
83
+ return;
84
+ case 'help':
85
+ log(result.text);
86
+ break;
87
+ case 'unknown':
88
+ log(`Invalid command ${result.command}. Try \\? for help.`);
89
+ break;
90
+ case 'query':
91
+ log(formatQueryResult(result.fields, result.rows, result.rowCount, result.command));
92
+ break;
93
+ }
94
+ }
95
+ catch (err) {
96
+ const message = err instanceof Error ? err.message : String(err);
97
+ log(`ERROR: ${message}`);
98
+ }
99
+ rl.resume();
100
+ rl.prompt();
101
+ })();
102
+ return;
103
+ }
104
+ buffer += (buffer ? '\n' : '') + line;
105
+ if (buffer.trimEnd().endsWith(';')) {
106
+ const sql = buffer;
107
+ buffer = '';
108
+ rl.setPrompt('netlifydb=> ');
109
+ rl.pause();
110
+ void (async () => {
111
+ try {
112
+ const result = await client.query(sql);
113
+ log(formatQueryResult(result.fields, result.rows, result.rowCount, result.command));
114
+ }
115
+ catch (err) {
116
+ const message = err instanceof Error ? err.message : String(err);
117
+ log(`ERROR: ${message}`);
118
+ }
119
+ rl.resume();
120
+ rl.prompt();
121
+ })();
122
+ }
123
+ else {
124
+ rl.setPrompt('netlifydb-> ');
125
+ rl.prompt();
126
+ }
127
+ });
128
+ rl.prompt();
129
+ };
130
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/commands/database/connect.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/commands/database/database.ts"],"names":[],"mappings":"AAEA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAI5C,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,eAAO,MAAM,qBAAqB,GAAI,SAAS,WAAW,SA4GzD,CAAA"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/commands/database/database.ts"],"names":[],"mappings":"AAEA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAK5C,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,eAAO,MAAM,qBAAqB,GAAI,SAAS,WAAW,SAmJzD,CAAA"}
@@ -8,43 +8,43 @@ export const createDatabaseCommand = (program) => {
8
8
  .description(`Provision a production ready Postgres database with a single command`)
9
9
  .addExamples([
10
10
  'netlify db status',
11
- 'netlify db init',
12
- 'netlify db init --help',
13
11
  ...(process.env.EXPERIMENTAL_NETLIFY_DB_ENABLED === '1'
14
- ? ['netlify db migrate', 'netlify db reset', 'netlify db migration new']
15
- : []),
12
+ ? ['netlify db migrations apply', 'netlify db migrations pull', 'netlify db reset', 'netlify db migrations new']
13
+ : ['netlify db init', 'netlify db init --help']),
16
14
  ]);
17
- dbCommand
18
- .command('init')
19
- .description(`Initialize a new database for the current site`)
20
- .option('--assume-no', 'Non-interactive setup. Does not initialize any third-party tools/boilerplate. Ideal for CI environments or AI tools.', false)
21
- .addOption(new Option('--boilerplate <tool>', 'Type of boilerplate to add to your project.').choices(Array.from(supportedBoilerplates).sort()))
22
- .option('--no-boilerplate', "Don't add any boilerplate to your project.")
23
- .option('-o, --overwrite', 'Overwrites existing files that would be created when setting up boilerplate')
24
- .action(async (_options, command) => {
25
- const { init } = await import('./init.js');
26
- // Only prompt for drizzle if the user did not specify a boilerplate option, and if we're in
27
- // interactive mode
28
- if (_options.boilerplate === undefined && !_options.assumeNo) {
29
- const answers = await inquirer.prompt([
30
- {
31
- type: 'confirm',
32
- name: 'useDrizzle',
33
- message: 'Set up Drizzle boilerplate?',
34
- },
35
- ]);
36
- if (answers.useDrizzle) {
37
- command.setOptionValue('boilerplate', 'drizzle');
15
+ if (process.env.EXPERIMENTAL_NETLIFY_DB_ENABLED !== '1') {
16
+ dbCommand
17
+ .command('init')
18
+ .description(`Initialize a new database for the current site`)
19
+ .option('--assume-no', 'Non-interactive setup. Does not initialize any third-party tools/boilerplate. Ideal for CI environments or AI tools.', false)
20
+ .addOption(new Option('--boilerplate <tool>', 'Type of boilerplate to add to your project.').choices(Array.from(supportedBoilerplates).sort()))
21
+ .option('--no-boilerplate', "Don't add any boilerplate to your project.")
22
+ .option('-o, --overwrite', 'Overwrites existing files that would be created when setting up boilerplate')
23
+ .action(async (_options, command) => {
24
+ const { init } = await import('./init.js');
25
+ // Only prompt for drizzle if the user did not specify a boilerplate option, and if we're in
26
+ // interactive mode
27
+ if (_options.boilerplate === undefined && !_options.assumeNo) {
28
+ const answers = await inquirer.prompt([
29
+ {
30
+ type: 'confirm',
31
+ name: 'useDrizzle',
32
+ message: 'Set up Drizzle boilerplate?',
33
+ },
34
+ ]);
35
+ if (answers.useDrizzle) {
36
+ command.setOptionValue('boilerplate', 'drizzle');
37
+ }
38
38
  }
39
- }
40
- const options = _options;
41
- if (options.assumeNo) {
42
- options.boilerplate = false;
43
- options.overwrite = false;
44
- }
45
- await init(options, command);
46
- })
47
- .addExamples([`netlify db init --assume-no`, `netlify db init --boilerplate=drizzle --overwrite`]);
39
+ const options = _options;
40
+ if (options.assumeNo) {
41
+ options.boilerplate = false;
42
+ options.overwrite = false;
43
+ }
44
+ await init(options, command);
45
+ })
46
+ .addExamples([`netlify db init --assume-no`, `netlify db init --boilerplate=drizzle --overwrite`]);
47
+ }
48
48
  dbCommand
49
49
  .command('status')
50
50
  .description(`Check the status of the database`)
@@ -55,14 +55,20 @@ export const createDatabaseCommand = (program) => {
55
55
  });
56
56
  if (process.env.EXPERIMENTAL_NETLIFY_DB_ENABLED === '1') {
57
57
  dbCommand
58
- .command('migrate')
59
- .description('Apply database migrations to the local development database')
60
- .option('--to <name>', 'Target migration name or prefix to apply up to (applies all if omitted)')
61
- .option('--json', 'Output result as JSON')
58
+ .command('connect')
59
+ .description('Connect to the database')
60
+ .option('-q, --query <sql>', 'Execute a single query and exit')
61
+ .option('--json', 'Output query results as JSON. When used without --query, prints the connection details as JSON instead.')
62
62
  .action(async (options, command) => {
63
- const { migrate } = await import('./migrate.js');
64
- await migrate(options, command);
65
- });
63
+ const { connect } = await import('./connect.js');
64
+ await connect(options, command);
65
+ })
66
+ .addExamples([
67
+ 'netlify db connect',
68
+ 'netlify db connect --query "SELECT * FROM users"',
69
+ 'netlify db connect --json --query "SELECT * FROM users"',
70
+ 'netlify db connect --json',
71
+ ]);
66
72
  dbCommand
67
73
  .command('reset')
68
74
  .description('Reset the local development database, removing all data and tables')
@@ -71,8 +77,17 @@ export const createDatabaseCommand = (program) => {
71
77
  const { reset } = await import('./reset.js');
72
78
  await reset(options, command);
73
79
  });
74
- const migrationCommand = dbCommand.command('migration').description('Manage database migrations');
75
- migrationCommand
80
+ const migrationsCommand = dbCommand.command('migrations').description('Manage database migrations');
81
+ migrationsCommand
82
+ .command('apply')
83
+ .description('Apply database migrations to the local development database')
84
+ .option('--to <name>', 'Target migration name or prefix to apply up to (applies all if omitted)')
85
+ .option('--json', 'Output result as JSON')
86
+ .action(async (options, command) => {
87
+ const { migrate } = await import('./migrate.js');
88
+ await migrate(options, command);
89
+ });
90
+ migrationsCommand
76
91
  .command('new')
77
92
  .description('Create a new migration')
78
93
  .option('-d, --description <description>', 'Purpose of the migration (used to generate the file name)')
@@ -86,8 +101,24 @@ export const createDatabaseCommand = (program) => {
86
101
  await migrationNew(options, command);
87
102
  })
88
103
  .addExamples([
89
- 'netlify db migration new',
90
- 'netlify db migration new --description "add users table" --scheme sequential',
104
+ 'netlify db migrations new',
105
+ 'netlify db migrations new --description "add users table" --scheme sequential',
106
+ ]);
107
+ migrationsCommand
108
+ .command('pull')
109
+ .description('Pull migrations and overwrite local migration files')
110
+ .option('-b, --branch [branch]', "Pull migrations for a specific branch (defaults to 'production'; pass --branch with no value to use local git branch)")
111
+ .option('--force', 'Skip confirmation prompt', false)
112
+ .option('--json', 'Output result as JSON')
113
+ .action(async (options, command) => {
114
+ const { migrationPull } = await import('./migration-pull.js');
115
+ await migrationPull(options, command);
116
+ })
117
+ .addExamples([
118
+ 'netlify db migrations pull',
119
+ 'netlify db migrations pull --branch staging',
120
+ 'netlify db migrations pull --branch',
121
+ 'netlify db migrations pull --force',
91
122
  ]);
92
123
  }
93
124
  };
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/commands/database/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/commands/database/database.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,15 @@
1
+ import { Client } from 'pg';
1
2
  import { type SQLExecutor } from '@netlify/dev';
2
3
  interface DBConnection {
3
4
  executor: SQLExecutor;
4
5
  cleanup: () => Promise<void>;
5
6
  }
6
7
  export declare function connectToDatabase(buildDir: string): Promise<DBConnection>;
8
+ interface RawDBConnection {
9
+ client: Client;
10
+ connectionString: string;
11
+ cleanup: () => Promise<void>;
12
+ }
13
+ export declare function connectRawClient(buildDir: string): Promise<RawDBConnection>;
7
14
  export {};
8
15
  //# sourceMappingURL=db-connection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"db-connection.d.ts","sourceRoot":"","sources":["../../../src/commands/database/db-connection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAK3D,UAAU,YAAY;IACpB,QAAQ,EAAE,WAAW,CAAA;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAwC/E"}
1
+ {"version":3,"file":"db-connection.d.ts","sourceRoot":"","sources":["../../../src/commands/database/db-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAE3B,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAK3D,UAAU,YAAY;IACpB,QAAQ,EAAE,WAAW,CAAA;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAM/E;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,CAAA;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA2DjF"}
@@ -3,13 +3,31 @@ import { NetlifyDev } from '@netlify/dev';
3
3
  import { LocalState } from '@netlify/dev-utils';
4
4
  import { PgClientExecutor } from './pg-client-executor.js';
5
5
  export async function connectToDatabase(buildDir) {
6
+ const { client, cleanup } = await connectRawClient(buildDir);
7
+ return {
8
+ executor: new PgClientExecutor(client),
9
+ cleanup,
10
+ };
11
+ }
12
+ export async function connectRawClient(buildDir) {
13
+ const envConnectionString = process.env.NETLIFY_DB_URL;
14
+ if (envConnectionString) {
15
+ const client = new Client({ connectionString: envConnectionString });
16
+ await client.connect();
17
+ return {
18
+ client,
19
+ connectionString: envConnectionString,
20
+ cleanup: () => client.end(),
21
+ };
22
+ }
6
23
  const state = new LocalState(buildDir);
7
- const connectionString = state.get('dbConnectionString');
8
- if (connectionString) {
9
- const client = new Client({ connectionString });
24
+ const storedConnectionString = state.get('dbConnectionString');
25
+ if (storedConnectionString) {
26
+ const client = new Client({ connectionString: storedConnectionString });
10
27
  await client.connect();
11
28
  return {
12
- executor: new PgClientExecutor(client),
29
+ client,
30
+ connectionString: storedConnectionString,
13
31
  cleanup: () => client.end(),
14
32
  };
15
33
  }
@@ -28,14 +46,20 @@ export async function connectToDatabase(buildDir) {
28
46
  serverAddress: null,
29
47
  });
30
48
  await netlifyDev.start();
31
- const { db } = netlifyDev;
32
- if (!db) {
49
+ const connectionString = state.get('dbConnectionString');
50
+ if (!connectionString) {
33
51
  await netlifyDev.stop();
34
52
  throw new Error('Local database failed to start. Set EXPERIMENTAL_NETLIFY_DB_ENABLED=1 to enable.');
35
53
  }
54
+ const client = new Client({ connectionString });
55
+ await client.connect();
36
56
  return {
37
- executor: db,
38
- cleanup: () => netlifyDev.stop(),
57
+ client,
58
+ connectionString,
59
+ cleanup: async () => {
60
+ await client.end();
61
+ await netlifyDev.stop();
62
+ },
39
63
  };
40
64
  }
41
65
  //# sourceMappingURL=db-connection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"db-connection.js","sourceRoot":"","sources":["../../../src/commands/database/db-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAE3B,OAAO,EAAE,UAAU,EAAoB,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAO1D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IACtD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAA;IACtC,MAAM,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;IAExD,IAAI,gBAAgB,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAC/C,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;QACtB,OAAO;YACL,QAAQ,EAAE,IAAI,gBAAgB,CAAC,MAAM,CAAC;YACtC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE;SAC5B,CAAA;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC;QAChC,WAAW,EAAE,QAAQ;QACrB,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC7B,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACzB,aAAa,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACjC,oBAAoB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACxC,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC7B,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC/B,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC3B,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC1B,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC7B,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC/B,aAAa,EAAE,IAAI;KACpB,CAAC,CAAA;IAEF,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;IAExB,MAAM,EAAE,EAAE,EAAE,GAAG,UAAU,CAAA;IACzB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,UAAU,CAAC,IAAI,EAAE,CAAA;QACvB,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAA;IACrG,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE;KACjC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"db-connection.js","sourceRoot":"","sources":["../../../src/commands/database/db-connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Client, FieldDef } from 'pg';
2
+ export type MetaCommandResult = {
3
+ type: 'query';
4
+ fields: FieldDef[];
5
+ rows: Record<string, unknown>[];
6
+ rowCount: number | null;
7
+ command: string;
8
+ } | {
9
+ type: 'quit';
10
+ } | {
11
+ type: 'help';
12
+ text: string;
13
+ } | {
14
+ type: 'unknown';
15
+ command: string;
16
+ };
17
+ export declare const executeMetaCommand: (input: string, client: Client) => Promise<MetaCommandResult>;
18
+ //# sourceMappingURL=meta-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-commands.d.ts","sourceRoot":"","sources":["../../../src/commands/database/meta-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AAE1C,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChH;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAcxC,eAAO,MAAM,kBAAkB,GAAU,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,iBAAiB,CAmDjG,CAAA"}
@@ -0,0 +1,51 @@
1
+ const HELP_TEXT = `Netlify DB interactive client. Supports a subset of psql commands.
2
+
3
+ General
4
+ \\q quit
5
+
6
+ Informational
7
+ \\d list tables
8
+ \\dt list tables
9
+ \\d NAME describe table
10
+ \\l list databases
11
+ \\? show this help`;
12
+ export const executeMetaCommand = async (input, client) => {
13
+ const trimmed = input.trim();
14
+ const [cmd, ...args] = trimmed.split(/\s+/);
15
+ if (cmd === '\\q') {
16
+ return { type: 'quit' };
17
+ }
18
+ if (cmd === '\\?') {
19
+ return { type: 'help', text: HELP_TEXT };
20
+ }
21
+ if (cmd === '\\dt' || (cmd === '\\d' && args.length === 0)) {
22
+ const result = await client.query(`SELECT schemaname AS "Schema", tablename AS "Name", tableowner AS "Owner"
23
+ FROM pg_tables
24
+ WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
25
+ ORDER BY schemaname, tablename`);
26
+ return { type: 'query', fields: result.fields, rows: result.rows, rowCount: result.rowCount, command: 'SELECT' };
27
+ }
28
+ if (cmd === '\\d' && args.length > 0) {
29
+ const tableName = args[0];
30
+ const result = await client.query(`SELECT column_name AS "Column", data_type AS "Type",
31
+ CASE WHEN is_nullable = 'YES' THEN 'yes' ELSE 'no' END AS "Nullable",
32
+ column_default AS "Default"
33
+ FROM information_schema.columns
34
+ WHERE table_schema = 'public' AND table_name = $1
35
+ ORDER BY ordinal_position`, [tableName]);
36
+ if (result.rowCount === 0) {
37
+ return { type: 'query', fields: result.fields, rows: result.rows, rowCount: 0, command: 'SELECT' };
38
+ }
39
+ return { type: 'query', fields: result.fields, rows: result.rows, rowCount: result.rowCount, command: 'SELECT' };
40
+ }
41
+ if (cmd === '\\l') {
42
+ const result = await client.query(`SELECT datname AS "Name",
43
+ pg_catalog.pg_get_userbyid(datdba) AS "Owner",
44
+ pg_catalog.pg_encoding_to_char(encoding) AS "Encoding"
45
+ FROM pg_catalog.pg_database
46
+ ORDER BY 1`);
47
+ return { type: 'query', fields: result.fields, rows: result.rows, rowCount: result.rowCount, command: 'SELECT' };
48
+ }
49
+ return { type: 'unknown', command: cmd };
50
+ };
51
+ //# sourceMappingURL=meta-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-commands.js","sourceRoot":"","sources":["../../../src/commands/database/meta-commands.ts"],"names":[],"mappings":"AAQA,MAAM,SAAS,GAAG;;;;;;;;;;8BAUY,CAAA;AAE9B,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAAE,KAAa,EAAE,MAAc,EAA8B,EAAE;IACpG,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAE3C,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IACzB,CAAC;IAED,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;IAC1C,CAAC;IAED,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B;;;sCAGgC,CACjC,CAAA;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IAClH,CAAC;IAED,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B;;;;;iCAK2B,EAC3B,CAAC,SAAS,CAAC,CACZ,CAAA;QACD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;QACpG,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IAClH,CAAC;IAED,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B;;;;kBAIY,CACb,CAAA;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IAClH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAA;AAC1C,CAAC,CAAA"}
@@ -0,0 +1,8 @@
1
+ import BaseCommand from '../base-command.js';
2
+ export interface MigrationPullOptions {
3
+ branch?: string | true;
4
+ force?: boolean;
5
+ json?: boolean;
6
+ }
7
+ export declare const migrationPull: (options: MigrationPullOptions, command: BaseCommand) => Promise<void>;
8
+ //# sourceMappingURL=migration-pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-pull.d.ts","sourceRoot":"","sources":["../../../src/commands/database/migration-pull.ts"],"names":[],"mappings":"AAOA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAG5C,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAkED,eAAO,MAAM,aAAa,GAAU,SAAS,oBAAoB,EAAE,SAAS,WAAW,kBAkEtF,CAAA"}
@@ -0,0 +1,107 @@
1
+ import { rm, mkdir, writeFile } from 'fs/promises';
2
+ import { dirname, resolve, isAbsolute } from 'path';
3
+ import inquirer from 'inquirer';
4
+ import { log, logJson } from '../../utils/command-helpers.js';
5
+ import execa from '../../utils/execa.js';
6
+ import { resolveMigrationsDirectory } from './migration-new.js';
7
+ const getLocalGitBranch = async () => {
8
+ const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD']);
9
+ const branch = stdout.trim();
10
+ if (!branch || branch === 'HEAD') {
11
+ throw new Error('Could not determine the current git branch. Are you in a detached HEAD state?');
12
+ }
13
+ return branch;
14
+ };
15
+ const resolveBranch = async (branchOption) => {
16
+ if (branchOption === undefined) {
17
+ return undefined;
18
+ }
19
+ if (branchOption === true) {
20
+ return getLocalGitBranch();
21
+ }
22
+ return branchOption;
23
+ };
24
+ const fetchMigrations = async (command, branch) => {
25
+ const siteId = command.siteId;
26
+ if (!siteId) {
27
+ throw new Error('The project must be linked with netlify link before pulling migrations.');
28
+ }
29
+ const accessToken = command.netlify.api.accessToken;
30
+ if (!accessToken) {
31
+ throw new Error('You must be logged in with netlify login to pull migrations.');
32
+ }
33
+ const token = accessToken.replace('Bearer ', '');
34
+ const basePath = command.netlify.api.basePath;
35
+ const url = new URL(`${basePath}/sites/${encodeURIComponent(siteId)}/database/migrations`);
36
+ if (branch) {
37
+ url.searchParams.set('branch', branch);
38
+ }
39
+ const response = await fetch(url, {
40
+ headers: {
41
+ Authorization: `Bearer ${token}`,
42
+ },
43
+ });
44
+ if (!response.ok) {
45
+ const text = await response.text();
46
+ throw new Error(`Failed to fetch migrations (${String(response.status)}): ${text}`);
47
+ }
48
+ const data = (await response.json());
49
+ return data.migrations;
50
+ };
51
+ export const migrationPull = async (options, command) => {
52
+ const { force, json } = options;
53
+ const branch = await resolveBranch(options.branch);
54
+ const source = branch ?? 'production';
55
+ const migrations = await fetchMigrations(command, branch);
56
+ if (migrations.length === 0) {
57
+ if (json) {
58
+ logJson({ migrations_pulled: 0, branch: source });
59
+ }
60
+ else {
61
+ log(`No migrations found for ${source}.`);
62
+ }
63
+ return;
64
+ }
65
+ const migrationsDirectory = resolveMigrationsDirectory(command);
66
+ if (!force) {
67
+ const { confirmed } = await inquirer.prompt([
68
+ {
69
+ type: 'confirm',
70
+ name: 'confirmed',
71
+ message: `This will overwrite all local migrations in ${migrationsDirectory} with ${String(migrations.length)} migration${migrations.length === 1 ? '' : 's'} from ${source}. Continue?`,
72
+ default: false,
73
+ },
74
+ ]);
75
+ if (!confirmed) {
76
+ log('Pull cancelled.');
77
+ return;
78
+ }
79
+ }
80
+ const canonicalMigrationsDir = resolve(migrationsDirectory);
81
+ await rm(canonicalMigrationsDir, { recursive: true, force: true });
82
+ for (const migration of migrations) {
83
+ if (isAbsolute(migration.path) || migration.path.split(/[/\\]/).includes('..')) {
84
+ throw new Error(`Migration path "${migration.path}" contains invalid path segments.`);
85
+ }
86
+ const filePath = resolve(canonicalMigrationsDir, migration.path);
87
+ if (!filePath.startsWith(canonicalMigrationsDir)) {
88
+ throw new Error(`Migration path "${migration.path}" resolves outside the migrations directory.`);
89
+ }
90
+ await mkdir(dirname(filePath), { recursive: true });
91
+ await writeFile(filePath, migration.content);
92
+ }
93
+ if (json) {
94
+ logJson({
95
+ migrations_pulled: migrations.length,
96
+ branch: source,
97
+ migrations: migrations.map((m) => m.name),
98
+ });
99
+ }
100
+ else {
101
+ log(`Pulled ${String(migrations.length)} migration${migrations.length === 1 ? '' : 's'} from ${source}:`);
102
+ for (const migration of migrations) {
103
+ log(` - ${migration.name}`);
104
+ }
105
+ }
106
+ };
107
+ //# sourceMappingURL=migration-pull.js.map