feat: add Cloudflare domain registration CLI#167
Conversation
|
Warning Review limit reached
More reviews will be available in 52 minutes and 9 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
WalkthroughAdds a complete ChangesDomains CLI Feature
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/lib/cloudflare.test.ts (1)
22-31: ⚡ Quick winMove env/global cleanup to
afterEachto prevent state leakage on test failures.Current in-test cleanup can be skipped when assertions throw, causing cross-test pollution.
🔧 Suggested refactor
-import { describe, expect, it, vi } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; @@ describe('Cloudflare OAuth helpers', () => { + afterEach(() => { + vi.unstubAllEnvs(); + vi.unstubAllGlobals(); + }); + it('builds the Cloudflare OAuth URL with PKCE and the fixed CLI callback', () => { @@ - vi.unstubAllEnvs(); }); @@ - vi.unstubAllEnvs(); - vi.unstubAllGlobals(); }); @@ - vi.unstubAllGlobals(); }); });Also applies to: 56-58, 95-95
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/cloudflare.test.ts` around lines 22 - 31, The vi.unstubAllEnvs() cleanup is called inside the test function after the expect statements, which means it will be skipped if an assertion throws, causing environment variable state to leak to subsequent tests. Move all vi.unstubAllEnvs() calls from the end of each test function (in the test for buildCloudflareAuthorizeUrl and other affected tests) into a shared afterEach hook that runs after every test, ensuring cleanup happens regardless of test pass/fail status.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/commands/domains/index.ts`:
- Around line 555-557: The `.catch(() => null)` handler on the
`getCloudflareRegistration(domain)` call is masking all errors indiscriminately,
including authentication, network, and API failures that should be reported.
Instead of catching all errors, modify the catch handler to check the error type
and only suppress the known "not found" case (likely a specific error code or
message), then rethrow all other errors so they properly trigger failure
telemetry and error handling. This ensures only expected "not found" scenarios
are silently handled while unexpected failures propagate for proper diagnosis.
In `@src/lib/cloudflare.ts`:
- Around line 175-180: The error_description parameter is being directly
injected into the HTML response without escaping, creating a security
vulnerability where crafted OAuth callbacks could inject malicious scripts. In
the error handling block where the res.end() method is called with the HTML
string containing the Cloudflare authorization failed message, escape the desc
variable using HTML entity encoding (such as replacing special characters like
<, >, and & with their HTML entity equivalents) before inserting it into the
HTML template to prevent script injection attacks.
- Around line 321-324: The JSON.parse call that reads and parses the
CLOUDFLARE_FILE can throw an exception when the file contains invalid JSON,
causing the CLI to crash instead of following the friendly auth recovery paths.
Wrap the JSON.parse and readFileSync statement in a try-catch block, and return
null in the catch block to gracefully handle malformed credential files the same
way the code currently handles missing accountId or accessToken.
- Around line 186-189: In the Cloudflare callback handler at the code block
checking for missing code or state parameters, the 400 response is being sent to
the client but the underlying result promise is not being rejected. This causes
the login process to hang until timeout instead of returning immediately. Add a
reject call for the result promise in this error path (where the 400 response is
written) to ensure the promise is properly rejected when the callback is
invalid, allowing the login to fail fast rather than waiting for the timeout.
---
Nitpick comments:
In `@src/lib/cloudflare.test.ts`:
- Around line 22-31: The vi.unstubAllEnvs() cleanup is called inside the test
function after the expect statements, which means it will be skipped if an
assertion throws, causing environment variable state to leak to subsequent
tests. Move all vi.unstubAllEnvs() calls from the end of each test function (in
the test for buildCloudflareAuthorizeUrl and other affected tests) into a shared
afterEach hook that runs after every test, ensuring cleanup happens regardless
of test pass/fail status.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2e50a3a0-11a5-411a-9df9-8659a35561e0
📒 Files selected for processing (9)
README.mdsrc/commands/domains/index.test.tssrc/commands/domains/index.tssrc/commands/domains/telemetry.test.tssrc/commands/domains/telemetry.tssrc/index.tssrc/lib/analytics.tssrc/lib/cloudflare.test.tssrc/lib/cloudflare.ts
There was a problem hiding this comment.
2 issues found across 9 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
8dcf7d2 to
8472808
Compare
8472808 to
5a3b0f0
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/cloudflare.ts`:
- Line 3: The writeFileSync mode option only applies permissions when the file
is newly created, leaving existing files with potentially broader permissions
when tokens are refreshed or re-logged. Add chmodSync to the import statement
from 'node:fs', then locate all writeFileSync calls that save the cloudflare
credentials file (likely in a function that saves access/refresh tokens), and
add a chmodSync call immediately after each writeFileSync to enforce 0o600
permissions on every save operation regardless of whether the file already
exists.
- Around line 593-601: The current logic at line 593 uses a fallback to
existing[0] when exact content match is not found, which is problematic for TXT
records since multiple TXT records can coexist at the same domain (SPF, DKIM,
DMARC, etc.) and overwriting the first one will replace unrelated records.
Modify the logic to check the record type before deciding whether to update or
create: if the record type is TXT and no exact content match is found, call
cloudflareFetch with method POST to create a new record instead of falling back
to updating existing[0]; preserve the current fallback behavior (method PUT) for
singleton record types like A, CNAME, and MX where existing[0] is an acceptable
default.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5fbf8705-e4dc-48fc-84e7-29c7e4f78a67
📒 Files selected for processing (9)
README.mdsrc/commands/domains/index.test.tssrc/commands/domains/index.tssrc/commands/domains/telemetry.test.tssrc/commands/domains/telemetry.tssrc/index.tssrc/lib/analytics.tssrc/lib/cloudflare.test.tssrc/lib/cloudflare.ts
✅ Files skipped from review due to trivial changes (1)
- README.md
🚧 Files skipped from review as they are similar to previous changes (7)
- src/lib/analytics.ts
- src/index.ts
- src/commands/domains/index.test.ts
- src/lib/cloudflare.test.ts
- src/commands/domains/telemetry.ts
- src/commands/domains/telemetry.test.ts
- src/commands/domains/index.ts
jwfing
left a comment
There was a problem hiding this comment.
Review: feat — add Cloudflare domain registration CLI
Summary: A clean, well-scoped, all-additive feature that implements the full Cloudflare domain lifecycle (OAuth/PKCE login → search/check/buy → attach → DNS sync → verify → resume/buy-and-attach) with strong security hygiene and good unit coverage of the core helpers; the items below are non-blocking.
Requirements context: No matching spec/plan found — docs/specs/ contains only 2026-03-27-diagnose-* and 2026-04-17-db-migrations-*, none of which cover domains. Assessed against the PR description, DEVELOPMENT.md, and the repo's cli-development skill conventions.
I verified the four review dimensions across src/lib/cloudflare.ts, src/commands/domains/{index,telemetry}.ts, src/lib/analytics.ts, the wiring in src/index.ts, and the three test files.
What's good (worth calling out)
- Security hygiene is strong: OAuth uses PKCE (S256) and a random
statethat's validated before token exchange (cloudflare.ts:376-378); credentials are writtenmode: 0o600(cloudflare.ts:308); the callback server binds127.0.0.1only with a 5-minuteunref()timeout. - Telemetry is privacy-safe and proven so:
sanitizeDomainTelemetryuses strict key allow-lists and a TLD regex, drops everything else, and never forwards raw domains or error messages — andtelemetry.test.tsasserts exactly that (domainanderror_messageabsent). - The purchase money-guard is conservative: non-interactive
buyrequires 5 exactly-matching--confirm-*flags against the live candidate fromcheckCloudflareDomains(index.ts:118-161, 308-319); registrations enableauto_renew+privacy_mode: redaction. - Conventions followed: command/registration layout,
CLIError+handleError,outputJson/Table/Success,.jsESM imports, analytics flushed infinallyviashutdownAnalytics(), andtrackDomainscorrectly mirrors thenull-config/OSS-fallback pattern oftrackConfig.
Critical
(none)
Suggestion
- [Security]
src/lib/cloudflare.ts:177-182— the OAuth callback error page interpolateserror_descriptionstraight into HTML (res.end(\…${desc}
…`)). It's untrusted query input rendered unescaped → reflected-injection on the127.0.0.1:8787page during the ~5-min login window. Blast radius is low (transient localhost origin, no tokens stored in the browser), but please HTML-escapedesc`. - [Software engineering / convention] agent-skills sync —
DEVELOPMENT.md§3 says adding a user-facing command group almost certainly requires updating theinsforge-cliskill inInsForge/agent-skills(and mentioning that PR here).README.mdis updated (good), but the agent skill will be stale and agents will emit wrongdomains …commands until it's updated. Please open/link the companion PR. - [Functionality]
src/lib/cloudflare.ts:579-611upsertCloudflareDnsRecord— when a name holds multiple records of the same type with differing content, the?? existing[0]fallbackPUTs over an unrelated existing record. It's fine for the single A / single verification-TXT shapes this PR produces, but sinceensureCloudflareZonemay adopt a zone the user already owns, considerPOST-ing a new record (rather than overwritingexisting[0]) when no content match is found, to avoid clobbering pre-existing DNS. - [Testing]
src/commands/domains/index.test.ts— the highest-risk behaviors lack direct tests: the non-interactiveconfirmPurchaserejection path (the spend guard) and the OAuthstatemismatch abort.hasExplicitPurchaseConfirmationis tested as a pure helper, but a test assertingconfirmPurchasethrowsDOMAIN_PURCHASE_CONFIRMATION_REQUIREDwhen flags are absent/mismatched would lock down the money path.
Information
- [Functionality]
index.ts:440-448, 638-646— theconfirmedtelemetry field builds a synthetic candidate from the user's own--confirm-*flags, sohasExplicitPurchaseConfirmationcompares those values to themselves. The metric therefore reports "confirm flags were passed," not "they matched the real price." Harmless (the actual gate inregisterAfterCheckuses the live candidate), but the analytics signal is misleading. - [Security/robustness]
cloudflare.ts:185-196— the callback server resolves on the first request that merely containscode+state, validatingstateonly afterward inperformCloudflareOAuthLogin. A local process could pre-empt the real callback and force aSTATE_MISMATCHabort (login DoS). Low risk; consider ignoring callbacks whosestatedoesn't match rather than resolving on the first one. - [Functionality] Cloudflare Registrar endpoints (
/registrar/domain-search,/domain-check,/registrationswithPrefer: respond-async) are relatively new/beta API surface I can't verify from here — worth a manual end-to-end smoke test against the current Cloudflare API before release. - Performance: no concerns —
pollRegistrationsleeps async (3s interval, bounded by deadline), DNS upserts iterate a tiny record set, no N+1 or blocking I/O on the event loop.
Verdict
approved (informational — human approval still required via the approve flow). No Critical findings; the Suggestions above are worth addressing before merge, particularly the HTML-escaping and the agent-skills sync, but none block.
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
The state-mismatch branch in the OAuth callback server sent a 400 response but never settled the result promise, so a mismatched-state callback (stale tab, browser refresh, CSRF redirect) left the CLI hanging until the 5-minute timeout. Reject immediately, mirroring the missing-code/state and error branches, and add a regression test that drives the real callback server with a bad state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/lib/cloudflare.ts (1)
137-144: 💤 Low valueStatic analysis context: manual HTML escaping is acceptable here.
The static analyzer flags manual HTML entity encoding, but for this specific use case—a localhost-only OAuth callback page displaying error text inside a
<p>tag—the escaping covers all necessary characters (&,<,>,",'). Adding a full sanitization library for this minimal, non-internet-facing use would be over-engineering.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/cloudflare.ts` around lines 137 - 144, The static analyzer is flagging the manual HTML entity escaping in the escapeHtml function as a code quality issue. Suppress the analyzer warning for this function by adding an appropriate suppression comment (such as a linter or analyzer directive) above the escapeHtml function definition, since this localhost-only OAuth callback use case with all necessary entity characters covered does not warrant the overhead of a full sanitization library. No changes to the actual escaping logic are needed.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/cloudflare.test.ts`:
- Around line 202-225: The stderrSpy.mockRestore() call at the end of the test
'rejects login immediately when the OAuth callback state does not match' will
not execute if any earlier assertion fails, causing the spy to leak into
subsequent tests. Restructure the test by wrapping the test body (starting from
the stderrSpy creation through the expect(delivered).toBe(true) and await
rejection statements) in a try block, and place the stderrSpy.mockRestore() call
in a finally block to guarantee cleanup regardless of whether assertions pass or
fail.
---
Nitpick comments:
In `@src/lib/cloudflare.ts`:
- Around line 137-144: The static analyzer is flagging the manual HTML entity
escaping in the escapeHtml function as a code quality issue. Suppress the
analyzer warning for this function by adding an appropriate suppression comment
(such as a linter or analyzer directive) above the escapeHtml function
definition, since this localhost-only OAuth callback use case with all necessary
entity characters covered does not warrant the overhead of a full sanitization
library. No changes to the actual escaping logic are needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 45628a68-f58a-4038-86c6-0a8439f0655e
📒 Files selected for processing (4)
src/commands/domains/index.test.tssrc/commands/domains/index.tssrc/lib/cloudflare.test.tssrc/lib/cloudflare.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/commands/domains/index.test.ts
- src/commands/domains/index.ts
| it('rejects login immediately when the OAuth callback state does not match', async () => { | ||
| // Silence the OAuth URL banner the login flow writes to stderr. | ||
| const stderrSpy = vi.spyOn(process.stderr, 'write').mockReturnValue(true); | ||
|
|
||
| // Without the fix this never settles and the test times out instead of | ||
| // hanging the real CLI for the full 5-minute callback timeout. | ||
| const loginPromise = performCloudflareOAuthLogin({ skipBrowser: true }); | ||
| const rejection = expect(loginPromise).rejects.toThrow('Cloudflare OAuth state mismatch.'); | ||
|
|
||
| // Wait for the callback server to bind, then deliver a mismatched state. | ||
| let delivered = false; | ||
| for (let attempt = 0; attempt < 50 && !delivered; attempt += 1) { | ||
| try { | ||
| await fetch('http://127.0.0.1:8787/callback?code=test-code&state=wrong-state'); | ||
| delivered = true; | ||
| } catch { | ||
| await new Promise((resolve) => setTimeout(resolve, 20)); | ||
| } | ||
| } | ||
| expect(delivered).toBe(true); | ||
|
|
||
| await rejection; | ||
| stderrSpy.mockRestore(); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "cloudflare.test.ts" --exec cat -n {}Repository: InsForge/CLI
Length of output: 9037
Guarantee stderr spy cleanup even when assertions fail.
At line 224, stderrSpy.mockRestore() only runs on the success path. If expect(delivered).toBe(true) (line 221) or await rejection (line 223) fails first, the spy leaks into later tests. Unlike the vi.stubGlobal() calls in other tests that are cleaned up by the afterEach hook, vi.spyOn() requires explicit restoration. Wrap the test body in try/finally to guarantee cleanup.
Suggested fix
it('rejects login immediately when the OAuth callback state does not match', async () => {
// Silence the OAuth URL banner the login flow writes to stderr.
const stderrSpy = vi.spyOn(process.stderr, 'write').mockReturnValue(true);
- // Without the fix this never settles and the test times out instead of
- // hanging the real CLI for the full 5-minute callback timeout.
- const loginPromise = performCloudflareOAuthLogin({ skipBrowser: true });
- const rejection = expect(loginPromise).rejects.toThrow('Cloudflare OAuth state mismatch.');
-
- // Wait for the callback server to bind, then deliver a mismatched state.
- let delivered = false;
- for (let attempt = 0; attempt < 50 && !delivered; attempt += 1) {
- try {
- await fetch('http://127.0.0.1:8787/callback?code=test-code&state=wrong-state');
- delivered = true;
- } catch {
- await new Promise((resolve) => setTimeout(resolve, 20));
- }
- }
- expect(delivered).toBe(true);
-
- await rejection;
- stderrSpy.mockRestore();
+ try {
+ // Without the fix this never settles and the test times out instead of
+ // hanging the real CLI for the full 5-minute callback timeout.
+ const loginPromise = performCloudflareOAuthLogin({ skipBrowser: true });
+ const rejection = expect(loginPromise).rejects.toThrow('Cloudflare OAuth state mismatch.');
+
+ // Wait for the callback server to bind, then deliver a mismatched state.
+ let delivered = false;
+ for (let attempt = 0; attempt < 50 && !delivered; attempt += 1) {
+ try {
+ await fetch('http://127.0.0.1:8787/callback?code=test-code&state=wrong-state');
+ delivered = true;
+ } catch {
+ await new Promise((resolve) => setTimeout(resolve, 20));
+ }
+ }
+ expect(delivered).toBe(true);
+ await rejection;
+ } finally {
+ stderrSpy.mockRestore();
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('rejects login immediately when the OAuth callback state does not match', async () => { | |
| // Silence the OAuth URL banner the login flow writes to stderr. | |
| const stderrSpy = vi.spyOn(process.stderr, 'write').mockReturnValue(true); | |
| // Without the fix this never settles and the test times out instead of | |
| // hanging the real CLI for the full 5-minute callback timeout. | |
| const loginPromise = performCloudflareOAuthLogin({ skipBrowser: true }); | |
| const rejection = expect(loginPromise).rejects.toThrow('Cloudflare OAuth state mismatch.'); | |
| // Wait for the callback server to bind, then deliver a mismatched state. | |
| let delivered = false; | |
| for (let attempt = 0; attempt < 50 && !delivered; attempt += 1) { | |
| try { | |
| await fetch('http://127.0.0.1:8787/callback?code=test-code&state=wrong-state'); | |
| delivered = true; | |
| } catch { | |
| await new Promise((resolve) => setTimeout(resolve, 20)); | |
| } | |
| } | |
| expect(delivered).toBe(true); | |
| await rejection; | |
| stderrSpy.mockRestore(); | |
| }); | |
| it('rejects login immediately when the OAuth callback state does not match', async () => { | |
| // Silence the OAuth URL banner the login flow writes to stderr. | |
| const stderrSpy = vi.spyOn(process.stderr, 'write').mockReturnValue(true); | |
| try { | |
| // Without the fix this never settles and the test times out instead of | |
| // hanging the real CLI for the full 5-minute callback timeout. | |
| const loginPromise = performCloudflareOAuthLogin({ skipBrowser: true }); | |
| const rejection = expect(loginPromise).rejects.toThrow('Cloudflare OAuth state mismatch.'); | |
| // Wait for the callback server to bind, then deliver a mismatched state. | |
| let delivered = false; | |
| for (let attempt = 0; attempt < 50 && !delivered; attempt += 1) { | |
| try { | |
| await fetch('http://127.0.0.1:8787/callback?code=test-code&state=wrong-state'); | |
| delivered = true; | |
| } catch { | |
| await new Promise((resolve) => setTimeout(resolve, 20)); | |
| } | |
| } | |
| expect(delivered).toBe(true); | |
| await rejection; | |
| } finally { | |
| stderrSpy.mockRestore(); | |
| } | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/cloudflare.test.ts` around lines 202 - 225, The
stderrSpy.mockRestore() call at the end of the test 'rejects login immediately
when the OAuth callback state does not match' will not execute if any earlier
assertion fails, causing the spy to leak into subsequent tests. Restructure the
test by wrapping the test body (starting from the stderrSpy creation through the
expect(delivered).toBe(true) and await rejection statements) in a try block, and
place the stderrSpy.mockRestore() call in a finally block to guarantee cleanup
regardless of whether assertions pass or fail.
Summary
Validation
Summary by cubic
Adds a Cloudflare domains CLI to
@insforge/cli(v0.1.90) to search, buy, attach, and verify custom domains end-to-end. Includes OAuth login with account discovery, zone creation, DNS sync, safe telemetry, and token auto-refresh.New Features
domainscommands:cloudflare login,search,check,buy,attach,dns sync,verify,status,resume,buy-and-attach.http://127.0.0.1:8787/callback; tokens saved to~/.insforge/cloudflare.json; auto account discovery with selection; supports--account-id,--skip-browser, andCLOUDFLARE_ACCOUNT_ID/CLOUDFLARE_ACCESS_TOKEN; refreshes tokens on 401.--confirm-*); optional--poll-secondsto wait for registration (defaults to 90s forbuy-and-attach); registrations enable auto-renew and WHOIS redaction.status --cloudflareshows registration details;resumecompletes attach/DNS/verify after registration.cli_domains_invokedviatrackDomainswith sanitized fields (e.g., TLD, states, structured error codes); never sends raw domains or error messages.Bug Fixes
account-settings.readin OAuth scopes for reliable Cloudflare account discovery.Written for commit eb36866. Summary will update on new commits.
Note
Add Cloudflare domain registration CLI with OAuth, DNS sync, and InsForge attach
domainscommand group to the CLI covering the full domain lifecycle: OAuth login, search, availability check, purchase, DNS sync, InsForge attach/verify, status, and end-to-endbuy-and-attach.~/.insforge/cloudflare.json.trackDomainsfunction in analytics.ts.Changes since #167 opened
cloudflaremodule [4b65967]cloudflare.upsertCloudflareDnsRecord[4b65967]domainscommand [4b65967]cloudflaremodule [4b65967]confirmPurchasein non-interactive mode, DNS record upsert scenarios, and cleanup hooks [4b65967]startCloudflareCallbackServerHTTP callback handler to reject the pending result promise immediately with an error when OAuth state mismatch is detected in the/callbackrequest, instead of only responding with a 400 HTML page and leaving the promise pending until timeout [43dee83]Macroscope summarized c6b0dce.
Summary by CodeRabbit
domainsCLI command group for Cloudflare-backed domain search, availability checks, purchase, attach, DNS sync, verification, status, and resume, including an end-to-end buy-and-attach option.