Repository navigation
chore(domain): stop guiding users to buy or delegate new domains #378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -284,11 +284,12 @@ cron.command('preview <expression>').description('Validate an expression and pri | |
| .option('--json').action(guard((expression, o) => cronCmd.cronPreview(expression, o))) | ||
|
|
||
| // ---- domain (bought here, or bring your own; hostnames on compute services; DNS of bought zones) ---- | ||
| const dom = program.command('domain').description('Domains: buy through InstaCloud or bring your own — attach / check / detach hostnames on compute services; DNS records of bought domains') | ||
| dom.command('search <keyword>').description('Search purchasable names with prices (a label like "myapp" or a full name like "myapp.com")') | ||
| const dom = program.command('domain').description('Domains: attach, check and detach hostnames on compute services, and manage domains already bought through InstaCloud') | ||
| // search, buy and zone delegate are hidden while the platform pauses new orders and BYO delegation. | ||
| dom.command('search <keyword>', { hidden: true }).description('Search purchasable names with prices (a label like "myapp" or a full name like "myapp.com")') | ||
| .option('--tlds <list>', 'comma-separated TLDs to include').option('--org <id>', "target org (default: linked project's org)").option('--json') | ||
| .action(guard((keyword, o) => domainCmd.domainSearch(keyword, o))) | ||
| 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)') | ||
| 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)') | ||
| .option('--years <n>', 'registration term in years (default 1)') | ||
| .option('--no-open', 'print the checkout URL instead of opening a browser').option('--json') | ||
| .action(guard((name, o) => domainCmd.domainBuy(name, o))) | ||
|
|
@@ -321,14 +322,14 @@ ns.command('reset <domain>').description("Put the zone back on the registrar's o | |
| .option('--org <id>', "target org (default: linked project's org)").option('--json') | ||
| .action(guard((domain, o) => domainCmd.domainNameserversReset(domain, o))) | ||
|
|
||
| const zone = dom.command('zone').description("Bring-your-own domains served from an InstaCloud-managed zone (nameserver delegation): point the domain's registrar at the pair `zone delegate` answers, and every attach's records — apexes included — are published for you. The alternative stays available: `insta domain attach` alone prints records to paste into your own zone") | ||
| 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` and add anything missing at your current provider BEFORE switching nameservers; re-running delegate re-imports) 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)") | ||
| 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") | ||
| 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)") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The agent-facing CLI reference still directs agents to this paused command, so hiding it from CLI help does not stop agents following the documented workflow. Prompt for AI agents |
||
| .option('--org <id>', "target org (default: linked project's org)").option('--json') | ||
| .action(guard((domain, o) => domainCmd.zoneDelegate(domain, o))) | ||
| zone.command('list').description("The org's delegated zones: which are still waiting for the nameserver switch and which are serving") | ||
| .option('--org <id>', "target org (default: linked project's org)").option('--json') | ||
| .action(guard((o) => domainCmd.zoneList(o))) | ||
| zone.command('records <domain>').description("Every record in the delegated zone — the pre-switch review. The scan seeds common records but is not exhaustive: compare against your current DNS and add what is missing at your CURRENT provider, then re-run `zone delegate` to re-import") | ||
| 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") | ||
| .option('--org <id>', "target org (default: linked project's org)").option('--json') | ||
| .action(guard((domain, o) => domainCmd.zoneRecords(domain, o))) | ||
| 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)") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,7 +40,8 @@ describe('domain search', () => { | |
| expect(calls[0]).toMatchObject({ method: 'GET', path: '/orgs/org1/domains/search?q=MyApp&tlds=com%2Cdev' }) | ||
| expect(out()).toContain('myapp.com $15.59 (renews $23.99/yr)') | ||
| expect(out()).toContain('myapp.dev unavailable — Domain unavailable') | ||
| expect(out()).toContain('buy one: insta domain buy myapp.com') | ||
| // New orders are paused, so the results name no buy command. | ||
| expect(out()).not.toContain('insta domain buy') | ||
| }) | ||
| it('--org overrides the linked org; --json is the platform body', async () => { | ||
| const { deps: d, calls } = deps({ '/domains/search': { results: [quote] } }) | ||
|
|
@@ -228,21 +229,20 @@ describe('domain list / status', () => { | |
| expect(out()).not.toContain('order o1') | ||
| expect(out()).toContain('api.myapp.com active → api') | ||
| }) | ||
| it('a canceled checkout says how to order again', async () => { | ||
| // New orders are paused (platform #689), so a canceled checkout names no way to order again. | ||
| it('a canceled checkout says why and does not send the reader to buy again', async () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: Removing this test drops the only coverage for Prompt for AI agents |
||
| const { deps: d } = deps({ '/domains/orders': { items: [{ ...order, status: 'canceled', failedReason: 'checkout expired before payment' }] }, '/orgs/org1/domains': { items: [] } }) | ||
| await domainStatus('myapp.com', {}, d) | ||
| expect(out()).toContain('canceled — checkout expired before payment') | ||
| expect(out()).toContain('order again: insta domain buy myapp.com') | ||
| }) | ||
| // `buy` and `attach` take no --org: they act on the linked project's org, so naming another one | ||
| // would send the reader to a command that acts somewhere else. | ||
| it('drops the follow-up commands when --org names an org they do not act on', async () => { | ||
| const routes = { '/domains/orders': { items: [{ ...order, status: 'canceled', failedReason: 'x' }] }, '/orgs/org9/domains': { items: [] } } | ||
| const { deps: d } = deps(routes) | ||
| await domainStatus('myapp.com', { org: 'org9' }, d) | ||
| expect(out()).toContain('canceled') | ||
| expect(out()).toContain('the checkout closed without payment') | ||
| expect(out()).not.toContain('insta domain buy') | ||
| }) | ||
| it('an empty list says so without pointing at search', async () => { | ||
| const { deps: d } = deps({ '/orgs/org1/domains': { items: [] } }) | ||
| await domainList({}, d) | ||
| expect(out()).toContain('no domains bought through InstaCloud in this org') | ||
| expect(out()).not.toContain('insta domain search') | ||
| }) | ||
| it('status of a name never bought here fails plainly, --json included', async () => { | ||
| const { deps: d } = deps({ '/domains/orders': { items: [] }, '/orgs/org1/domains': { items: [] } }) | ||
| await expect(domainStatus('other.com', { json: true }, d)).rejects.toThrow('exit 1') | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,6 +42,8 @@ describe('domain zone delegate', () => { | |
| // The review-then-switch contract is the safety of the whole flow — it prints every time. | ||
| expect(out()).toContain('insta domain zone records byo.example') | ||
| expect(out()).toContain('only then switch the nameservers') | ||
| // BYO delegation is paused (platform #687), so re-running delegate is no longer a step. | ||
| expect(out()).not.toContain('re-running delegate') | ||
| }) | ||
| it('under --org naming ANOTHER org the call goes projectless — the wrong project must not sign', async () => { | ||
| const { deps: d, calls } = deps({}, { status: 200, body: awaiting }) | ||
|
|
@@ -72,6 +74,7 @@ describe('domain zone list', () => { | |
| const { deps: d2 } = deps({ '/zones': { items: [] } }) | ||
| await zoneList({}, d2) | ||
| expect(out()).toContain('no delegated zones') | ||
| expect(out()).not.toContain('zone delegate') | ||
| }) | ||
| it('combines pages into the existing JSON response and stops on the terminal cursor', async () => { | ||
| const second = { ...awaiting, domainName: 'second.example' } | ||
|
|
@@ -93,7 +96,7 @@ describe('domain zone list', () => { | |
| }) | ||
|
|
||
| describe('domain zone records', () => { | ||
| it('lists EVERY type (the review must see CAA) and prints the add-then-reimport reminder', async () => { | ||
| it('lists EVERY type (the review must see CAA) and prints the compare-before-switching reminder', async () => { | ||
| const { deps: d, calls } = deps({ | ||
| '/zones/byo.example/records': { items: [ | ||
| { type: 'CNAME', host: '@', answer: 'edge.example', proxied: true }, | ||
|
|
@@ -105,11 +108,9 @@ describe('domain zone records', () => { | |
| expect(calls[0]).toMatchObject({ method: 'GET', path: '/orgs/org1/zones/byo.example/records' }) | ||
| expect(out()).toContain('CAA') | ||
| expect(out()).toContain('(proxied)') | ||
| // The instruction is copy-pasteable VERBATIM: domain and org scope included. | ||
| expect(out()).toContain('re-run `insta domain zone delegate byo.example` to re-import') | ||
| stdout.length = 0 | ||
| await zoneRecords('Byo.Example', { org: 'org9' }, d) | ||
| expect(out()).toContain('re-run `insta domain zone delegate byo.example --org org9` to re-import') | ||
| expect(out()).toContain('compare them against your current DNS before switching nameservers') | ||
| // BYO delegation is paused (platform #687): the reminder no longer sends anyone to re-run it. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The removed Prompt for AI agents |
||
| expect(out()).not.toContain('zone delegate') | ||
| }) | ||
| it('says plainly when the scan has not landed yet', () => { | ||
| expect(zoneRecordLines([])[0]).toContain('run this again in a moment') | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This removes the only recovery instruction for records the scan misses.
zoneRecordsonly reads and prints records, so users cannot correct the managed zone there; retain the add-at-provider and re-run-delegate step before telling them to switch nameservers.Prompt for AI agents