insta 0.1.0 → 0.1.2
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/commands/domain.js +56 -1
- package/dist/commands/github.js +1 -3
- package/dist/index.js +14 -0
- package/dist/template-manifest.js +10 -0
- package/package.json +1 -1
package/dist/commands/domain.js
CHANGED
|
@@ -92,12 +92,20 @@ export async function domainAttach(host, opts, deps) {
|
|
|
92
92
|
function domainLines(d, linked = true) {
|
|
93
93
|
const out = [`${d.domainName} ${d.status}${d.expiresAt ? ` (expires ${d.expiresAt.slice(0, 10)}${d.autorenew ? ', auto-renews' : ''})` : ''}`];
|
|
94
94
|
// Vacuously true for a domain with no hostnames, which is every domain until something attaches.
|
|
95
|
-
|
|
95
|
+
// Not while delegated: the platform fails every hostname on the way out, and refuses the attach.
|
|
96
|
+
if (linked && !d.delegated && d.hostnames.every((h) => h.state === 'failed')) {
|
|
96
97
|
const names = d.hostnames.map((h) => h.hostname);
|
|
97
98
|
// Attaching the bought name itself re-attaches its www.
|
|
98
99
|
const retry = names.includes(d.domainName) ? names.filter((h) => h !== `www.${d.domainName}`) : names;
|
|
99
100
|
out.push(` nothing serving — ${(retry.length ? retry : [d.domainName]).map((h) => `insta domain attach ${h}`).join('; ')}`);
|
|
100
101
|
}
|
|
102
|
+
// The zone answers elsewhere, so nothing published here resolves and an attach is refused. The
|
|
103
|
+
// repair is a next action, so it follows `linked` like the others: under --org it would name this org.
|
|
104
|
+
if (d.delegated) {
|
|
105
|
+
out.push(` delegated to ${d.nameservers.join(', ')}${linked ? '' : ' — attach is refused'}`);
|
|
106
|
+
if (linked)
|
|
107
|
+
out.push(` attach is refused until: insta domain nameservers reset ${d.domainName}`);
|
|
108
|
+
}
|
|
101
109
|
const w = Math.max(0, ...d.hostnames.map((x) => x.hostname.length));
|
|
102
110
|
for (const h of d.hostnames)
|
|
103
111
|
out.push(` ${h.hostname.padEnd(w)} ${h.state}${h.service ? ` → ${h.service}` : ''}${h.reason ? ` — ${h.reason}` : ''}`);
|
|
@@ -136,6 +144,53 @@ export async function domainStatus(name, opts, deps) {
|
|
|
136
144
|
for (const line of domain ? domainLines(domain, !opts.org) : orderStatusLines(order, !opts.org))
|
|
137
145
|
info(line);
|
|
138
146
|
}
|
|
147
|
+
// ---- nameservers and transferring out ----
|
|
148
|
+
const domainPath = (orgId, domainName) => `/orgs/${orgId}/domains/${encodeURIComponent(domainName)}`;
|
|
149
|
+
export async function domainNameserversSet(domainName, hosts, opts, deps) {
|
|
150
|
+
const nameservers = hosts.flatMap((h) => h.split(/[\s,]+/)).map((h) => h.replace(/\.$/, '')).filter(Boolean);
|
|
151
|
+
if (!nameservers.length)
|
|
152
|
+
die("name at least one nameserver, or `insta domain nameservers reset <domain>` to restore the registrar's own");
|
|
153
|
+
const { api, orgId } = await orgDeps(opts, deps);
|
|
154
|
+
const r = await api.request('PUT', `${domainPath(orgId, domainName)}/nameservers`, { nameservers });
|
|
155
|
+
if (opts.json)
|
|
156
|
+
return printJson(r);
|
|
157
|
+
for (const line of domainLines(r, !opts.org))
|
|
158
|
+
info(line);
|
|
159
|
+
}
|
|
160
|
+
export async function domainNameserversReset(domainName, opts, deps) {
|
|
161
|
+
const { api, orgId } = await orgDeps(opts, deps);
|
|
162
|
+
const r = await api.request('DELETE', `${domainPath(orgId, domainName)}/nameservers`);
|
|
163
|
+
if (opts.json)
|
|
164
|
+
return printJson(r);
|
|
165
|
+
for (const line of domainLines(r, !opts.org))
|
|
166
|
+
info(line);
|
|
167
|
+
}
|
|
168
|
+
export async function domainTransferLock(domainName, mode, opts, deps) {
|
|
169
|
+
if (mode !== 'on' && mode !== 'off')
|
|
170
|
+
die('mode must be on or off');
|
|
171
|
+
const locked = mode === 'on';
|
|
172
|
+
const { api, orgId } = await orgDeps(opts, deps);
|
|
173
|
+
const r = await api.request('PATCH', domainPath(orgId, domainName), { locked });
|
|
174
|
+
if (opts.json)
|
|
175
|
+
return printJson(r);
|
|
176
|
+
info(`${r.domainName} transfer lock ${r.locked ? 'on' : 'off'}`);
|
|
177
|
+
if (!r.locked) {
|
|
178
|
+
// ICANN's post-registration lock outranks this one and nothing here can waive it.
|
|
179
|
+
if (r.transferLockExpiresAt && new Date(r.transferLockExpiresAt).getTime() > Date.now()) {
|
|
180
|
+
info(` ICANN holds the registration until ${r.transferLockExpiresAt.slice(0, 10)} whatever this says`);
|
|
181
|
+
}
|
|
182
|
+
if (!opts.org)
|
|
183
|
+
info(` authorization code: insta domain transfer code ${r.domainName}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export async function domainTransferCode(domainName, opts, deps) {
|
|
187
|
+
const { api, orgId } = await orgDeps(opts, deps);
|
|
188
|
+
const r = await api.request('POST', `${domainPath(orgId, domainName)}/auth-code`);
|
|
189
|
+
if (opts.json)
|
|
190
|
+
return printJson(r);
|
|
191
|
+
info(r.authCode);
|
|
192
|
+
}
|
|
193
|
+
// ---- records ----
|
|
139
194
|
export function recordLines(records) {
|
|
140
195
|
const w = (pick) => Math.max(...records.map((r) => pick(r).length));
|
|
141
196
|
const idW = w((r) => String(r.id)), typeW = w((r) => r.type), nameW = w((r) => r.fqdn), answerW = w((r) => r.answer), ttlW = w((r) => String(r.ttl));
|
package/dist/commands/github.js
CHANGED
|
@@ -41,7 +41,7 @@ export function parseWatchPaths(raw) {
|
|
|
41
41
|
throw new Error("watch paths need at least one pattern, e.g. 'apps/web/**,packages/ui/**' (quote them, or the shell expands the *)");
|
|
42
42
|
return out;
|
|
43
43
|
}
|
|
44
|
-
//
|
|
44
|
+
// Persisted commands constrain builder selection; automatic detection must leave them unset.
|
|
45
45
|
// autoDeploy rides along only when switched off: a public repo 400s on autoDeploy: true.
|
|
46
46
|
export function sourceBody(src, c, o) {
|
|
47
47
|
const repo = src.source === 'app'
|
|
@@ -50,8 +50,6 @@ export function sourceBody(src, c, o) {
|
|
|
50
50
|
return {
|
|
51
51
|
...repo,
|
|
52
52
|
rootDir: c.rootDir,
|
|
53
|
-
buildCommand: c.buildCommand,
|
|
54
|
-
startCommand: c.startCommand,
|
|
55
53
|
port: o.port !== undefined ? parsePort(o.port) : c.port,
|
|
56
54
|
...(o.repoBranch ? { branch: o.repoBranch } : {}),
|
|
57
55
|
...(o.autoDeploy === false ? { autoDeploy: false } : {}),
|
package/dist/index.js
CHANGED
|
@@ -214,6 +214,20 @@ dom.command('list').description("Domains bought through InstaCloud in this org
|
|
|
214
214
|
dom.command('status <name>').description("A bought domain's order and attach state")
|
|
215
215
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
216
216
|
.action(guard((name, o) => domainCmd.domainStatus(name, o)));
|
|
217
|
+
const ns = dom.command('nameservers').description("Delegate a bought domain's zone to nameservers you name, or put it back on InstaCloud's registrar");
|
|
218
|
+
ns.command('set <domain> <nameservers...>').description("Delegate the zone — the nameservers must already host it. Every hostname the domain serves stops answering, unless they are the registrar's own: the records an attach published live in the zone you are leaving")
|
|
219
|
+
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
220
|
+
.action(guard((domain, hosts, o) => domainCmd.domainNameserversSet(domain, hosts, o)));
|
|
221
|
+
ns.command('reset <domain>').description("Put the zone back on the registrar's own nameservers; a hostname it took down is re-attached with `insta domain attach`")
|
|
222
|
+
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
223
|
+
.action(guard((domain, o) => domainCmd.domainNameserversReset(domain, o)));
|
|
224
|
+
const xfer = dom.command('transfer').description('Take a bought domain to another registrar — open the lock, then read the code (all three need org admin)');
|
|
225
|
+
xfer.command('lock <domain> <mode>').description("Open or close the registrar transfer lock (mode: on|off). ICANN's own 60-day lock on a new registration outranks it")
|
|
226
|
+
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
227
|
+
.action(guard((domain, mode, o) => domainCmd.domainTransferLock(domain, mode, o)));
|
|
228
|
+
xfer.command('code <domain>').description('The EPP authorization code the gaining registrar asks for — it moves nothing on its own')
|
|
229
|
+
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
230
|
+
.action(guard((domain, o) => domainCmd.domainTransferCode(domain, o)));
|
|
217
231
|
const rec = dom.command('records').description('DNS records of a bought domain — the zone InstaCloud holds at the registrar');
|
|
218
232
|
rec.command('list <domain>').description('Every record in the zone, managed ones marked')
|
|
219
233
|
.option('--org <id>', "target org (default: linked project's org)").option('--json')
|
|
@@ -121,6 +121,16 @@ export function validateManifest(m) {
|
|
|
121
121
|
if (svc.port !== undefined && (!Number.isInteger(svc.port) || svc.port < 1 || svc.port > 65535)) {
|
|
122
122
|
problems.push(`${where}: port must be an integer between 1 and 65535, got: ${svc.port}`);
|
|
123
123
|
}
|
|
124
|
+
// A worker is PORTLESS: the platform deploys it as its own port-0 service, so nothing is routed
|
|
125
|
+
// to it and nothing probes it. The server's three refusals, said here before the upload.
|
|
126
|
+
if (svc.type === 'worker') {
|
|
127
|
+
if (svc.port !== undefined)
|
|
128
|
+
problems.push(`${where}.port: a worker has no routed port — remove it (a worker is portless; declare type: web to serve HTTP)`);
|
|
129
|
+
if (svc.healthcheck !== undefined)
|
|
130
|
+
problems.push(`${where}.healthcheck: a worker has no HTTP endpoint to probe — its health is the machine's state; remove it (or declare type: web)`);
|
|
131
|
+
if (svc.alwaysOn === false)
|
|
132
|
+
problems.push(`${where}.alwaysOn: a worker cannot scale to zero — nothing is routed to it, so nothing would wake it; remove alwaysOn or set it true`);
|
|
133
|
+
}
|
|
124
134
|
if (svc.type === 'web' && !svc.healthcheck)
|
|
125
135
|
problems.push(`${where}: web services must declare a healthcheck path`);
|
|
126
136
|
if (svc.healthcheck && !String(svc.healthcheck).startsWith('/'))
|