insta 0.1.25 → 0.1.26
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/README.md +1 -1
- package/dist/commands/cron.js +3 -3
- package/dist/commands/domain.js +11 -15
- package/dist/commands/template.js +10 -9
- package/dist/index.js +7 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -229,7 +229,7 @@ build never reaches a production installer.
|
|
|
229
229
|
| `insta branch` | `create` · `list` · `switch` · `delete` · `merge` |
|
|
230
230
|
| `insta service` (`services`, `svc`) | `add` · `list` · `remove` · `rename` |
|
|
231
231
|
| `insta secrets` | Write `.env`, plus `list` · `set` · `unset` · `bind` · `unbind` · `bindings` · `sources` · `tree` |
|
|
232
|
-
| `insta domain` | Bought or bring-your-own: `attach` · `check` · `detach
|
|
232
|
+
| `insta domain` | Bought or bring-your-own: `attach` · `check` · `detach`. Domains already bought through InstaCloud: `list` · `status` · `records …` |
|
|
233
233
|
| `insta compute` | `start` · `stop` · `suspend` · `restart` · `status` · `scale` · `limits` · `volume` · `always-on` · `exec` · `ssh` · `repo` · `connect-repo` · `watch-paths` · `disconnect-repo` · `logs` · `metrics` |
|
|
234
234
|
| `insta postgres` | `url` (print the DSN) · `connect` (psql) · `stats` · `limits` · `restart` · `volume` · `always-on` · `private-access` · `public-access` · `logs` · `metrics` — every verb takes `[service]` |
|
|
235
235
|
| `insta redis` · `mysql` · `mongodb` | `query` · `status` · `limits` · `volume` · `always-on` · `logs` · `metrics` |
|
package/dist/commands/cron.js
CHANGED
|
@@ -165,11 +165,11 @@ export function jobShowLines(j, serviceName) {
|
|
|
165
165
|
// decrypts it. Saying so beats an empty "value" column that reads as "this header is set to
|
|
166
166
|
// nothing". Secret-backed headers get a row each, because the secret NAME is readable and is the
|
|
167
167
|
// thing an operator needs when a rotation or a missing secret is the question.
|
|
168
|
-
const refs =
|
|
169
|
-
const literal = j.request.headerNames.filter((n) => findHeader(
|
|
168
|
+
const refs = refsOf(j.request);
|
|
169
|
+
const literal = j.request.headerNames.filter((n) => findHeader(refs, n) === undefined);
|
|
170
170
|
const rows = [
|
|
171
171
|
...(literal.length ? [`${literal.join(', ')} (names only — values are encrypted at rest and never returned)`] : []),
|
|
172
|
-
...refs.map(([h, s]) => `${h} ← secret ${s} (resolved at send time)`),
|
|
172
|
+
...Object.entries(refs).map(([h, s]) => `${h} ← secret ${s} (resolved at send time)`),
|
|
173
173
|
];
|
|
174
174
|
if (!rows.length)
|
|
175
175
|
lines.push(' headers (none)');
|
package/dist/commands/domain.js
CHANGED
|
@@ -30,9 +30,6 @@ export async function domainSearch(keyword, opts, deps) {
|
|
|
30
30
|
return printJson(r);
|
|
31
31
|
for (const line of searchLines(r.results))
|
|
32
32
|
info(line);
|
|
33
|
-
const buyable = r.results.find((x) => x.purchasable);
|
|
34
|
-
if (buyable)
|
|
35
|
-
info(`buy one: insta domain buy ${buyable.domainName}`);
|
|
36
33
|
}
|
|
37
34
|
export async function domainBuy(name, opts, deps) {
|
|
38
35
|
const years = whole('--years', opts.years);
|
|
@@ -117,10 +114,10 @@ function domainLines(d, linked = true) {
|
|
|
117
114
|
out.push(` ${h.hostname.padEnd(w)} ${h.state}${h.service ? ` → ${h.service}` : ''}${h.reason ? ` — ${h.reason}` : ''}`);
|
|
118
115
|
return out;
|
|
119
116
|
}
|
|
120
|
-
function orderStatusLines(o
|
|
117
|
+
function orderStatusLines(o) {
|
|
121
118
|
const out = [`order ${o.id}: ${o.domainName} — ${o.status}${o.failedReason ? ` — ${o.failedReason}` : ''}`];
|
|
122
|
-
if (
|
|
123
|
-
out.push(
|
|
119
|
+
if (o.status === 'canceled')
|
|
120
|
+
out.push(' the checkout closed without payment');
|
|
124
121
|
return out;
|
|
125
122
|
}
|
|
126
123
|
export async function domainList(opts, deps) {
|
|
@@ -129,7 +126,7 @@ export async function domainList(opts, deps) {
|
|
|
129
126
|
if (opts.json)
|
|
130
127
|
return printJson(r);
|
|
131
128
|
if (!r.items.length)
|
|
132
|
-
return info('no domains bought through InstaCloud in this org
|
|
129
|
+
return info('no domains bought through InstaCloud in this org');
|
|
133
130
|
for (const d of r.items)
|
|
134
131
|
for (const line of domainLines(d, !opts.org))
|
|
135
132
|
info(line);
|
|
@@ -147,7 +144,7 @@ export async function domainStatus(name, opts, deps) {
|
|
|
147
144
|
die(`${host} was not bought through this org`);
|
|
148
145
|
if (opts.json)
|
|
149
146
|
return printJson({ domain, order });
|
|
150
|
-
for (const line of domain ? domainLines(domain, !opts.org) : orderStatusLines(order
|
|
147
|
+
for (const line of domain ? domainLines(domain, !opts.org) : orderStatusLines(order))
|
|
151
148
|
info(line);
|
|
152
149
|
}
|
|
153
150
|
// ---- nameservers and transferring out ----
|
|
@@ -369,10 +366,9 @@ export function zoneRecordLines(records) {
|
|
|
369
366
|
* into the zone itself — apexes included — instead of printing them for hand-copying. The zone is
|
|
370
367
|
* SEEDED by the provider's record scan, which is a heuristic: the review-then-switch contract
|
|
371
368
|
* (printed, and enforced by nothing else) is to compare `zone records` against the domain's current
|
|
372
|
-
* DNS
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* either way.
|
|
369
|
+
* DNS before re-pointing. A domain carrying live MX records is refused outright: a DNS move that
|
|
370
|
+
* can drop mail is never done implicitly. 202 approval_required in agent mode (zone.delegate); org
|
|
371
|
+
* admin either way.
|
|
376
372
|
*/
|
|
377
373
|
const orgArgOf = (opts) => (opts.org ? ` --org ${opts.org}` : '');
|
|
378
374
|
export async function zoneDelegate(domainName, opts, deps) {
|
|
@@ -391,7 +387,7 @@ export async function zoneDelegate(domainName, opts, deps) {
|
|
|
391
387
|
const z = res.body;
|
|
392
388
|
for (const line of zoneLines(z, opts.org))
|
|
393
389
|
info(line);
|
|
394
|
-
info(`the zone was seeded by a provider scan
|
|
390
|
+
info(`the zone was seeded by a provider scan, which can miss records. Check \`insta domain zone records ${z.domainName}${orgArgOf(opts)}\` against your current DNS, and only then switch the nameservers.`);
|
|
395
391
|
}
|
|
396
392
|
export async function zoneList(opts, deps) {
|
|
397
393
|
const { api, orgId } = await orgDeps(opts, deps);
|
|
@@ -412,7 +408,7 @@ export async function zoneList(opts, deps) {
|
|
|
412
408
|
if (opts.json)
|
|
413
409
|
return printJson(r);
|
|
414
410
|
if (!r.items.length)
|
|
415
|
-
return info('no delegated zones
|
|
411
|
+
return info('no delegated zones');
|
|
416
412
|
for (const z of r.items)
|
|
417
413
|
for (const line of zoneLines(z, opts.org))
|
|
418
414
|
info(line);
|
|
@@ -425,7 +421,7 @@ export async function zoneRecords(domainName, opts, deps) {
|
|
|
425
421
|
for (const line of zoneRecordLines(r.items))
|
|
426
422
|
info(line);
|
|
427
423
|
if (r.items.length)
|
|
428
|
-
info(
|
|
424
|
+
info('every type shows here. The provider scan can miss records, so compare them against your current DNS before switching nameservers');
|
|
429
425
|
}
|
|
430
426
|
/**
|
|
431
427
|
* Release a delegated zone: the platform prunes the records it published and deletes the managed
|
|
@@ -344,6 +344,9 @@ async function promptVariable(v) {
|
|
|
344
344
|
throw new CliCancel();
|
|
345
345
|
return answer.trim();
|
|
346
346
|
}
|
|
347
|
+
// The poll route is keyed by deployment id, not project: name the project so agent mode signs
|
|
348
|
+
// with the project-bound session (a bootstrap session is rejected as "for a different project").
|
|
349
|
+
const readDeployment = (api, projectId) => (id) => api.request('GET', `/template-deployments/${id}`, undefined, { projectId });
|
|
347
350
|
export async function templateDeploy(target, opts = {}, deps = {}) {
|
|
348
351
|
const given = parseSetFlags(opts.set ?? []); // a typo'd --set fails before any network access
|
|
349
352
|
// --json asked for parseable output: every human progress line is suppressed so stdout carries
|
|
@@ -424,9 +427,7 @@ export async function templateDeploy(target, opts = {}, deps = {}) {
|
|
|
424
427
|
for (const line of publicBucketLines(services))
|
|
425
428
|
info(line);
|
|
426
429
|
}
|
|
427
|
-
|
|
428
|
-
// with the project-bound session (a bootstrap session is rejected as "for a different project").
|
|
429
|
-
const dep = await watchDeployment((id) => api.request('GET', `/template-deployments/${id}`, undefined, { projectId: p.projectId }), deploymentId, quiet ? () => { } : info, deps.wait);
|
|
430
|
+
const dep = await watchDeployment(readDeployment(api, p.projectId), deploymentId, quiet ? () => { } : info, deps.wait);
|
|
430
431
|
if (opts.json)
|
|
431
432
|
return printJson(source ? { source, ...dep } : dep);
|
|
432
433
|
info(`template ${codeLabel} deployed to branch ${branchName}`);
|
|
@@ -526,10 +527,10 @@ export async function templateUpgrade(service, opts = {}, deps = {}) {
|
|
|
526
527
|
const branchName = opts.branch ?? p.branch;
|
|
527
528
|
const ask = deps.ask ?? promptVariable;
|
|
528
529
|
const target = await deploymentOfService(api, p.projectId, branchName, service, 'upgrade');
|
|
529
|
-
// The
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
//
|
|
530
|
+
// The preview route is keyed by deployment id, not project, so it names the project as
|
|
531
|
+
// readDeployment does. It is a GET and raises coded 409s of its own (template_superseded among
|
|
532
|
+
// them), so it gets the same reading as the POST rather than the raw "<sentence> (HTTP 409)" the
|
|
533
|
+
// guard prints.
|
|
533
534
|
let plan;
|
|
534
535
|
try {
|
|
535
536
|
;
|
|
@@ -576,7 +577,7 @@ export async function templateUpgrade(service, opts = {}, deps = {}) {
|
|
|
576
577
|
const deploymentId = res.body.deploymentId ?? (res.body.deployment ?? res.body).id;
|
|
577
578
|
if (!quiet)
|
|
578
579
|
info(`upgrading ${service} to ${plan.to_version} (${deploymentId})`);
|
|
579
|
-
const dep = await watchDeployment((
|
|
580
|
+
const dep = await watchDeployment(readDeployment(api, p.projectId), deploymentId, quiet ? () => { } : info, deps.wait);
|
|
580
581
|
if (quiet)
|
|
581
582
|
return printJson(dep);
|
|
582
583
|
info(`${service} is on ${plan.to_version}`);
|
|
@@ -635,7 +636,7 @@ export async function templateRollback(service, opts = {}, deps = {}) {
|
|
|
635
636
|
return;
|
|
636
637
|
const deploymentId = res.body.deploymentId ?? (res.body.deployment ?? res.body).id;
|
|
637
638
|
out(`rolling ${service} back (${deploymentId})`);
|
|
638
|
-
const dep = await watchDeployment((
|
|
639
|
+
const dep = await watchDeployment(readDeployment(api, p.projectId), deploymentId, out, deps.wait);
|
|
639
640
|
if (quiet)
|
|
640
641
|
return printJson(dep);
|
|
641
642
|
info(`${service} is back on ${(dep.deployment ?? dep).template_version ?? 'its previous version'}`);
|
package/dist/index.js
CHANGED
|
@@ -273,11 +273,12 @@ cron.command('runs <name>').description('Run history, most recent first: status,
|
|
|
273
273
|
cron.command('preview <expression>').description('Validate an expression and print its next five UTC fire times — answered by the same parser the scheduler uses. Exits 1 when the expression is invalid')
|
|
274
274
|
.option('--json').action(guard((expression, o) => cronCmd.cronPreview(expression, o)));
|
|
275
275
|
// ---- domain (bought here, or bring your own; hostnames on compute services; DNS of bought zones) ----
|
|
276
|
-
const dom = program.command('domain').description('Domains:
|
|
277
|
-
|
|
276
|
+
const dom = program.command('domain').description('Domains: attach, check and detach hostnames on compute services, and manage domains already bought through InstaCloud');
|
|
277
|
+
// search, buy and zone delegate are hidden while the platform pauses new orders and BYO delegation.
|
|
278
|
+
dom.command('search <keyword>', { hidden: true }).description('Search purchasable names with prices (a label like "myapp" or a full name like "myapp.com")')
|
|
278
279
|
.option('--tlds <list>', 'comma-separated TLDs to include').option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
279
280
|
.action(guard((keyword, o) => domainCmd.domainSearch(keyword, o)));
|
|
280
|
-
dom.command('buy <name>').description('Buy a domain — pay at the printed Stripe Checkout link. It serves nothing until you attach it (gated: domain.purchase)')
|
|
281
|
+
dom.command('buy <name>', { hidden: true }).description('Buy a domain — pay at the printed Stripe Checkout link. It serves nothing until you attach it (gated: domain.purchase)')
|
|
281
282
|
.option('--years <n>', 'registration term in years (default 1)')
|
|
282
283
|
.option('--no-open', 'print the checkout URL instead of opening a browser').option('--json')
|
|
283
284
|
.action(guard((name, o) => domainCmd.domainBuy(name, o)));
|
|
@@ -309,14 +310,14 @@ ns.command('set <domain> <nameservers...>').description("Delegate the zone to na
|
|
|
309
310
|
ns.command('reset <domain>').description("Put the zone back on the registrar's own nameservers — from your own delegation or from an InstaCloud-managed zone alike; a hostname `set` took down is re-attached with `insta domain attach`, one a managed zone was serving re-verifies on its own")
|
|
310
311
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
311
312
|
.action(guard((domain, o) => domainCmd.domainNameserversReset(domain, o)));
|
|
312
|
-
const zone = dom.command('zone').description("Bring-your-own domains
|
|
313
|
-
zone.command('delegate <domain>').description("Delegate a domain you own elsewhere: builds its managed zone (seeded by a provider record scan — a HEURISTIC, so review `zone records`
|
|
313
|
+
const zone = dom.command('zone').description("Bring-your-own domains already delegated to an InstaCloud-managed zone: list them, review their records, or release them. For a hostname under a domain you own elsewhere, `insta domain attach` prints the records to add in your own DNS");
|
|
314
|
+
zone.command('delegate <domain>', { hidden: true }).description("Delegate a domain you own elsewhere: builds its managed zone (seeded by a provider record scan — a HEURISTIC, so review `zone records` against your current DNS BEFORE switching nameservers) and answers the two nameservers to set at your registrar. A domain carrying live MX records is refused — move mail first or keep the records path (org admin; gated: zone.delegate — agent mode gates from a linked project, an unlinked --org call falls under org administration instead)")
|
|
314
315
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
315
316
|
.action(guard((domain, o) => domainCmd.zoneDelegate(domain, o)));
|
|
316
317
|
zone.command('list').description("The org's delegated zones: which are still waiting for the nameserver switch and which are serving")
|
|
317
318
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
318
319
|
.action(guard((o) => domainCmd.zoneList(o)));
|
|
319
|
-
zone.command('records <domain>').description("Every record in the delegated zone
|
|
320
|
+
zone.command('records <domain>').description("Every record in the delegated zone, for review before you switch nameservers. The provider scan seeds common records but is not exhaustive, so compare it against your current DNS first")
|
|
320
321
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
321
322
|
.action(guard((domain, o) => domainCmd.zoneRecords(domain, o)));
|
|
322
323
|
zone.command('release <domain>').description("Release a delegated zone: the platform's records are pruned and the zone deleted. Point the nameservers back at your own provider; hostnames re-verify on the records path (org admin; gated: zone.delegate — agent mode gates from a linked project, an unlinked --org call falls under org administration instead)")
|