New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

neonctl

Package Overview
Dependencies
Maintainers
2
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

neonctl - npm Package Compare versions

Comparing version 1.13.0 to 1.14.0

4

commands/branches.js

@@ -5,3 +5,3 @@ import { writer } from '../writer.js';

import { retryOnLock } from '../api.js';
import { branchIdFromProps } from '../enrichers.js';
import { branchIdFromProps, fillSingleProject } from '../enrichers.js';
const BRANCH_FIELDS = ['id', 'name', 'created_at', 'updated_at'];

@@ -19,5 +19,5 @@ export const command = 'branches';

type: 'string',
demandOption: true,
},
})
.middleware(fillSingleProject)
.command('list', 'List branches', (yargs) => yargs, async (args) => await list(args))

@@ -24,0 +24,0 @@ .command('create', 'Create a branch', (yargs) => yargs.options({

import { EndpointType } from '@neondatabase/api-client';
import { branchIdFromProps } from '../enrichers.js';
export const command = 'connection-string <branch>';
import { branchIdFromProps, fillSingleProject } from '../enrichers.js';
export const command = 'connection-string [branch]';
export const aliases = ['cs'];
export const describe = 'Get connection string';
export const builder = (argv) => {
return argv.usage('usage: $0 connection-string <branch> [options]').options({
return argv
.usage('usage: $0 connection-string [branch] [options]')
.positional('branch', {
describe: 'Branch name or id. If ommited will use the primary branch',
type: 'string',
})
.options({
'project.id': {
type: 'string',
describe: 'Project ID',
demandOption: true,
},

@@ -16,3 +21,2 @@ 'role.name': {

describe: 'Role name',
demandOption: true,
},

@@ -22,3 +26,2 @@ 'database.name': {

describe: 'Database name',
demandOption: true,
},

@@ -35,7 +38,9 @@ pooled: {

},
});
})
.middleware(fillSingleProject);
};
export const handler = async (props) => {
const projectId = props.project.id;
const branchId = await branchIdFromProps(props);
const { data: { endpoints }, } = await props.apiClient.listProjectBranchEndpoints(props.project.id, branchId);
const { data: { endpoints }, } = await props.apiClient.listProjectBranchEndpoints(projectId, branchId);
const endpoint = endpoints.find((e) => e.type === EndpointType.ReadWrite);

@@ -45,3 +50,29 @@ if (!endpoint) {

}
const { data: password } = await props.apiClient.getProjectBranchRolePassword(props.project.id, endpoint.branch_id, props.role.name);
const role = props.role?.name ||
(await props.apiClient
.listProjectBranchRoles(projectId, branchId)
.then(({ data }) => {
if (data.roles.length === 0) {
throw new Error(`No roles found for the branch: ${branchId}`);
}
if (data.roles.length === 1) {
return data.roles[0].name;
}
throw new Error(`Multiple roles found for the branch, please provide one with the --role.name option: ${data.roles
.map((r) => r.name)
.join(', ')}`);
}));
const database = props.database?.name ||
(await props.apiClient
.listProjectBranchDatabases(projectId, branchId)
.then(({ data }) => {
if (data.databases.length === 0) {
throw new Error(`No databases found for the branch: ${branchId}`);
}
if (data.databases.length === 1) {
return data.databases[0].name;
}
throw new Error(`Multiple databases found for the branch, please provide one with the --database.name option: ${data.databases}`);
}));
const { data: password } = await props.apiClient.getProjectBranchRolePassword(props.project.id, endpoint.branch_id, role);
const host = props.pooled

@@ -51,4 +82,4 @@ ? endpoint.host.replace(endpoint.id, `${endpoint.id}-pooler`)

const connectionString = new URL(`postgres://${host}`);
connectionString.pathname = props.database.name;
connectionString.username = props.role.name;
connectionString.pathname = database;
connectionString.username = role;
connectionString.password = password.password;

@@ -55,0 +86,0 @@ if (props.prisma) {

@@ -72,2 +72,10 @@ import { describe } from '@jest/globals';

});
testCliCommand({
name: 'connection_string without any args should pass',
args: ['connection-string'],
mockDir: 'single_project',
expected: {
snapshot: true,
},
});
});
import { retryOnLock } from '../api.js';
import { branchIdFromProps } from '../enrichers.js';
import { branchIdFromProps, fillSingleProject } from '../enrichers.js';
import { databaseCreateRequest } from '../parameters.gen.js';

@@ -18,3 +18,2 @@ import { commandFailHandler } from '../utils.js';

type: 'string',
demandOption: true,
},

@@ -24,5 +23,5 @@ branch: {

type: 'string',
demandOption: true,
},
})
.middleware(fillSingleProject)
.command('list', 'List databases', (yargs) => yargs, async (args) => await list(args))

@@ -29,0 +28,0 @@ .command('create', 'Create a database', (yargs) => yargs.options(databaseCreateRequest), async (args) => await create(args))

@@ -0,1 +1,2 @@

import { fillSingleProject } from '../enrichers.js';
import { commandFailHandler } from '../utils.js';

@@ -15,5 +16,5 @@ import { writer } from '../writer.js';

type: 'string',
demandOption: true,
},
})
.middleware(fillSingleProject)
.command('list', 'List operations', (yargs) => yargs, async (args) => await list(args));

@@ -20,0 +21,0 @@ export const handler = (args) => {

import { retryOnLock } from '../api.js';
import { branchIdFromProps } from '../enrichers.js';
import { branchIdFromProps, fillSingleProject } from '../enrichers.js';
import { roleCreateRequest } from '../parameters.gen.js';

@@ -18,3 +18,2 @@ import { commandFailHandler } from '../utils.js';

type: 'string',
demandOption: true,
},

@@ -24,5 +23,5 @@ branch: {

type: 'string',
demandOption: true,
},
})
.middleware(fillSingleProject)
.command('list', 'List roles', (yargs) => yargs, async (args) => await list(args))

@@ -29,0 +28,0 @@ .command('create', 'Create a role', (yargs) => yargs.options(roleCreateRequest), async (args) => await create(args))

@@ -9,12 +9,41 @@ const HAIKU_REGEX = /^[a-z]+-[a-z]+-\d{6}$/;

if (!branchData) {
throw new Error(`Branch ${branch} not found`);
throw new Error(`Branch ${branch} not found.\nAvailable branches: ${data.branches
.map((b) => b.name)
.join(', ')}`);
}
return branchData.id;
};
export const branchIdFromProps = async (props) => branchIdResolve({
branch: 'branch' in props && typeof props.branch === 'string'
export const branchIdFromProps = async (props) => {
const branch = 'branch' in props && typeof props.branch === 'string'
? props.branch
: props.id,
apiClient: props.apiClient,
projectId: props.project.id,
});
: props.id;
if (branch) {
return await branchIdResolve({
branch,
apiClient: props.apiClient,
projectId: props.project.id,
});
}
const { data } = await props.apiClient.listProjectBranches(props.project.id);
const primaryBranch = data.branches.find((b) => b.primary);
if (primaryBranch) {
return primaryBranch.id;
}
throw new Error('No primary branch found');
};
export const fillSingleProject = async (props) => {
if (props.project) {
return props;
}
const { data } = await props.apiClient.listProjects({});
if (data.projects.length === 0) {
throw new Error('No projects found');
}
if (data.projects.length > 1) {
throw new Error(`Multiple projects found, please provide one with the --project.id option`);
}
return {
...props,
project: { id: data.projects[0].id },
};
};
export const isCi = () => {
return process.env.CI !== 'false' && Boolean(process.env.CI);
};
export const isDebug = () => {
return Boolean(process.env.DEBUG);
};

@@ -84,3 +84,6 @@ import yargs from 'yargs';

if (isAxiosError(err)) {
if (err.response?.status === 401) {
if (err.code === 'ECONNABORTED') {
log.error('Request timed out');
}
else if (err.response?.status === 401) {
log.error('Authentication failed, please run `neonctl auth`');

@@ -95,2 +98,3 @@ }

}
err.stack && log.degug('Stack: %s', err.stack);
process.exit(1);

@@ -97,0 +101,0 @@ });

import { format } from 'node:util';
import { isDebug } from './env.js';
export const log = {
degug: (...args) => {
if (isDebug()) {
process.stderr.write(`DEBUG: ${format(...args)}\n`);
}
},
info: (...args) => {

@@ -4,0 +10,0 @@ process.stderr.write(`INFO: ${format(...args)}\n`);

@@ -8,3 +8,3 @@ {

"type": "module",
"version": "1.13.0",
"version": "1.14.0",
"description": "CLI tool for NeonDB Cloud management",

@@ -11,0 +11,0 @@ "main": "index.js",

@@ -7,6 +7,6 @@ /* eslint-disable no-console */

import { join } from 'node:path';
const runMockServer = async () => new Promise((resolve) => {
const runMockServer = async (mockDir) => new Promise((resolve) => {
const app = express();
app.use(express.json());
app.use('/', emocks(join(process.cwd(), 'mocks')));
app.use('/', emocks(join(process.cwd(), 'mocks', mockDir)));
const server = app.listen(0);

@@ -18,7 +18,7 @@ server.on('listening', () => {

});
export const testCliCommand = ({ args, name, expected, }) => {
export const testCliCommand = ({ args, name, expected, mockDir = 'main', }) => {
let server;
describe(name, () => {
beforeAll(async () => {
server = await runMockServer();
server = await runMockServer(mockDir);
});

@@ -58,2 +58,5 @@ afterAll(async () => {

try {
if (code !== 0 && error) {
console.error(error);
}
expect(code).toBe(0);

@@ -60,0 +63,0 @@ if (code === 0 && expected) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc