insta 0.0.79 → 0.0.80

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.
@@ -5,7 +5,11 @@ import { cycleLine, dimensionLines } from './metrics.js';
5
5
  export async function resolveOrgId(opts) {
6
6
  if (opts.org)
7
7
  return opts.org;
8
- return (await requireProject()).orgId;
8
+ // `ProjectConfig.orgId` is typed string but INSTA_PROJECT_ID resolves a project with no org.
9
+ const orgId = (await requireProject()).orgId;
10
+ if (!orgId)
11
+ die('INSTA_PROJECT_ID names no organization — set INSTA_ORG_ID, or pass --org <id>');
12
+ return orgId;
9
13
  }
10
14
  // Format the billing overview into printable lines (pure, so it's unit-testable).
11
15
  // `org` is the caller's --org, echoed into the portal hint: `billing` and `billing portal` resolve
@@ -36,7 +36,10 @@ export async function domainSearch(keyword, opts, deps) {
36
36
  export async function domainBuy(name, opts, deps) {
37
37
  const years = whole('--years', opts.years);
38
38
  const { api, project: p } = await domainDeps(deps);
39
- const res = await api.rawRequest('POST', `/projects/${p.projectId}/domains/orders`, { domainName: name, years });
39
+ const orgId = p.orgId || die('this project link names no organization — set INSTA_ORG_ID');
40
+ // The org route still signs for a PROJECT in agent mode: `domain.purchase` is read there, and a
41
+ // bootstrap session names none, so the platform refuses it.
42
+ const res = await api.rawRequest('POST', `/orgs/${orgId}/domains/orders`, { domainName: name, years }, { projectId: p.projectId });
40
43
  if (handleApproval(res, opts.json))
41
44
  return;
42
45
  if (opts.json)
@@ -57,12 +60,13 @@ export function ownerOf(host, owned) {
57
60
  */
58
61
  export async function domainAttach(host, opts, deps) {
59
62
  const { api, project: p } = await domainDeps(deps);
63
+ const orgId = p.orgId || die('this project link names no organization — set INSTA_ORG_ID');
60
64
  const name = host.trim().toLowerCase();
61
- const { items } = await api.request('GET', `/projects/${p.projectId}/domains`);
65
+ const { items } = await api.request('GET', `/orgs/${orgId}/domains`);
62
66
  const owner = ownerOf(name, items);
63
67
  if (!owner) {
64
68
  // The domains list holds registered names only; a bought name still registering is an order.
65
- const { items: orders } = await api.request('GET', `/projects/${p.projectId}/domains/orders`);
69
+ const { items: orders } = await api.request('GET', `/orgs/${orgId}/domains/orders`);
66
70
  const o = ownerOf(name, orders);
67
71
  if (o)
68
72
  die(`${o.domainName} is not registered yet — its order is ${o.status}: insta domain status ${o.domainName}`);
@@ -83,10 +87,10 @@ export async function domainAttach(host, opts, deps) {
83
87
  info(`then: insta domain status ${owner.domainName}`);
84
88
  }
85
89
  // ---- list / status ----
86
- function domainLines(d) {
90
+ function domainLines(d, linked = true) {
87
91
  const out = [`${d.domainName} ${d.status}${d.expiresAt ? ` (expires ${d.expiresAt.slice(0, 10)}${d.autorenew ? ', auto-renews' : ''})` : ''}`];
88
92
  // Vacuously true for a domain with no hostnames, which is every domain until something attaches.
89
- if (d.hostnames.every((h) => h.state === 'failed')) {
93
+ if (linked && d.hostnames.every((h) => h.state === 'failed')) {
90
94
  const names = d.hostnames.map((h) => h.hostname);
91
95
  // Attaching the bought name itself re-attaches its www.
92
96
  const retry = names.includes(d.domainName) ? names.filter((h) => h !== `www.${d.domainName}`) : names;
@@ -97,30 +101,29 @@ function domainLines(d) {
97
101
  out.push(` ${h.hostname.padEnd(w)} ${h.state}${h.service ? ` → ${h.service}` : ''}${h.reason ? ` — ${h.reason}` : ''}`);
98
102
  return out;
99
103
  }
100
- function orderStatusLines(o) {
104
+ function orderStatusLines(o, linked = true) {
101
105
  const out = [`order ${o.id}: ${o.domainName} — ${o.status}${o.failedReason ? ` — ${o.failedReason}` : ''}`];
102
- if (o.status === 'canceled')
106
+ if (linked && o.status === 'canceled')
103
107
  out.push(` the checkout closed without payment — order again: insta domain buy ${o.domainName}`);
104
108
  return out;
105
109
  }
106
110
  export async function domainList(opts, deps) {
107
- const { api, project: p } = await domainDeps(deps);
108
- const r = await api.request('GET', `/projects/${p.projectId}/domains`);
111
+ const { api, orgId } = await orgDeps(opts, deps);
112
+ const r = await api.request('GET', `/orgs/${orgId}/domains`);
109
113
  if (opts.json)
110
114
  return printJson(r);
111
115
  if (!r.items.length)
112
116
  return info('no domains bought through InstaCloud in this org (search: insta domain search <keyword>)');
113
117
  for (const d of r.items)
114
- for (const line of domainLines(d))
118
+ for (const line of domainLines(d, !opts.org))
115
119
  info(line);
116
120
  }
117
121
  export async function domainStatus(name, opts, deps) {
118
- const { api, project: p } = await domainDeps(deps);
122
+ const { api, orgId } = await orgDeps(opts, deps);
119
123
  const host = name.trim().toLowerCase();
120
- // Both are the ORG's; the project in the path is the scope the agent policy is read at.
121
124
  const [{ items: domains }, { items: orders }] = await Promise.all([
122
- api.request('GET', `/projects/${p.projectId}/domains`),
123
- api.request('GET', `/projects/${p.projectId}/domains/orders`),
125
+ api.request('GET', `/orgs/${orgId}/domains`),
126
+ api.request('GET', `/orgs/${orgId}/domains/orders`),
124
127
  ]);
125
128
  const domain = domains.find((d) => d.domainName === host) ?? null;
126
129
  const order = orders.find((o) => o.domainName === host) ?? null;
@@ -128,7 +131,7 @@ export async function domainStatus(name, opts, deps) {
128
131
  die(`${host} was not bought through this org`);
129
132
  if (opts.json)
130
133
  return printJson({ domain, order });
131
- for (const line of domain ? domainLines(domain) : orderStatusLines(order))
134
+ for (const line of domain ? domainLines(domain, !opts.org) : orderStatusLines(order, !opts.org))
132
135
  info(line);
133
136
  }
134
137
  export function recordLines(records) {
package/dist/index.js CHANGED
@@ -371,9 +371,11 @@ dom.command('buy <name>').description('Buy a domain — pay at the printed Strip
371
371
  dom.command('attach <hostname>').description('Point a bought domain, or any subdomain of one, at a compute service — `abc.com` binds it and its www, `api.abc.com` binds only that (gated: deploy)')
372
372
  .option('--branch <b>').option('--group <g>', "compute service (default: the branch's sole compute service)").option('--json')
373
373
  .action(guard((hostname, o) => domainCmd.domainAttach(hostname, o)));
374
- dom.command('list').description("Domains bought through InstaCloud in this org — a domain belongs to the org, each of its hostnames to a service").option('--json')
374
+ dom.command('list').description("Domains bought through InstaCloud in this org — a domain belongs to the org, each of its hostnames to a service")
375
+ .option('--org <id>', "target org (default: linked project's org)").option('--json')
375
376
  .action(guard((o) => domainCmd.domainList(o)));
376
- dom.command('status <name>').description("A bought domain's order and attach state").option('--json')
377
+ dom.command('status <name>').description("A bought domain's order and attach state")
378
+ .option('--org <id>', "target org (default: linked project's org)").option('--json')
377
379
  .action(guard((name, o) => domainCmd.domainStatus(name, o)));
378
380
  const rec = dom.command('records').description('DNS records of a bought domain — the zone InstaCloud holds at the registrar');
379
381
  rec.command('list <domain>').description('Every record in the zone, managed ones marked')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.79",
3
+ "version": "0.0.80",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [