Sign In

insta

Package Overview
Dependencies
Maintainers
3
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

insta - npm Package Compare versions

Comparing version
0.0.28
to
0.0.29
+59
-0
dist/commands/db.js

@@ -123,2 +123,61 @@ import { ApiClient, ApiError, requireProject } from '../api.js';

// next release, so depending on them here would be a scheduled breakage.
// Bytes → human units, one decimal above KiB. Local because the metrics payload is the only
// bytes-denominated read in this file (fmtMib serves the MiB-denominated resize path).
export function fmtBytes(n) {
if (n < 1024)
return `${n} B`;
const units = ['KiB', 'MiB', 'GiB', 'TiB'];
let v = n / 1024;
let i = 0;
while (v >= 1024 && i < units.length - 1) {
v /= 1024;
i++;
}
return `${v.toFixed(1)} ${units[i]}`;
}
// Human-readable stats lines from GET /database/metrics. Pure seam for tests. "—" for anything
// unmeasured (old platform, suspended instance, no cache traffic yet) — never a fake 0: the
// platform omits cacheHitRatio and sends max 0 in exactly those cases.
export function dbStatsLines(group, body) {
const c = body?.connections ?? {};
const max = typeof c.max === 'number' && c.max > 0 ? c.max : null;
const total = typeof c.total === 'number' ? c.total : null;
const conn = total === null ? '—'
: (max === null ? String(total) : `${total} / ${max}`)
+ (typeof c.active === 'number' && max !== null ? ` (${c.active} active)` : '');
const ratio = body?.cacheHitRatio;
const cache = typeof ratio === 'number' ? `${(ratio * 100).toFixed(1)}%` : '—';
const size = typeof body?.dbSizeBytes === 'number' ? fmtBytes(body.dbSizeBytes) : '—';
const bits = [
typeof body?.state === 'string' ? body.state : null,
typeof body?.serverVersion === 'string' && body.serverVersion ? `PG ${body.serverVersion}` : null,
].filter(Boolean);
const state = bits.length ? ` (${bits.join(' · ')})` : '';
return [
`postgres ${group}${state}`,
` connections ${conn}`,
` cache hit ${cache}`,
` size ${size}`,
];
}
// Point-in-time stats snapshot for a postgres service: connections vs the server's ceiling, cache
// hit rate, database size. Read-only. insta-db-backed: a suspended instance answers from the
// provider's control plane (shown as "(suspended)" with structural zeros), never dialed.
// Neon-backed: the platform reads over a direct SQL connection, so a one-shot call may wake a
// suspended endpoint — acceptable for an explicit command, which is why nothing here polls.
export async function dbStats(opts) {
const api = await ApiClient.load();
const p = await requireProject();
const qs = new URLSearchParams();
const branch = opts.branch ?? p.branch;
if (branch)
qs.set('branch', branch);
if (opts.group)
qs.set('group', opts.group);
const res = await api.rawRequest('GET', `/projects/${p.projectId}/database/metrics${qs.toString() ? `?${qs}` : ''}`);
if (opts.json)
return printJson(res.body);
for (const line of dbStatsLines(opts.group ?? 'default', res.body))
info(line);
}
export function dbVolumeLines(group, body) {

@@ -125,0 +184,0 @@ const gib = typeof body?.volumeGib === 'number' ? `${body.volumeGib}Gi` : (typeof body?.volumeSize === 'string' ? body.volumeSize : undefined);

+54
-4

@@ -11,2 +11,54 @@ import { ApiClient, requireProject } from '../api.js';

}
// One printed series line. Pure seam so the formatting is testable without a backend.
//
// Byte-rate series (compute's egress/ingress) arrive as raw bytes per second, which is unreadable at
// real traffic volumes — 20480031 bytes/s is 20 MB/s. Percent and vCPU units are already
// human-sized, so only bytes and byte rates get scaled.
export function metricLine(s) {
const last = s.points?.[s.points.length - 1];
const value = last ? formatMetricValue(last[1], s.unit) : 'n/a';
const unit = s.unit && !isScaled(s.unit) ? ` (${s.unit})` : '';
return `${s.name}${unit}: ${value} [${s.points?.length ?? 0} points]`;
}
// The platform's unit strings are the contract here (`bytes` for memory/storage, `bytes/s` for
// egress/ingress — src/adapters/fly.ts and insta-db.ts). Matching them loosely is deliberate: an
// unrecognised unit fails SILENTLY back to the raw 8-digit number this scaling exists to fix, so a
// casing or spacing change on the platform side must not be enough to regress it.
function scaleOf(unit) {
const u = unit?.trim().toLowerCase();
if (u === 'bytes' || u === 'byte' || u === 'b')
return 'bytes';
if (u === 'bytes/s' || u === 'byte/s' || u === 'b/s' || u === 'bytes/sec')
return 'bytes/s';
return undefined;
}
function isScaled(unit) {
return scaleOf(unit) !== undefined;
}
function formatMetricValue(v, unit) {
if (!Number.isFinite(v))
return 'n/a';
const scale = scaleOf(unit);
// Traffic scales by 1000 because egress is BILLED per decimal GB (`bytes / 1e9`, platform
// src/adapters/fly.ts) — a 1024-based "GB/s" would sit ~7% off the invoice. Memory and storage
// stay binary: those ceilings are provisioned in GiB. Same split as the console.
if (scale === 'bytes')
return humanBytes(v, 1024);
if (scale === 'bytes/s')
return `${humanBytes(v, 1000)}/s`;
return String(v);
}
function humanBytes(v, base) {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let value = v;
let i = 0;
while (Math.abs(value) >= base && i < units.length - 1) {
value /= base;
i += 1;
}
// Sub-KB values keep their integer form (`512 B`, not `512.0 B`), but a RATE is fractional —
// PromQL rate() of a byte counter yields things like 342.857142, which must not print in full.
const shown = i === 0 && Number.isInteger(value) ? String(value) : value.toFixed(1);
return `${shown} ${units[i]}`;
}
// insta metrics <db|compute> [group]

@@ -23,6 +75,4 @@ export async function metrics(component, group, opts) {

return info('(no series)');
for (const s of res.series) {
const last = s.points?.[s.points.length - 1];
info(`${s.name}${s.unit ? ` (${s.unit})` : ''}: ${last ? last[1] : 'n/a'} [${s.points?.length ?? 0} points]`);
}
for (const s of res.series)
info(metricLine(s));
}

@@ -29,0 +79,0 @@ // Customer-facing name for each internal billing dimension (the platform stores RAM as `ram`).

@@ -183,2 +183,5 @@ #!/usr/bin/env node

.action(guard((o) => dbCmd.dbLimits(o)));
db.command('stats').description("Postgres stats snapshot: connections vs the server's max (active count), cache hit rate, database size. insta-db-backed services answer without waking a suspended instance")
.option('--json').option('--branch <branch>', 'branch (default: current)').option('--group <g>', 'postgres service name (default: the sole/default one)')
.action(guard((o) => dbCmd.dbStats(o)));
db.command('always-on <mode>').description('Set a postgres service always-on (mode: on|off). on = instance stays warm, no cold starts; off = default scale-to-zero (idle instance suspends; first connection cold-starts). insta-db-backed services only')

@@ -185,0 +188,0 @@ .option('--json').option('--branch <branch>', 'branch (default: current)').option('--group <g>', 'postgres service name (default: the sole/default one)')

+1
-1
{
"name": "insta",
"version": "0.0.28",
"version": "0.0.29",
"type": "module",

@@ -5,0 +5,0 @@ "description": "InstaCloud CLI — a thin client of the platform control-plane API.",