insta 0.0.55 → 0.0.57
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.
- package/dist/api.js +6 -3
- package/dist/commands/feedback.js +2 -13
- package/dist/commands/manifest.js +4 -1
- package/dist/commands/services.js +21 -5
- package/dist/index.js +6 -18
- package/dist/version.js +14 -0
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { readGlobal, writeGlobal, readProject, writeProject } from './config.js';
|
|
4
4
|
import { autoResolveProject, promptChoice } from './resolve-project.js';
|
|
5
5
|
import { die } from './util.js';
|
|
6
|
+
import { USER_AGENT } from './version.js';
|
|
6
7
|
export class ApiError extends Error {
|
|
7
8
|
status;
|
|
8
9
|
body;
|
|
@@ -24,8 +25,10 @@ export function storeApiKeyCredential(cfg, token, user) {
|
|
|
24
25
|
}
|
|
25
26
|
export class ApiClient {
|
|
26
27
|
cfg;
|
|
27
|
-
|
|
28
|
+
fetchImpl;
|
|
29
|
+
constructor(cfg, fetchImpl = fetch) {
|
|
28
30
|
this.cfg = cfg;
|
|
31
|
+
this.fetchImpl = fetchImpl;
|
|
29
32
|
}
|
|
30
33
|
static async load() { return new ApiClient(await readGlobal()); }
|
|
31
34
|
get apiUrl() { return this.cfg.apiUrl; }
|
|
@@ -70,10 +73,10 @@ export class ApiClient {
|
|
|
70
73
|
return r;
|
|
71
74
|
}
|
|
72
75
|
async fetch(method, path, body, auth) {
|
|
73
|
-
const headers = { 'Content-Type': 'application/json', 'Insta-Hints': '1' };
|
|
76
|
+
const headers = { 'Content-Type': 'application/json', 'Insta-Hints': '1', 'User-Agent': USER_AGENT };
|
|
74
77
|
if (auth && this.cfg.accessToken)
|
|
75
78
|
headers.Authorization = `Bearer ${this.cfg.accessToken}`;
|
|
76
|
-
const res = await
|
|
79
|
+
const res = await this.fetchImpl(this.apiUrl + path, {
|
|
77
80
|
method,
|
|
78
81
|
headers,
|
|
79
82
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
@@ -14,6 +14,7 @@ import { readGlobal, readProject } from '../config.js';
|
|
|
14
14
|
import { envForApiUrl } from '../env.js';
|
|
15
15
|
import { info, printJson, CliCancel } from '../util.js';
|
|
16
16
|
import { clean } from '../redact.js';
|
|
17
|
+
import { cliVersion } from '../version.js';
|
|
17
18
|
export const TYPES = ['bug', 'feature-request', 'friction', 'other'];
|
|
18
19
|
export const COMPONENTS = ['cli', 'mcp', 'platform', 'skills', 'docs', 'other'];
|
|
19
20
|
export const SEVERITIES = ['blocker', 'major', 'minor'];
|
|
@@ -42,18 +43,6 @@ const FEEDBACK_INGEST_TOKEN = process.env.INSTA_FEEDBACK_TOKEN || 'insta-feedbac
|
|
|
42
43
|
// An expired deadline is reported as UNCONFIRMED, not failed — the report may well be stored.
|
|
43
44
|
const FEEDBACK_TIMEOUT_MS = 15_000;
|
|
44
45
|
const MAX_FILE_BYTES = 256 * 1024;
|
|
45
|
-
function resolveCliVersion() {
|
|
46
|
-
// Same resolution as index.ts: the standalone binary bakes INSTA_CLI_VERSION via --define;
|
|
47
|
-
// npm/node reads the installed package.json next to dist/.
|
|
48
|
-
if (process.env.INSTA_CLI_VERSION)
|
|
49
|
-
return process.env.INSTA_CLI_VERSION;
|
|
50
|
-
try {
|
|
51
|
-
return JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return '0.0.0';
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
46
|
function requireEnum(value, allowed, flag) {
|
|
58
47
|
if (!allowed.includes(value)) {
|
|
59
48
|
throw new Error(`${flag} must be one of: ${allowed.join(', ')}`);
|
|
@@ -206,7 +195,7 @@ export async function feedback(opts, deps = {}) {
|
|
|
206
195
|
// transport-failure shapes) instead of guard()'s plaintext stderr line.
|
|
207
196
|
let payload;
|
|
208
197
|
try {
|
|
209
|
-
payload = await buildPayload(opts, { cliVersion: deps.cliVersion ??
|
|
198
|
+
payload = await buildPayload(opts, { cliVersion: deps.cliVersion ?? cliVersion() });
|
|
210
199
|
}
|
|
211
200
|
catch (e) {
|
|
212
201
|
if (!opts.json)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ApiClient, requireProject } from '../api.js';
|
|
2
|
+
import { pgBadge } from './services.js';
|
|
2
3
|
import { info, printJson } from '../util.js';
|
|
3
4
|
/**
|
|
4
5
|
* The label that names WHERE a resource runs.
|
|
@@ -21,7 +22,9 @@ export function resourceLabel(r) {
|
|
|
21
22
|
// One `manifest` resource line. Pure, so the label is unit-tested without a network mock.
|
|
22
23
|
export function resourceLine(r) {
|
|
23
24
|
const where = r.ref?.url ?? r.ref?.bucket ?? r.ref?.neonProjectId ?? '';
|
|
24
|
-
|
|
25
|
+
// Database rows only: the platform stamps ref.pgVersion on insta-db (and legacy neon) resources.
|
|
26
|
+
const pg = r.kind === 'insta-db' || r.kind === 'neon' ? pgBadge(r.ref?.pgVersion) : '';
|
|
27
|
+
return ` - ${resourceLabel(r)} ${where}${pg} [${r.status}]`;
|
|
25
28
|
}
|
|
26
29
|
// Agent-legible view of each environment's databases / storage / compute.
|
|
27
30
|
export async function manifest(opts) {
|
|
@@ -118,10 +118,7 @@ export async function servicesAdd(type, name, opts = {}) {
|
|
|
118
118
|
if (opts.json)
|
|
119
119
|
return printJson(res.body.service);
|
|
120
120
|
const svc = res.body.service;
|
|
121
|
-
|
|
122
|
-
const img = svc.image ? ` running ${svc.image}${svc.port ? `:${svc.port}` : ''}` : '';
|
|
123
|
-
const vol = svc.volume_gib ? ` vol ${svc.volume_gib}Gi at /data` : '';
|
|
124
|
-
info(`added ${type} service ${name} on ${branch ?? 'default'} (${svc.id})${access}${svc.region ? ` ${svc.region}` : ''}${img}${vol}${svc.domain ? ` — ${svc.domain}` : ''}`);
|
|
121
|
+
info(serviceAddedLine(type, name, branch, svc));
|
|
125
122
|
// Discoverability: the DB is directly dialable, but its DSN is deliberately absent from the
|
|
126
123
|
// general `insta secrets` bundle — without this line nothing in the product says how to reach it.
|
|
127
124
|
if (type === 'postgres') {
|
|
@@ -132,13 +129,32 @@ export async function servicesAdd(type, name, opts = {}) {
|
|
|
132
129
|
}
|
|
133
130
|
renderNextActions(res.body.nextActions);
|
|
134
131
|
}
|
|
132
|
+
// The `services add` success line. Pure, so the badge's placement is unit-tested: a template string
|
|
133
|
+
// nothing asserts on silently loses a segment.
|
|
134
|
+
export function serviceAddedLine(type, name, branch, svc) {
|
|
135
|
+
const access = svc.type === 'storage' ? ` [${svc.public ? 'public' : 'private'}]` : '';
|
|
136
|
+
const img = svc.image ? ` running ${svc.image}${svc.port ? `:${svc.port}` : ''}` : '';
|
|
137
|
+
const vol = svc.volume_gib ? ` vol ${svc.volume_gib}Gi at /data` : '';
|
|
138
|
+
// The major belongs next to the connect hint: it decides which psql/pg_dump to reach for.
|
|
139
|
+
const pg = svc.type === 'postgres' ? pgBadge(svc.pg_version) : '';
|
|
140
|
+
return `added ${type} service ${name} on ${branch ?? 'default'} (${svc.id})${access}${svc.region ? ` ${svc.region}` : ''}${img}${vol}${pg}${svc.domain ? ` — ${svc.domain}` : ''}`;
|
|
141
|
+
}
|
|
142
|
+
// ` pg <major>` for a postgres row, or '' when the platform sent nothing usable. The field arrives
|
|
143
|
+
// as untyped API JSON: only a positive integer renders, so a malformed or nonsense value (true,
|
|
144
|
+
// '16', 16.4, 0, -1) can never print as a version an agent would pick tooling by.
|
|
145
|
+
export function pgBadge(v) {
|
|
146
|
+
return typeof v === 'number' && Number.isInteger(v) && v > 0 ? ` pg ${v}` : '';
|
|
147
|
+
}
|
|
135
148
|
// Render one `services list` row. Pure, so it's unit-tested without a network mock (mirrors
|
|
136
149
|
// billingLines in billing.ts). Compute rows show the running image when the platform reports one.
|
|
137
150
|
export function serviceListLine(s) {
|
|
138
151
|
const extra = s.type === 'compute'
|
|
139
152
|
? ` x${s.machine_count}${s.volume_gib ? ` vol ${s.volume_gib}Gi` : ''}${s.image ? ` running ${s.image}${s.port ? `:${s.port}` : ''}` : ''}`
|
|
140
153
|
: ['redis', 'mysql', 'mongodb'].includes(s.type) ? ` tcp/${s.port ?? defaultDatabasePort(s.type)}${s.volume_gib ? ` vol ${s.volume_gib}Gi` : ''}`
|
|
141
|
-
: s.type === 'storage' ? ` ${s.public ? 'public' : 'private'}`
|
|
154
|
+
: s.type === 'storage' ? ` ${s.public ? 'public' : 'private'}`
|
|
155
|
+
// Postgres major, so the reader picks matching pg_dump/psql BEFORE connecting (a newer client
|
|
156
|
+
// dumps statements an older server cannot restore). Older platforms send no pg_version.
|
|
157
|
+
: s.type === 'postgres' ? pgBadge(s.pg_version) : '';
|
|
142
158
|
return `${s.type}/${s.name} [${s.status}]${extra}${s.domain ? ` ${s.domain}` : ''} ${s.id}`;
|
|
143
159
|
}
|
|
144
160
|
export async function servicesList(opts) {
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
2
|
import { Command } from 'commander';
|
|
4
3
|
import { ApiError } from './api.js';
|
|
5
4
|
import { CliCancel, CliExit, fail, relayedExitCode } from './util.js';
|
|
6
5
|
import { trackCommand } from './telemetry.js';
|
|
6
|
+
import { cliVersion } from './version.js';
|
|
7
7
|
import * as auth from './commands/auth.js';
|
|
8
8
|
import * as envCmd_ from './commands/env.js';
|
|
9
9
|
import { ENV_NAMES } from './env.js';
|
|
@@ -52,7 +52,7 @@ const guard = (fn) => async (...a) => {
|
|
|
52
52
|
}
|
|
53
53
|
await trackCommand(a[a.length - 1], a.slice(0, -2), {
|
|
54
54
|
error, durationMs: Date.now() - started, exitCode: Number(process.exitCode ?? 0), childExitCode: relayedExitCode(),
|
|
55
|
-
},
|
|
55
|
+
}, cliVersion());
|
|
56
56
|
};
|
|
57
57
|
const program = new Command();
|
|
58
58
|
// Positional options: some command groups (e.g. `secrets`, `billing`) declare a flag (like
|
|
@@ -63,19 +63,7 @@ const program = new Command();
|
|
|
63
63
|
// group's own options only match before the subcommand name, so occurrences after it are matched
|
|
64
64
|
// against the subcommand's own (identically-named) option instead.
|
|
65
65
|
program.enablePositionalOptions();
|
|
66
|
-
|
|
67
|
-
// the installed package.json (npm/node — ../package.json sits beside dist/) → 0.0.0.
|
|
68
|
-
function resolveVersion() {
|
|
69
|
-
if (process.env.INSTA_CLI_VERSION)
|
|
70
|
-
return process.env.INSTA_CLI_VERSION;
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return '0.0.0';
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
program.name('insta').description('InstaCloud CLI — manage projects, branches, secrets, deploys').version(resolveVersion());
|
|
66
|
+
program.name('insta').description('InstaCloud CLI — manage projects, branches, secrets, deploys').version(cliVersion());
|
|
79
67
|
// ---- auth ----
|
|
80
68
|
program.command('login').description('Log in — bare: sign in from your browser (any account type); or --email <email> + password, --oauth <github|google>, --device (headless), --api-key <insta_…> (headless, durable token)')
|
|
81
69
|
.option('--email <email>', 'account email (email + password login)')
|
|
@@ -366,10 +354,10 @@ program.command('feedback')
|
|
|
366
354
|
.action(guard((o) => feedbackCmd.feedback(o)));
|
|
367
355
|
// ---- self-update ----
|
|
368
356
|
program.command('upgrade').description('Update the insta CLI to the latest release (binary or npm install)')
|
|
369
|
-
.action(guard(() => selfUpdate.upgrade(
|
|
357
|
+
.action(guard(() => selfUpdate.upgrade(cliVersion())));
|
|
370
358
|
program.command('autoupdate [mode]').description('Show or set auto-update: on | off (default: on while pre-1.0)')
|
|
371
359
|
.action(guard((mode) => selfUpdate.autoupdate(mode)));
|
|
372
|
-
program.command('__update-check', { hidden: true }).action(guard(() => selfUpdate.backgroundCheck(
|
|
373
|
-
selfUpdate.maybeUpdate(
|
|
360
|
+
program.command('__update-check', { hidden: true }).action(guard(() => selfUpdate.backgroundCheck(cliVersion())));
|
|
361
|
+
selfUpdate.maybeUpdate(cliVersion(), process.argv);
|
|
374
362
|
program.parseAsync(computeArgv);
|
|
375
363
|
//# sourceMappingURL=index.js.map
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
// bun build --define bakes INSTA_CLI_VERSION into the standalone binary, which has no package.json to read.
|
|
3
|
+
export function cliVersion() {
|
|
4
|
+
if (process.env.INSTA_CLI_VERSION)
|
|
5
|
+
return process.env.INSTA_CLI_VERSION;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return '0.0.0';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export const USER_AGENT = `insta-cli/${cliVersion()}`;
|
|
14
|
+
//# sourceMappingURL=version.js.map
|