@domainkit/react 0.19.0 → 0.20.1
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 +6 -4
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@ Headless React hooks for custom-domain setup, over a transport your server owns.
|
|
|
4
4
|
supplies state, copy, and accessibility; your application supplies the markup. Provider credentials
|
|
5
5
|
never reach the browser.
|
|
6
6
|
|
|
7
|
+
Documentation: [domain-kit.dev](https://domain-kit.dev)
|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```sh
|
|
10
|
-
npm install @domainkit/react domainkit effect
|
|
12
|
+
npm install @domainkit/react domainkit effect react react-dom
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
React 19 is required. Install `domainkit` and `@domainkit/react` at the same release version.
|
|
@@ -162,9 +164,9 @@ A host that observes on its own clock passes the readiness it holds as
|
|
|
162
164
|
`Verify.useController`. The hook then observes nothing on mount, sets no timer, and routes `observe`
|
|
163
165
|
and `retry` to the host's own, while drift replanning runs off the supplied value.
|
|
164
166
|
|
|
165
|
-
Observation
|
|
166
|
-
|
|
167
|
-
|
|
167
|
+
Observation and verification retries stay available in read-only, because checking DNS reads the
|
|
168
|
+
world rather than changing the domain. Provisioning and cleanup retries are refused. Connection
|
|
169
|
+
retries re-inspect instead of resending a failed write.
|
|
168
170
|
|
|
169
171
|
## Words
|
|
170
172
|
|
package/dist/index.mjs
CHANGED
|
@@ -147,6 +147,7 @@ const english = {
|
|
|
147
147
|
},
|
|
148
148
|
conflictReason: (reason) => {
|
|
149
149
|
switch (reason) {
|
|
150
|
+
case "spf-conflict": return "This name has a different SPF record or more than one SPF record.";
|
|
150
151
|
case "exclusive-name": return "Another record already owns this name.";
|
|
151
152
|
case "cname-collision": return "A CNAME cannot share a name with other records.";
|
|
152
153
|
case "value-mismatch": return "A record with this name holds a different value.";
|
|
@@ -156,6 +157,7 @@ const english = {
|
|
|
156
157
|
},
|
|
157
158
|
conflictAdvice: (reason) => {
|
|
158
159
|
switch (reason) {
|
|
160
|
+
case "spf-conflict": return "Review the SPF records at your provider and keep one matching policy, then check again.";
|
|
159
161
|
case "exclusive-name": return "Remove the record on that name at your provider, then check again.";
|
|
160
162
|
case "cname-collision": return "Remove the other records on that name at your provider, then check again.";
|
|
161
163
|
case "value-mismatch": return "Point that record at this value at your provider, or remove it and check again.";
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["mergeMessages","State","useController","currentUrl","State","useController","useController","Connect.useController","Verify.useController","Provision.useController","Cleanup.useController","Connect.holdsConnection","offering","Connect.offering","Connect.hostProvider","Provision.pendingPlan"],"sources":["../src/messages.ts","../src/domain-kit.tsx","../src/events.ts","../src/task.ts","../src/attempt.ts","../src/cleanup.ts","../src/domain-field.ts","../src/connect.ts","../src/records.ts","../src/provision.ts","../src/verify.ts","../src/domain.ts","../src/outcome.ts","../src/testing.ts","../src/failure.ts"],"sourcesContent":["/**\n * Every string the package can put on screen. Nothing renders a `_tag`, a reason name, or a\n * status literal directly: each one arrives here first, so a host translates the whole surface by\n * passing `messages` to `DomainKit.Root`.\n */\nimport type { DnsRecord, DomainKit, Plan, Reason, Receipt, Storage } from \"domainkit\";\n\nexport interface Catalog {\n // Actions\n readonly connect: string;\n /** The token method's button, which carries the verb rather than the method's own label. */\n readonly methodToken: string;\n readonly methodOAuth: (provider: string) => string;\n readonly methodIntegration: (provider: string) => string;\n readonly disconnect: string;\n readonly detach: string;\n readonly cancel: string;\n readonly close: string;\n readonly retry: string;\n readonly approve: string;\n /** The provisioning dialog's primary action: what it adds, and how many. */\n readonly addRecords: (count: number) => string;\n readonly decline: string;\n /** Why the primary action is unavailable: every operation the plan holds is blocked. */\n readonly everyRecordConflicts: string;\n readonly reviewChanges: string;\n readonly cleanUp: string;\n readonly checkDns: string;\n readonly checkAgain: string;\n readonly moreActions: string;\n /** Reveals the fields a provider does not need, such as an account id. */\n readonly moreOptions: string;\n /** Reveals the providers the dialog narrowed away. */\n readonly useAnotherProvider: string;\n /** Opens the token form where a provider also offers a method the customer clicks through. */\n readonly useTokenInstead: string;\n /** Returns from one method's form to the provider's methods. */\n readonly back: string;\n /** The connected card's identity: who holds the connection and which account it reaches. */\n readonly connectedAccount: (provider: string, account: string) => string;\n /** How many records this domain's apply receipt proves DomainKit added. */\n readonly recordsAdded: (count: number) => string;\n readonly needsReconnect: string;\n /** The disconnect dialog's scope question, when the connection serves other domains too. */\n readonly disconnectScope: string;\n readonly disconnectThisDomain: string;\n readonly disconnectEveryDomain: (count: number) => string;\n readonly copy: string;\n readonly copied: string;\n readonly copyZone: string;\n readonly download: string;\n readonly useConnection: (label: string) => string;\n readonly chooseZone: string;\n /** The domain field's listbox, named for a customer reading it with assistive technology. */\n readonly zoneSuggestions: string;\n /** Which account a typed domain's records will go to. */\n readonly recordsGoTo: (provider: string, account: string) => string;\n /** A typed domain no connected account reaches; the customer adds the records by hand. */\n readonly notInConnectedAccount: string;\n /** A held connection whose credential the provider turned down. */\n readonly reconnectAccount: (account: string) => string;\n readonly getToken: string;\n\n // Progress\n readonly loading: string;\n readonly connecting: string;\n readonly redirecting: string;\n readonly detaching: string;\n readonly disconnecting: string;\n readonly planning: string;\n readonly approving: string;\n readonly applying: string;\n readonly rejecting: string;\n readonly planningCleanup: string;\n readonly cleaning: string;\n readonly observing: string;\n\n // Connection\n readonly connectTitle: (provider: string) => string;\n /** The dialog heading, and the trigger, when no provider is named yet. */\n readonly connectAnyTitle: string;\n /** What the disconnected prompt says about the provider whose nameservers serve the domain. */\n readonly hostDetected: (provider: string) => string;\n readonly connectDescription: (domain: string) => string;\n readonly connectedTo: (provider: string) => string;\n /** Shown where a connect control would be when the customer may not connect. */\n readonly notConnected: string;\n /**\n * What a customer who may read the domain but not write to it is told in place of the connect\n * control, so the surface explains the gap rather than leaving an empty row.\n */\n readonly administratorConnects: (provider: string) => string;\n readonly reconnectRequired: (provider: string) => string;\n readonly disconnectTitle: (provider: string) => string;\n /**\n * What disconnecting means, in the present. The default names DomainKit as what stops managing\n * the records; a host application overrides the key to name itself.\n */\n readonly disconnectConsent: (domain: string, provider: string) => string;\n /**\n * The option inside the disconnect dialog, over the records it would remove. Only this domain's\n * apply receipt proves what DomainKit created, so the words say which records go.\n */\n readonly disconnectWithCleanup: (count: number) => string;\n /** What the listed records do when that option is off. */\n readonly disconnectKeepsRecords: (provider: string) => string;\n readonly detachConsent: string;\n readonly detached: string;\n readonly reusableConnections: string;\n readonly authenticationAlternative: string;\n readonly discoveredConnection: (label: string) => string;\n readonly discoveryAmbiguous: string;\n readonly discoveryNotFound: (nameservers: ReadonlyArray<string>) => string;\n readonly noProviders: string;\n readonly fieldLabel: (name: string) => string;\n readonly optionalField: string;\n\n // Plan review\n readonly planTitle: string;\n readonly planConsent: string;\n readonly cleanupTitle: string;\n readonly cleanupConsent: string;\n readonly noChanges: string;\n readonly planExpires: (at: string) => string;\n readonly declinedBy: (actor: string) => string;\n readonly declineReason: (reason: string) => string;\n readonly operation: (operation: Plan.Operation) => string;\n readonly conflictReason: (reason: Plan.Conflict[\"reason\"]) => string;\n /** What to do about a conflict, in the row that reports it. */\n readonly conflictAdvice: (reason: Plan.Conflict[\"reason\"]) => string;\n /** What a pending plan holds for one row: a write, a record already there, or a blocker. */\n readonly planStatus: (operation: Plan.Operation) => string;\n readonly attemptStatus: (status: Storage.AttemptStatus) => string;\n\n // Records\n readonly recordsCaption: (domain: string) => string;\n readonly headingType: string;\n readonly headingName: string;\n readonly headingValue: string;\n readonly headingStatus: string;\n /** The column that says what a pending plan will do, rendered only while one is pending. */\n readonly headingPlan: string;\n readonly headingPurpose: string;\n readonly priority: (priority: number) => string;\n readonly ttl: (seconds: number) => string;\n readonly recordType: (record: DnsRecord.Observed) => string;\n\n // Receipts\n readonly applied: (receipt: Receipt.Model) => string;\n readonly cleaned: (receipt: Receipt.Model) => string;\n readonly partiallyAppliedTitle: string;\n readonly partiallyApplied: string;\n readonly partiallyCleanedTitle: string;\n readonly partiallyCleaned: string;\n readonly receiptOutcome: (outcome: Receipt.Outcome) => string;\n readonly skippedReason: (reason: Receipt.Skipped[\"reason\"]) => string;\n\n // Verification\n readonly requirementStatus: (status: Storage.RequirementStatus) => string;\n readonly overall: (overall: Storage.Overall) => string;\n readonly evidenceSource: (evidence: EvidenceLike) => string;\n readonly hostEvidenceStatus: (status: \"failed\" | \"ok\" | \"pending\") => string;\n /** What the requirement asks for, shown when an observation disagrees with it. */\n readonly expectedValue: (value: string) => string;\n /** What one observer actually read back for that name. */\n readonly observedValues: (values: ReadonlyArray<string>) => string;\n readonly observedNothing: string;\n readonly checkedAt: (at: string) => string;\n readonly nextCheckAt: (at: string) => string;\n readonly hostEvidence: string;\n readonly noEvidence: string;\n\n // Failures, rendered from the error's reason: a heading and the sentence under it\n readonly invalidInput: (reason: Reason.InvalidInput, context: OutcomeContext) => Outcome;\n readonly unauthenticated: (reason: Reason.Unauthenticated, context: OutcomeContext) => Outcome;\n readonly forbidden: (reason: Reason.Forbidden, context: OutcomeContext) => Outcome;\n readonly notFound: (reason: Reason.NotFound, context: OutcomeContext) => Outcome;\n readonly conflict: (reason: Reason.Conflict, context: OutcomeContext) => Outcome;\n readonly stale: (reason: Reason.Stale, context: OutcomeContext) => Outcome;\n readonly batchStale: (reason: Reason.BatchStale, context: OutcomeContext) => Outcome;\n readonly expired: (reason: Reason.Expired, context: OutcomeContext) => Outcome;\n readonly busy: (reason: Reason.Busy, context: OutcomeContext) => Outcome;\n readonly providerRejected: (reason: Reason.ProviderRejected, context: OutcomeContext) => Outcome;\n readonly providerUnavailable: (\n reason: Reason.ProviderUnavailable,\n context: OutcomeContext,\n ) => Outcome;\n readonly providerConflict: (reason: Reason.ProviderConflict, context: OutcomeContext) => Outcome;\n readonly unsupported: (reason: Reason.Unsupported, context: OutcomeContext) => Outcome;\n readonly reconnect: (reason: Reason.Reconnect, context: OutcomeContext) => Outcome;\n readonly storageFailed: (reason: Reason.StorageFailed, context: OutcomeContext) => Outcome;\n readonly cryptoFailed: (reason: Reason.CryptoFailed, context: OutcomeContext) => Outcome;\n readonly resolverFailed: (reason: Reason.ResolverFailed, context: OutcomeContext) => Outcome;\n}\n\n/** What an outcome says: a heading the customer reads first, then what to do about it. */\nexport interface Outcome {\n readonly title: string;\n /** What to do about it. Absent where the title has already said the whole of it. */\n readonly description?: string;\n}\n\n/**\n * What the flow was doing when it failed. The reason alone cannot name the provider a customer\n * typed a token for, so the part that renders the outcome supplies it.\n */\nexport interface OutcomeContext {\n /** The provider's display name, when the flow knows which one the customer acted on. */\n readonly provider?: string;\n readonly domain?: string;\n}\n\n/** The evidence shapes `Verify` produces, structurally, so the catalog needs no service import. */\nexport type EvidenceLike =\n | { readonly _tag: \"Host\"; readonly source: string; readonly label: string }\n | { readonly _tag: \"Provider\"; readonly provider: string }\n | { readonly _tag: \"PublicDns\"; readonly resolver: string };\n\nconst entity: Readonly<Record<Reason.NotFound[\"entity\"], string>> = {\n approval: \"approval\",\n attachment: \"domain attachment\",\n batch: \"domain setup\",\n authorization: \"provider authorization\",\n connection: \"provider connection\",\n continuation: \"sign-in attempt\",\n plan: \"plan\",\n provider: \"provider\",\n receipt: \"receipt\",\n record: \"DNS record\",\n zone: \"DNS zone\",\n};\n\nconst expiredEntity: Readonly<Record<Reason.Expired[\"entity\"], string>> = {\n approval: \"approval\",\n continuation: \"sign-in attempt\",\n credential: \"provider credential\",\n plan: \"plan\",\n};\n\nconst recordTypes: Readonly<Record<Exclude<DnsRecord.Observed[\"_tag\"], \"Opaque\">, string>> = {\n A: \"A\",\n AAAA: \"AAAA\",\n CAA: \"CAA\",\n CNAME: \"CNAME\",\n MX: \"MX\",\n NS: \"NS\",\n SRV: \"SRV\",\n TXT: \"TXT\",\n};\n\n/** The provider the customer acted on, or a neutral stand-in when the flow does not know it. */\nconst named = (provider: string | undefined): string => provider ?? \"The provider\";\n\n/** The domain the failure is about, or a neutral stand-in. */\nconst where = (domain: string | undefined): string => domain ?? \"this domain\";\n\n/** `accountId` reads as \"Account id\" until a host names the field itself. */\nconst humanize = (name: string): string => {\n const spaced = name\n .replaceAll(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replaceAll(/[_-]+/g, \" \")\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n};\n\nexport const english: Catalog = {\n connect: \"Connect\",\n methodToken: \"Connect with an API token\",\n methodOAuth: (provider) => `Continue with ${provider}`,\n methodIntegration: (provider) => `Install the ${provider} integration`,\n disconnect: \"Disconnect\",\n detach: \"Detach domain\",\n cancel: \"Cancel\",\n close: \"Close\",\n retry: \"Try again\",\n approve: \"Approve\",\n addRecords: (count) => (count === 1 ? \"Add 1 record\" : `Add ${count} records`),\n decline: \"Decline\",\n everyRecordConflicts: \"Resolve the records above at your provider, then check again.\",\n reviewChanges: \"Review changes\",\n cleanUp: \"Remove records\",\n checkDns: \"Check DNS\",\n checkAgain: \"Check again\",\n moreActions: \"More actions\",\n moreOptions: \"Add an account id\",\n useAnotherProvider: \"Use a different provider\",\n useTokenInstead: \"Use an API token instead\",\n back: \"Back\",\n connectedAccount: (provider, account) => `${provider} · ${account}`,\n recordsAdded: (count) => (count === 1 ? \"1 added\" : `${count} added`),\n needsReconnect: \"Needs reconnecting\",\n disconnectScope: \"This connection serves other domains.\",\n disconnectThisDomain: \"Only this domain\",\n disconnectEveryDomain: (count) => `All ${count} domains`,\n copy: \"Copy\",\n copied: \"Copied\",\n copyZone: \"Copy zone file\",\n download: \"Download\",\n useConnection: (label) => `Use ${label}`,\n chooseZone: \"Choose the zone that serves this domain\",\n zoneSuggestions: \"Zones your connected accounts serve\",\n recordsGoTo: (provider, account) => `Records go to ${provider} through ${account}.`,\n notInConnectedAccount: \"Not in a connected account.\",\n reconnectAccount: (account) => `Reconnect ${account}`,\n getToken: \"Where do I find this?\",\n\n loading: \"Loading…\",\n connecting: \"Connecting…\",\n redirecting: \"Opening the provider…\",\n detaching: \"Detaching…\",\n disconnecting: \"Disconnecting…\",\n planning: \"Preparing DNS changes…\",\n approving: \"Approving…\",\n applying: \"Adding records…\",\n rejecting: \"Declining…\",\n planningCleanup: \"Preparing cleanup…\",\n cleaning: \"Removing records…\",\n observing: \"Checking DNS…\",\n\n connectTitle: (provider) => `Connect ${provider}`,\n connectAnyTitle: \"Connect a DNS provider\",\n hostDetected: (provider) => `${provider} DNS detected`,\n connectDescription: (domain) => `Authorize DNS changes for ${domain}.`,\n connectedTo: (provider) => `${provider} connected`,\n notConnected: \"No DNS provider is connected.\",\n administratorConnects: (provider) => `An administrator can connect ${provider}`,\n reconnectRequired: (provider) => `${provider} needs to be reconnected`,\n disconnectTitle: (provider) => `Disconnect ${provider}?`,\n disconnectConsent: (domain, provider) =>\n `DomainKit stops managing DNS for ${domain} through ${provider}.`,\n disconnectWithCleanup: (count) =>\n count === 1\n ? \"Remove the 1 record DomainKit added\"\n : `Remove the ${count} records DomainKit added`,\n disconnectKeepsRecords: (provider) => `Records stay in ${provider}.`,\n detachConsent: \"This domain is detached from the provider. Existing DNS records are preserved.\",\n detached: \"Domain detached. DNS records were preserved.\",\n reusableConnections: \"Connections you already have\",\n authenticationAlternative: \"or\",\n discoveredConnection: (label) => `${label} already serves this domain`,\n discoveryAmbiguous: \"More than one connection can serve this domain. Pick one.\",\n discoveryNotFound: (nameservers) =>\n nameservers.length === 0\n ? \"No connected provider serves this domain yet.\"\n : `No connected provider serves this domain. Its nameservers are ${nameservers.join(\", \")}.`,\n noProviders: \"No DNS providers are available.\",\n fieldLabel: humanize,\n optionalField: \"optional\",\n\n planTitle: \"Review DNS changes\",\n planConsent: \"Review the exact DNS operations before approving this plan.\",\n cleanupTitle: \"Review the records to remove\",\n cleanupConsent: \"Only records the apply receipt proves DomainKit created will be deleted.\",\n noChanges: \"No changes needed\",\n planExpires: (at) => `This plan expires at ${at}.`,\n declinedBy: (actor) => `Declined by ${actor}. Build a new plan to continue.`,\n declineReason: (reason) => `Reason: ${reason}`,\n operation: (operation) => {\n switch (operation._tag) {\n case \"Create\":\n return \"Add\";\n case \"Noop\":\n return \"Already in place\";\n case \"Delete\":\n return \"Remove\";\n case \"Conflict\":\n return \"Blocked\";\n }\n },\n conflictReason: (reason) => {\n switch (reason) {\n case \"exclusive-name\":\n return \"Another record already owns this name.\";\n case \"cname-collision\":\n return \"A CNAME cannot share a name with other records.\";\n case \"value-mismatch\":\n return \"A record with this name holds a different value.\";\n case \"opaque\":\n return \"A record here uses a form DomainKit will not overwrite.\";\n case \"missing\":\n return \"The record this plan expected is gone.\";\n }\n },\n conflictAdvice: (reason) => {\n switch (reason) {\n case \"exclusive-name\":\n return \"Remove the record on that name at your provider, then check again.\";\n case \"cname-collision\":\n return \"Remove the other records on that name at your provider, then check again.\";\n case \"value-mismatch\":\n return \"Point that record at this value at your provider, or remove it and check again.\";\n case \"opaque\":\n return \"Remove that record at your provider, then check again.\";\n case \"missing\":\n return \"Check again to build a plan from what is there now.\";\n }\n },\n planStatus: (operation) => {\n switch (operation._tag) {\n case \"Create\":\n return \"Will add\";\n case \"Noop\":\n return \"Already set\";\n case \"Delete\":\n return \"Will remove\";\n case \"Conflict\":\n return \"Conflict\";\n }\n },\n attemptStatus: (status) => {\n switch (status) {\n case \"planned\":\n return \"Awaiting review\";\n case \"approved\":\n return \"Approved\";\n case \"applying\":\n return \"Applying\";\n case \"complete\":\n return \"Applied\";\n case \"partial\":\n return \"Partly applied\";\n case \"failed\":\n return \"Failed\";\n case \"expired\":\n return \"Expired\";\n case \"rejected\":\n return \"Declined\";\n }\n },\n\n recordsCaption: (domain) => `DNS records for ${domain}`,\n headingType: \"Type\",\n headingName: \"Name\",\n headingValue: \"Value\",\n headingStatus: \"Status\",\n headingPlan: \"Plan\",\n headingPurpose: \"Purpose\",\n priority: (priority) => `Priority ${priority}`,\n ttl: (seconds) => `TTL ${seconds}s`,\n recordType: (record) => (record._tag === \"Opaque\" ? record.type : recordTypes[record._tag]),\n\n applied: (receipt) =>\n receipt.status === \"complete\" ? \"DNS records added.\" : \"Some DNS records were not added.\",\n cleaned: (receipt) =>\n receipt.status === \"complete\" ? \"DNS records removed.\" : \"Some DNS records were not removed.\",\n partiallyAppliedTitle: \"Some DNS changes did not land\",\n partiallyApplied: \"Review what applied, then retry. Retrying is safe.\",\n partiallyCleanedTitle: \"Some DNS records are still there\",\n partiallyCleaned: \"Review what is left, then retry. Retrying is safe.\",\n receiptOutcome: (outcome) => {\n switch (outcome._tag) {\n case \"Applied\":\n return \"Done\";\n case \"Skipped\":\n return \"Skipped\";\n case \"Failed\":\n return outcome.message;\n }\n },\n skippedReason: (reason) => {\n switch (reason) {\n case \"noop\":\n return \"The record was already in place.\";\n case \"not-approved\":\n return \"The approval left this operation out.\";\n case \"not-attempted\":\n return \"An earlier operation failed before this one ran.\";\n }\n },\n\n requirementStatus: (status) => {\n switch (status) {\n case \"satisfied\":\n return \"Found\";\n case \"missing\":\n return \"Missing\";\n case \"mismatch\":\n return \"Different value\";\n case \"unknown\":\n return \"Not checked\";\n }\n },\n overall: (overall) => {\n switch (overall) {\n case \"ready\":\n return \"Ready\";\n case \"pending\":\n return \"Pending\";\n case \"failed\":\n return \"Failed\";\n }\n },\n evidenceSource: (evidence) => {\n switch (evidence._tag) {\n case \"Host\":\n return evidence.label;\n case \"Provider\":\n return `${evidence.provider} records`;\n case \"PublicDns\":\n return `Public DNS via ${evidence.resolver}`;\n }\n },\n hostEvidenceStatus: (status) => {\n switch (status) {\n case \"ok\":\n return \"Ready\";\n case \"pending\":\n return \"Pending\";\n case \"failed\":\n return \"Failed\";\n }\n },\n expectedValue: (value) => `Expected ${value}`,\n observedValues: (values) => `Found ${values.join(\", \")}`,\n observedNothing: \"Found nothing\",\n checkedAt: (at) => `Checked ${at}`,\n nextCheckAt: (at) => `Next check ${at}`,\n hostEvidence: \"Other checks\",\n noEvidence: \"Nothing has been checked yet.\",\n\n invalidInput: (reason) => ({\n description: reason.message,\n title:\n reason.field === undefined\n ? \"Check what you entered\"\n : `Check the ${humanize(reason.field).toLowerCase()}`,\n }),\n // The dialog's heading already names the provider, so the outcome answers about the credential\n // and nothing else. A longer title wraps in the column beside the retry, and a second line under\n // it repeats what the title said.\n unauthenticated: () => ({\n title: \"Token not accepted\",\n }),\n forbidden: (_reason, context) => ({\n description: `The connection needs permission to edit DNS for ${where(context.domain)}.`,\n title: \"This connection can't change DNS here\",\n }),\n notFound: (reason) => ({\n description: \"Reload the page and start this step again.\",\n title: `That ${entity[reason.entity]} no longer exists`,\n }),\n conflict: (reason) => ({\n description: \"Review what the zone already holds, then build a new plan.\",\n title:\n reason.operations.length === 1\n ? \"A record is in the way\"\n : `${reason.operations.length} records are in the way`,\n }),\n stale: () => ({\n description: \"Review the new plan before you apply it.\",\n title: \"The zone changed since you reviewed\",\n }),\n batchStale: () => ({\n description: \"Open it again to see where it stands.\",\n title: \"This setup changed since you reviewed it\",\n }),\n expired: (reason) => ({\n description: \"Start this step again.\",\n title: `That ${expiredEntity[reason.entity]} expired`,\n }),\n busy: () => ({\n description: \"Wait for it to finish, then try again.\",\n title: \"Another change is running\",\n }),\n providerRejected: (reason, context) => ({\n description: reason.message,\n title: `${named(context.provider ?? reason.provider)} refused the change`,\n }),\n providerUnavailable: (reason, context) => ({\n description: \"Nothing changed. Try again in a minute.\",\n title: `${named(context.provider ?? reason.provider)} isn't responding`,\n }),\n providerConflict: (reason, context) => ({\n description: \"Remove or rename that record at the provider, then try again.\",\n title: `${named(context.provider ?? reason.provider)} already holds a conflicting record`,\n }),\n unsupported: (reason, context) => ({\n description: \"Nothing changed. This step needs a provider that can do it.\",\n title: `${named(context.provider ?? reason.provider)} cannot ${reason.operation}`,\n }),\n reconnect: (reason, context) => ({\n description: \"The stored credential no longer works. Connect again to continue.\",\n title: `Reconnect ${named(context.provider ?? reason.provider)}`,\n }),\n storageFailed: () => ({\n description: \"Nothing changed. Try again.\",\n title: \"The change could not be saved\",\n }),\n cryptoFailed: () => ({\n description: \"Connect the provider again to replace it.\",\n title: \"A stored credential could not be read\",\n }),\n resolverFailed: (reason) => ({\n description: \"The lookup failed, which says nothing about your DNS. Try again in a moment.\",\n title: `DNS lookups through ${reason.resolver} failed`,\n }),\n};\n\nexport const merge = (overrides: Partial<Catalog> = {}): Catalog => ({ ...english, ...overrides });\n\n/** The title and description for a failure, chosen by the error's reason. */\nexport const outcome = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): Outcome => {\n const reason = error.reason;\n switch (reason._tag) {\n case \"InvalidInput\":\n return catalog.invalidInput(reason, context);\n case \"Unauthenticated\":\n return catalog.unauthenticated(reason, context);\n case \"Forbidden\":\n return catalog.forbidden(reason, context);\n case \"NotFound\":\n return catalog.notFound(reason, context);\n case \"Conflict\":\n return catalog.conflict(reason, context);\n case \"Stale\":\n return catalog.stale(reason, context);\n case \"BatchStale\":\n return catalog.batchStale(reason, context);\n case \"Expired\":\n return catalog.expired(reason, context);\n case \"Busy\":\n return catalog.busy(reason, context);\n case \"ProviderRejected\":\n return catalog.providerRejected(reason, context);\n case \"ProviderUnavailable\":\n return catalog.providerUnavailable(reason, context);\n case \"ProviderConflict\":\n return catalog.providerConflict(reason, context);\n case \"Unsupported\":\n return catalog.unsupported(reason, context);\n case \"Reconnect\":\n return catalog.reconnect(reason, context);\n case \"StorageFailed\":\n return catalog.storageFailed(reason, context);\n case \"CryptoFailed\":\n return catalog.cryptoFailed(reason, context);\n case \"ResolverFailed\":\n return catalog.resolverFailed(reason, context);\n }\n};\n\n/** The same failure as one sentence, for a host that renders text rather than a card. */\nexport const failure = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): string => {\n const { description, title } = outcome(error, catalog, context);\n return description === undefined ? `${title}.` : `${title}. ${description}`;\n};\n","import { Transport } from \"domainkit/client\";\nimport * as Effect from \"effect/Effect\";\nimport {\n createContext,\n useCallback,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport type { Listener } from \"./events.ts\";\nimport type { Catalog } from \"./messages.ts\";\nimport { merge as mergeMessages } from \"./messages.ts\";\n\nexport interface RootProps {\n readonly children: ReactNode;\n readonly messages?: Partial<Catalog>;\n /** Where an interactive provider flow sends the customer. Defaults to `window.location`. */\n readonly navigate?: (url: string) => void;\n readonly onEvent?: Listener;\n /**\n * Report the domain's state without the controls that change it, for a customer who may read\n * the domain but not write to it. Capability gating already hides a group the transport does\n * not declare; this covers authorization the transport cannot express, such as a member of an\n * organisation. Every flow carries it on `FlowState.readOnly`, so a surface can explain it.\n */\n readonly readOnly?: boolean;\n /** Bump to re-inspect every mounted domain after a change the UI did not make. */\n readonly revision?: number;\n /** The transport, by value. Rebuilding it inline on every render does not restart controllers. */\n readonly transport: Transport.Interface;\n}\n\ninterface ContextValue {\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n readonly emit: Listener;\n readonly messages: Catalog;\n readonly navigate: (url: string) => void;\n readonly readOnly: boolean;\n readonly revision: number;\n readonly transport: Transport.Interface;\n}\n\nconst Context = createContext<ContextValue | null>(null);\n\nconst navigateInBrowser = (url: string): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\"DomainKit provider authorization requires a browser or a `navigate` prop\");\n }\n window.location.assign(url);\n};\n\nexport interface StableTransport {\n readonly transport: Transport.Interface;\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n}\n\ntype Method = (...args: ReadonlyArray<never>) => Effect.Effect<unknown, unknown>;\n\n/**\n * A transport whose identity survives re-renders. Each method reads the newest transport when it\n * runs, so a host may write `<DomainKit.Root transport={Transport.fromFetch(\"/api/domainkit\")}>`\n * inline and controllers still see one transport for the whole mount. Swapping in a transport\n * that declares different capability groups rebuilds it, and every controller re-runs.\n */\nconst useStableTransport = (transport: Transport.Interface): StableTransport => {\n const latest = useRef(transport);\n useLayoutEffect(() => {\n latest.current = transport;\n });\n const signature = Transport.capabilities(transport).join(\",\");\n return useMemo(() => {\n const capabilities = Transport.capabilities(latest.current);\n const stable = Object.fromEntries(\n capabilities.map((capability) => {\n const group = latest.current[capability] as unknown as Record<string, Method>;\n return [\n capability,\n Object.fromEntries(\n Object.keys(group).map((name) => [\n name,\n (...args: ReadonlyArray<never>) =>\n Effect.suspend(() => {\n const live = latest.current[capability] as unknown as Record<string, Method>;\n const method = live[name];\n if (method === undefined) {\n throw new Error(`The transport no longer declares ${capability}.${name}`);\n }\n return method(...args);\n }),\n ]),\n ),\n ];\n }),\n ) as Transport.Interface;\n return { capabilities, transport: stable };\n }, [signature]);\n};\n\n/**\n * The transport, the catalog, and the two host callbacks every hook below reads. It renders no\n * element of its own: `@domainkit/react` supplies behaviour, state, copy, and accessibility, and\n * the host application supplies the markup.\n */\nexport function Root({\n children,\n messages,\n navigate = navigateInBrowser,\n onEvent,\n readOnly = false,\n revision = 0,\n transport,\n}: RootProps): ReactElement {\n const { capabilities, transport: stable } = useStableTransport(transport);\n const onEventRef = useRef(onEvent);\n useLayoutEffect(() => {\n onEventRef.current = onEvent;\n }, [onEvent]);\n const emit = useCallback<Listener>((event) => {\n try {\n onEventRef.current?.(event);\n } catch {\n // Host observers are best-effort and cannot change a completed operation's outcome.\n }\n }, []);\n const value: ContextValue = {\n capabilities,\n emit,\n messages: mergeMessages(messages),\n navigate,\n readOnly,\n revision,\n transport: stable,\n };\n return <Context.Provider value={value}>{children}</Context.Provider>;\n}\n\nexport function useDomainKit(): ContextValue {\n const value = useContext(Context);\n if (value === null) {\n throw new Error(\"DomainKit hooks must be called inside DomainKit.Root\");\n }\n return value;\n}\n\n/** The catalog `DomainKit.Root` holds, with the host's overrides already merged in. */\nexport function useMessages(): Catalog {\n return useDomainKit().messages;\n}\n\n/** The transport `DomainKit.Root` holds, with the identity it keeps for the whole mount. */\nexport function useTransport(): Transport.Interface {\n return useDomainKit().transport;\n}\n\nconst ReadOnlyContext = createContext<boolean | null>(null);\n\n/** Narrow one subtree to read-only without touching the rest of the page. */\nexport function ReadOnly({\n children,\n value,\n}: {\n readonly children: ReactNode;\n readonly value: boolean;\n}) {\n return <ReadOnlyContext.Provider value={value}>{children}</ReadOnlyContext.Provider>;\n}\n\n/** Whether this surface may offer controls that change the domain. */\nexport function useReadOnly(): boolean {\n const scoped = useContext(ReadOnlyContext);\n const root = useDomainKit().readOnly;\n return scoped ?? root;\n}\n\n/** Which capability groups the host's transport declares, for gating a surface of your own. */\nexport function useCapabilities(): ReadonlyArray<Transport.Capability> {\n return useDomainKit().capabilities;\n}\n","import type { DomainKit, Receipt } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\n\n/** What a customer finished doing, for host notifications, analytics, and audit trails. */\nexport type Event = Data.TaggedEnum<{\n Connected: {\n readonly domain: string;\n readonly connectionId: string;\n readonly snapshot: Transport.Snapshot;\n };\n Detached: { readonly domain: string };\n Disconnected: { readonly domain: string; readonly connectionId: string };\n Applied: { readonly domain: string; readonly receipt: Receipt.Model };\n Cleaned: { readonly domain: string; readonly receipt: Receipt.Model };\n Declined: { readonly domain: string; readonly attempt: Transport.Attempt };\n Failed: { readonly domain: string; readonly error: DomainKit.Error };\n}>;\nexport const Event = Data.taggedEnum<Event>();\n\nexport type Listener = (event: Event) => void;\n","/**\n * The one place the package leaves Effect. Every controller runs its transport calls through\n * `useRunner`, which interrupts the call in flight when a newer one starts or the component\n * unmounts, and drops results that arrive after either.\n */\nimport { DomainKit, Reason } from \"domainkit\";\nimport * as Effect from \"effect/Effect\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nexport interface Runner {\n /**\n * Run `effect`, replacing whatever this runner had in flight. `onSuccess` and `onFailure` fire\n * only while this call is still the newest and the component is mounted.\n */\n readonly run: <A>(\n effect: Effect.Effect<A, DomainKit.Error>,\n handlers: {\n readonly onSuccess: (value: A) => void;\n readonly onFailure: (error: DomainKit.Error) => void;\n },\n ) => void;\n /** Stop the call in flight without starting another. */\n readonly cancel: () => void;\n}\n\n/** A defect is not a lifecycle failure; report it in the shape the UI already renders. */\nconst defect = (cause: unknown): DomainKit.Error =>\n new DomainKit.Error({\n reason: new Reason.ProviderUnavailable({\n provider: \"domainkit\",\n message: `The transport failed: ${String(cause)}`,\n }),\n });\n\ninterface Live {\n readonly id: number;\n interrupt: (() => void) | null;\n}\n\nexport function useRunner(): Runner {\n const state = useRef<{ mounted: boolean; next: number; live: Live | null }>({\n live: null,\n mounted: true,\n next: 0,\n });\n useEffect(() => {\n const current = state.current;\n current.mounted = true;\n return () => {\n current.mounted = false;\n current.live?.interrupt?.();\n current.live = null;\n };\n }, []);\n return useMemo<Runner>(() => {\n const stop = () => {\n state.current.live?.interrupt?.();\n state.current.live = null;\n };\n return {\n cancel: stop,\n run: (effect, handlers) => {\n stop();\n const live: Live = { id: (state.current.next += 1), interrupt: null };\n state.current.live = live;\n const interrupt = Effect.runCallback(effect, {\n onExit: (exit) => {\n if (state.current.live?.id !== live.id || !state.current.mounted) return;\n state.current.live = null;\n if (Exit.isSuccess(exit)) {\n handlers.onSuccess(exit.value);\n return;\n }\n // Read both before the interrupt guard: it narrows `exit` to the success side.\n const cause = exit.cause;\n const error = Exit.findErrorOption(exit);\n if (Exit.hasInterrupts(exit)) return;\n handlers.onFailure(Option.isSome(error) ? error.value : defect(cause));\n },\n });\n // A synchronous effect already ran `onExit` and cleared `live`; only a call still in\n // flight needs an interrupt handle.\n if (state.current.live?.id === live.id) live.interrupt = () => interrupt();\n },\n };\n }, []);\n}\n","/**\n * The plan -> approve -> apply machine both `Provision` and `Cleanup` run. They differ only in\n * which plan they build and which event they emit when the receipt lands, so the machine lives\n * here once and each namespace exports its own controller over it.\n */\nimport type { Approval, DomainKit, Plan, Receipt } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport type State = Data.TaggedEnum<{\n Idle: {};\n Planning: {};\n Planned: { readonly plan: Plan.Model };\n Approving: { readonly plan: Plan.Model };\n Applying: { readonly plan: Plan.Model; readonly approval: Approval.Model };\n Applied: { readonly plan: Plan.Model | null; readonly receipt: Receipt.Model };\n Rejecting: { readonly plan: Plan.Model };\n Rejected: { readonly plan: Plan.Model; readonly attempt: Transport.Attempt };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const State = Data.taggedEnum<State>();\n\n/** The verbs `Provision` and `Cleanup` share on the wire. */\nexport interface Group {\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Effect.Effect<Approval.Model, DomainKit.Error>;\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Effect.Effect<Transport.Attempt, DomainKit.Error>;\n readonly apply: (\n approvalId: Approval.ApprovalId,\n ) => Effect.Effect<Receipt.Model, DomainKit.Error>;\n}\n\nexport interface Controller {\n readonly state: State;\n /** Build a plan. The plan itself rides on the state, from `Planned` through `Applied`. */\n readonly plan: () => void;\n /** Authorize the digest and apply it. Pass `operationIds` to approve part of the plan. */\n readonly approve: (operationIds?: ReadonlyArray<Plan.OperationId>) => void;\n /** Decline the plan. Terminal: approving it afterwards fails `Stale`. */\n readonly reject: (reason?: string) => void;\n /** Apply the approval this controller already holds. */\n readonly apply: () => void;\n /** Re-plan when the zone moved under the plan, otherwise re-run the step that failed. */\n readonly retry: () => void;\n readonly reset: () => void;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * Identifies the inputs this attempt is for. When it changes the attempt is abandoned, because a\n * plan, approval, and receipt only mean anything for the inputs that produced them.\n */\n readonly key: string;\n readonly group: Group | undefined;\n /** The plan call, or `null` when this flow has nothing to plan yet. */\n readonly plan: () => Effect.Effect<Plan.Model, DomainKit.Error> | null;\n readonly done: (receipt: Receipt.Model) => Event;\n readonly onDone: ((receipt: Receipt.Model) => void) | undefined;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly: boolean | undefined;\n}\n\n/** Reasons that mean the plan itself is gone: retrying the same step would fail the same way. */\nconst needsNewPlan = (error: DomainKit.Error): boolean =>\n error.reason._tag === \"Stale\" ||\n error.reason._tag === \"Expired\" ||\n error.reason._tag === \"Conflict\";\n\n/** The plan an attempt holds, whatever step it is on; `null` before there is one. */\nexport const planOf = (state: State): Plan.Model | null => {\n switch (state._tag) {\n case \"Planned\":\n case \"Approving\":\n case \"Applying\":\n case \"Rejecting\":\n case \"Rejected\":\n case \"Applied\":\n return state.plan;\n case \"Idle\":\n case \"Planning\":\n case \"Failure\":\n return null;\n }\n};\n\n/**\n * The plan still awaiting its apply, which is what a row of records reports; `null` once one has\n * landed, because from then on an observation answers instead.\n */\nexport const pendingPlan = (state: State): Plan.Model | null => {\n switch (state._tag) {\n case \"Planned\":\n case \"Approving\":\n case \"Applying\":\n return state.plan;\n case \"Idle\":\n case \"Planning\":\n case \"Applied\":\n case \"Rejecting\":\n case \"Rejected\":\n case \"Failure\":\n return null;\n }\n};\n\nexport function useAttempt(options: Options): Controller {\n const { domain, done, group, key, onDone } = options;\n const { emit } = useDomainKit();\n const inherited = useReadOnly();\n // Every step of an attempt is a write, planning included: a plan is an attempt the server\n // records. A read-only surface may render a button anyway, so the refusal lives here.\n const readOnly = options.readOnly ?? inherited;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Idle());\n // The key travels with what it produced, so a command raised before the reset commits still\n // refuses to run: a plan built for one domain must never be approved for another.\n const held = useRef<{\n key: string;\n plan: Plan.Model | null;\n approval: Approval.Model | null;\n }>({ approval: null, key, plan: null });\n const lastCommand = useRef<{ key: string; run: () => void } | null>(null);\n const build = useRef(options.plan);\n useEffect(() => {\n build.current = options.plan;\n });\n\n // Abandoning while rendering, not one effect later, is what makes the guards below sound: a\n // reply that lands in between finds the new key already recorded and drops itself.\n const [current, setCurrent] = useState(key);\n if (current !== key) {\n setCurrent(key);\n runner.cancel();\n held.current = { approval: null, key, plan: null };\n lastCommand.current = null;\n setState(State.Idle());\n }\n\n const onFailure = useCallback(\n (error: DomainKit.Error) => {\n setState(State.Failure({ error }));\n emit(Event.Failed({ domain, error }));\n },\n [domain, emit],\n );\n\n const applyWith = useCallback(\n (plan: Plan.Model, approval: Approval.Model) => {\n if (readOnly || group === undefined || held.current.key !== key) return;\n const command = () => {\n setState(State.Applying({ approval, plan }));\n runner.run(group.apply(approval.id), {\n onFailure,\n onSuccess: (receipt) => {\n setState(State.Applied({ plan, receipt }));\n emit(done(receipt));\n onDone?.(receipt);\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [done, emit, group, key, onDone, onFailure, readOnly, runner],\n );\n\n const buildPlan = useCallback(() => {\n if (readOnly) return;\n const effect = build.current();\n if (effect === null) return;\n const command = () => {\n setState(State.Planning());\n runner.run(effect, {\n onFailure,\n onSuccess: (plan) => {\n if (held.current.key !== key) return;\n held.current = { approval: null, key, plan };\n setState(State.Planned({ plan }));\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n }, [key, onFailure, readOnly, runner]);\n\n const approve = useCallback(\n (operationIds?: ReadonlyArray<Plan.OperationId>) => {\n const plan = held.current.plan;\n if (readOnly || group === undefined || plan === null || held.current.key !== key) return;\n const command = () => {\n setState(State.Approving({ plan }));\n runner.run(\n group.approve({\n planId: plan.id,\n ...(operationIds === undefined ? {} : { operationIds }),\n }),\n {\n onFailure,\n onSuccess: (approval) => {\n if (held.current.key !== key) return;\n held.current = { approval, key, plan };\n applyWith(plan, approval);\n },\n },\n );\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [applyWith, group, key, onFailure, readOnly, runner],\n );\n\n const reject = useCallback(\n (reason?: string) => {\n const plan = held.current.plan;\n if (readOnly || group === undefined || plan === null || held.current.key !== key) return;\n const command = () => {\n setState(State.Rejecting({ plan }));\n runner.run(group.reject({ planId: plan.id, ...(reason === undefined ? {} : { reason }) }), {\n onFailure,\n onSuccess: (attempt) => {\n setState(State.Rejected({ attempt, plan }));\n emit(Event.Declined({ attempt, domain }));\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [domain, emit, group, key, onFailure, readOnly, runner],\n );\n\n const apply = useCallback(() => {\n const { approval, plan } = held.current;\n if (readOnly || approval === null || plan === null) return;\n applyWith(plan, approval);\n }, [applyWith]);\n\n const retry = useCallback(() => {\n // Every step of an attempt is a write, so read-only has nothing to retry.\n if (readOnly) return;\n if (state._tag === \"Failure\" && needsNewPlan(state.error)) {\n held.current = { approval: null, key, plan: null };\n buildPlan();\n return;\n }\n const command = lastCommand.current;\n if (command === null || command.key !== key) buildPlan();\n else command.run();\n }, [buildPlan, key, readOnly, state]);\n\n const reset = useCallback(() => {\n runner.cancel();\n held.current = { approval: null, key, plan: null };\n lastCommand.current = null;\n setState(State.Idle());\n }, [key, runner]);\n\n return { apply, approve, plan: buildPlan, reject, reset, retry, state };\n}\n","import { DomainKit, Reason, Receipt } from \"domainkit\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback } from \"react\";\n\nimport { pendingPlan, planOf, State, useAttempt, type Controller } from \"./attempt.ts\";\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\n\nexport { pendingPlan, planOf, State };\nexport type { Controller };\n\nexport interface Options {\n readonly domain: string;\n /** Which apply to undo. Without it, the domain's latest provisioning receipt. */\n readonly receiptId?: Receipt.ReceiptId;\n readonly onCleaned?: (receipt: Receipt.Model) => void;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\n/**\n * Cleanup is bound to a receipt: it removes only what an apply proved DomainKit created. When the\n * host does not name one, the controller reads the domain's latest from the snapshot.\n */\nexport function useController({ domain, onCleaned, readOnly, receiptId }: Options): Controller {\n const { transport } = useDomainKit();\n const group = transport.cleanup;\n const connection = transport.connection;\n return useAttempt({\n domain,\n key: [domain, receiptId ?? \"\"].join(\"|\"),\n done: (receipt) => Event.Cleaned({ domain, receipt }),\n group,\n onDone: onCleaned,\n readOnly,\n plan: useCallback(() => {\n if (group === undefined) return null;\n if (receiptId !== undefined) return group.plan(receiptId);\n if (connection === undefined) return null;\n return Effect.flatMap(connection.inspect(domain), (snapshot) =>\n snapshot.lastReceiptId === null\n ? Effect.fail(\n new DomainKit.Error({\n reason: new Reason.NotFound({ entity: \"receipt\", id: snapshot.domain }),\n }),\n )\n : group.plan(Receipt.ReceiptId.make(snapshot.lastReceiptId)),\n );\n }, [connection, domain, group, receiptId]),\n });\n}\n","/**\n * Adding a domain is one input. The zones every connected account reaches load when the field\n * mounts, typing filters them, Tab completes the highlighted one while keeping whatever subdomain\n * was typed in front of it, and the surface names the account the records will go to.\n *\n * The listbox is built here rather than on a combobox primitive because the completion rule is not\n * a selection model: a suggestion never replaces what the customer typed, it finishes it, and a\n * domain outside every zone leaves the input a plain text field.\n */\nimport type { DomainKit } from \"domainkit\";\nimport { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type AriaAttributes,\n type FocusEventHandler,\n type FormEventHandler,\n type KeyboardEventHandler,\n type MouseEventHandler,\n} from \"react\";\n\nimport type { Descriptor } from \"./connect.ts\";\nimport { useDomainKit, useMessages, useReadOnly } from \"./domain-kit.tsx\";\nimport { useRunner } from \"./task.ts\";\n\nexport type Zone = Transport.Zone;\nexport type Account = Transport.Zones[\"connections\"][number];\nexport type AuthMethod = Descriptor[\"methods\"][number];\n\n/** Where a domain's records would go: the connection that serves it, and in which zone. */\nexport interface Placement {\n readonly connectionId: string;\n readonly zone: string;\n}\n\n// ---------------------------------------------------------------------------------------------\n// useZones\n// ---------------------------------------------------------------------------------------------\n\nexport type ZonesState = Data.TaggedEnum<{\n Loading: {};\n Ready: {\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const ZonesState = Data.taggedEnum<ZonesState>();\n\nexport interface ZonesController {\n readonly state: ZonesState;\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n readonly refresh: () => void;\n}\n\nexport interface ZonesOptions {\n /** Only this provider's connections. Omit for every connection this owner holds. */\n readonly provider?: string;\n}\n\nconst nothing = {\n connections: [] as ReadonlyArray<Account>,\n providers: [] as ReadonlyArray<Descriptor>,\n zones: [] as ReadonlyArray<Zone>,\n};\n\n/**\n * Every zone this owner's connections reach. A connection whose credential the provider turned\n * down is listed in `connections` as `reconnect` and contributes no zones, so one dead account\n * never costs the customer the others.\n */\nexport function useZones({ provider }: ZonesOptions = {}): ZonesController {\n const { revision, transport } = useDomainKit();\n const connection = transport.connection;\n const runner = useRunner();\n const [state, setState] = useState<ZonesState>(ZonesState.Loading());\n\n const load = useCallback(() => {\n if (connection === undefined) return;\n setState(ZonesState.Loading());\n runner.run(connection.zones(provider === undefined ? {} : { provider }), {\n onFailure: (error) => setState(ZonesState.Failure({ error })),\n onSuccess: (listing) =>\n setState(\n ZonesState.Ready({\n connections: listing.connections,\n providers: listing.providers,\n zones: listing.zones,\n }),\n ),\n });\n }, [connection, provider, runner]);\n\n useEffect(load, [load, revision]);\n\n const held = state._tag === \"Ready\" ? state : nothing;\n return {\n connections: held.connections,\n providers: held.providers,\n refresh: load,\n state,\n zones: held.zones,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// useAccounts\n// ---------------------------------------------------------------------------------------------\n\nexport interface ConnectAccountInput {\n readonly provider: string;\n readonly method: AuthMethod[\"kind\"];\n /** Keyed by the descriptor's field names. Ignored by the interactive methods. */\n readonly values?: Readonly<Record<string, string>>;\n}\n\nexport type AccountsState = Data.TaggedEnum<{\n Loading: {};\n Ready: {};\n Submitting: { readonly provider: string };\n Redirecting: { readonly url: string };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const AccountsState = Data.taggedEnum<AccountsState>();\n\nexport interface AccountsController {\n readonly state: AccountsState;\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n /** Connect a provider with no domain attached. The account is what the customer is granting. */\n readonly connect: (input: ConnectAccountInput) => void;\n /**\n * Prove an account again for a connection the owner already holds. The connection and its\n * domains stay; only the credential behind it is replaced.\n */\n readonly reconnect: (input: ConnectAccountInput & { readonly connectionId: string }) => void;\n readonly refresh: () => void;\n}\n\nexport interface AccountsOptions {\n /** Where an interactive method returns the customer. Defaults to the page they started from. */\n readonly returnTo?: string | null;\n /** Refuse the commands that grant an account. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\nconst currentUrl = (): string | null =>\n typeof window === \"undefined\" ? null : window.location.href;\n\n/**\n * The accounts this owner holds, and the one way to add another: connect a provider without naming\n * a domain. A token method finishes in place; an interactive one redirects and comes back through\n * the library's own callback, which lands on `returnTo`.\n */\nexport function useAccounts({\n readOnly: refused,\n returnTo,\n}: AccountsOptions = {}): AccountsController {\n const { navigate, transport } = useDomainKit();\n const inherited = useReadOnly();\n // Granting an account is a write like any other, so the refusal lives here rather than in the\n // markup a host wrote.\n const readOnly = refused ?? inherited;\n const connection = transport.connection;\n const runner = useRunner();\n const listing = useZones();\n const [command, setCommand] = useState<AccountsState | null>(null);\n\n const refresh = listing.refresh;\n const submit = useCallback(\n (input: ConnectAccountInput & { readonly connectionId?: string }) => {\n if (connection === undefined || readOnly) return;\n const destination = returnTo === undefined ? currentUrl() : returnTo;\n const interactive = destination === null ? {} : { returnTo: destination };\n const method =\n input.method === \"token\"\n ? Transport.Method.token(input.values ?? {})\n : input.method === \"oauth\"\n ? Transport.Method.oauth(interactive)\n : Transport.Method.integration(interactive);\n setCommand(AccountsState.Submitting({ provider: input.provider }));\n const granting =\n input.connectionId === undefined\n ? connection.start({ method, provider: input.provider })\n : connection.reconnect({ connectionId: input.connectionId, method });\n runner.run(granting, {\n onFailure: (error) => setCommand(AccountsState.Failure({ error })),\n onSuccess: (started) => {\n if (started._tag === \"Redirect\") {\n setCommand(AccountsState.Redirecting({ url: started.authorizationUrl }));\n navigate(started.authorizationUrl);\n return;\n }\n // A selection is about a domain and this flow names none, so the account is connected.\n setCommand(null);\n refresh();\n },\n });\n },\n [connection, navigate, readOnly, refresh, returnTo, runner],\n );\n const connect = useCallback((input: ConnectAccountInput) => submit(input), [submit]);\n const reconnect = useCallback(\n (input: ConnectAccountInput & { readonly connectionId: string }) => submit(input),\n [submit],\n );\n\n const state =\n command ??\n (listing.state._tag === \"Loading\"\n ? AccountsState.Loading()\n : listing.state._tag === \"Failure\"\n ? AccountsState.Failure({ error: listing.state.error })\n : AccountsState.Ready());\n\n return {\n connect,\n reconnect,\n connections: listing.connections,\n providers: listing.providers,\n refresh,\n state,\n zones: listing.zones,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// Matching\n// ---------------------------------------------------------------------------------------------\n\nconst normalize = (value: string): string => value.trim().toLowerCase().replace(/\\.$/, \"\");\n\n/**\n * The zone a value already sits in: the longest listed zone the value is at or under. Two accounts\n * can serve the same zone, so `preferred` names the one the customer picked and wins among equals;\n * without it the first listed account answers.\n */\nexport const placementOf = (\n value: string,\n zones: ReadonlyArray<Zone>,\n preferred?: Placement | null,\n): { readonly zone: Zone; readonly placement: Placement } | null => {\n const domain = normalize(value);\n if (domain === \"\") return null;\n const matching = zones.filter((candidate) => {\n const zone = normalize(candidate.zone);\n return domain === zone || domain.endsWith(`.${zone}`);\n });\n const longest = matching.reduce(\n (best, candidate) =>\n best === null || normalize(candidate.zone).length > normalize(best.zone).length\n ? candidate\n : best,\n null as Zone | null,\n );\n if (longest === null) return null;\n const closest = matching.filter(\n (candidate) => normalize(candidate.zone) === normalize(longest.zone),\n );\n const best =\n closest.find(\n (candidate) =>\n preferred != null &&\n candidate.connectionId === preferred.connectionId &&\n normalize(candidate.zone) === normalize(preferred.zone),\n ) ??\n closest[0] ??\n longest;\n return { placement: { connectionId: best.connectionId, zone: best.zone }, zone: best };\n};\n\n/**\n * What the customer typed in front of the zone they are reaching for. \"mail.ex\" against\n * `example.com` is the subdomain \"mail\"; \"ex\" on its own is none.\n */\nconst subdomainOf = (value: string, zone: string): string => {\n const typed = normalize(value);\n const target = normalize(zone);\n if (typed === \"\" || target.startsWith(typed)) return \"\";\n const cut = typed.lastIndexOf(\".\");\n if (cut < 0) return \"\";\n const head = typed.slice(0, cut);\n const tail = typed.slice(cut + 1);\n return target.startsWith(tail) ? head : \"\";\n};\n\n/** Zones the typed value is reaching for: a prefix of the zone, or a subdomain of one. */\nexport const suggestionsFor = (value: string, zones: ReadonlyArray<Zone>): ReadonlyArray<Zone> => {\n const typed = normalize(value);\n if (typed === \"\") return zones;\n return zones.filter((candidate) => {\n const zone = normalize(candidate.zone);\n if (zone.startsWith(typed)) return true;\n const cut = typed.lastIndexOf(\".\");\n if (cut < 0) return false;\n const tail = typed.slice(cut + 1);\n return tail !== \"\" && zone.startsWith(tail);\n });\n};\n\n/** The value a suggestion completes to: whatever subdomain was typed, then the zone. */\nexport const completionOf = (value: string, zone: Zone): string => {\n const subdomain = subdomainOf(value, zone.zone);\n return subdomain === \"\" ? zone.zone : `${subdomain}.${zone.zone}`;\n};\n\n// ---------------------------------------------------------------------------------------------\n// useDomainField\n// ---------------------------------------------------------------------------------------------\n\nconst optionId = (listId: string, zone: Zone): string =>\n `${listId}-${zone.connectionId}-${zone.zone}`;\n\nexport interface DomainFieldOptions {\n /** Every zone the surface offers, which `useZones` or `useAccounts` already holds. */\n readonly zones: ReadonlyArray<Zone>;\n readonly value: string;\n readonly onChange: (value: string) => void;\n /**\n * Fires when the value or the account it resolves to changes, so a host holds the two together\n * and submits them together. It reports the value as typed, not only the placement, because a\n * form needs the name the customer is on as well as where its records would go.\n */\n readonly onResolve?: (input: {\n readonly domain: string;\n readonly connection: Placement | null;\n }) => void;\n /** The input's id. The listbox and its options are named from it; one is generated otherwise. */\n readonly id?: string;\n}\n\n/** The props one suggestion carries, so the option is a listbox option to a screen reader. */\nexport interface OptionProps {\n readonly \"aria-selected\": boolean;\n readonly id: string;\n readonly onMouseDown: MouseEventHandler<Element>;\n readonly role: \"option\";\n}\n\nexport interface DomainFieldController {\n /** Whether the listbox is showing: the customer opened it and there is something in it. */\n readonly open: boolean;\n /** The zones the typed value is reaching for, in the order they were listed. */\n readonly suggestions: ReadonlyArray<Zone>;\n /** The suggestion Tab and Enter would complete, or `null` when the list is empty. */\n readonly highlighted: Zone | null;\n /** The zone the value already sits in, with the account its records would go to. */\n readonly found: { readonly zone: Zone; readonly placement: Placement } | null;\n /** Finish the name from one suggestion, keeping whatever subdomain was typed in front of it. */\n readonly complete: (zone: Zone) => void;\n readonly close: () => void;\n readonly inputProps: {\n readonly \"aria-activedescendant\": AriaAttributes[\"aria-activedescendant\"];\n readonly \"aria-autocomplete\": \"list\";\n readonly \"aria-controls\": string;\n readonly \"aria-expanded\": boolean;\n readonly autoComplete: \"off\";\n readonly id: string;\n readonly onChange: FormEventHandler<HTMLInputElement>;\n readonly onFocus: FocusEventHandler<HTMLInputElement>;\n readonly onKeyDown: KeyboardEventHandler<HTMLInputElement>;\n readonly role: \"combobox\";\n readonly type: \"text\";\n readonly value: string;\n };\n readonly listboxProps: {\n readonly \"aria-label\": string;\n readonly hidden: boolean;\n readonly id: string;\n readonly role: \"listbox\";\n };\n readonly optionProps: (zone: Zone) => OptionProps;\n}\n\n/**\n * One input over every zone the workspace's accounts reach, as props rather than markup. Arrow\n * keys move the highlight, Tab or Enter completes it, Escape closes the list, and `found` says\n * where the records will go.\n */\nexport function useDomainField({\n id,\n onChange,\n onResolve,\n value,\n zones,\n}: DomainFieldOptions): DomainFieldController {\n const messages = useMessages();\n const generated = useId();\n const inputId = id ?? generated;\n const listId = `${inputId}-suggestions`;\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(0);\n // Which account the customer completed from, so a zone two accounts both serve stays the one\n // they picked rather than whichever the listing happens to hold first. `placementOf` honours it\n // only while the value still sits in that zone, so a value that moves — whether the customer\n // typed it or the host set it — loses the preference by the same rule.\n const [chosen, setChosen] = useState<Placement | null>(null);\n const suggestions = suggestionsFor(value, zones);\n const highlighted = suggestions[Math.min(active, Math.max(suggestions.length - 1, 0))] ?? null;\n const found = placementOf(value, zones, chosen);\n const showing = open && suggestions.length > 0;\n\n // One report per value and placement: a re-render that changes neither says nothing.\n const placement = found?.placement ?? null;\n const connectionId = placement?.connectionId ?? null;\n const placedIn = placement?.zone ?? null;\n const announced = useRef<string | null>(null);\n useEffect(() => {\n const signature = `${value}|${connectionId ?? \"\"}|${placedIn ?? \"\"}`;\n if (announced.current === signature) return;\n announced.current = signature;\n onResolve?.({\n connection:\n connectionId === null || placedIn === null ? null : { connectionId, zone: placedIn },\n domain: value,\n });\n }, [connectionId, onResolve, placedIn, value]);\n\n const complete = (zone: Zone) => {\n onChange(completionOf(value, zone));\n setChosen({ connectionId: zone.connectionId, zone: zone.zone });\n setOpen(false);\n setActive(0);\n };\n\n return {\n close: () => setOpen(false),\n complete,\n found,\n highlighted,\n inputProps: {\n \"aria-activedescendant\":\n showing && highlighted !== null ? optionId(listId, highlighted) : undefined,\n \"aria-autocomplete\": \"list\",\n \"aria-controls\": listId,\n \"aria-expanded\": showing,\n autoComplete: \"off\",\n id: inputId,\n onChange: (event) => {\n onChange((event.target as HTMLInputElement).value);\n setActive(0);\n setOpen(true);\n },\n onFocus: () => setOpen(true),\n onKeyDown: (event) => {\n if (event.key === \"Escape\") {\n setOpen(false);\n return;\n }\n if (suggestions.length === 0) return;\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActive((index) => (index + 1) % suggestions.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setOpen(true);\n setActive((index) => (index + suggestions.length - 1) % suggestions.length);\n return;\n }\n // Tab and Enter finish the name rather than choosing one: what the customer typed in\n // front of the zone stays in front of it.\n if ((event.key === \"Tab\" || event.key === \"Enter\") && showing && highlighted !== null) {\n event.preventDefault();\n complete(highlighted);\n }\n },\n role: \"combobox\",\n type: \"text\",\n value,\n },\n listboxProps: {\n \"aria-label\": messages.zoneSuggestions,\n hidden: !showing,\n id: listId,\n role: \"listbox\",\n },\n open: showing,\n optionProps: (zone) => ({\n \"aria-selected\": zone === highlighted,\n id: optionId(listId, zone),\n // The press must not take focus off the input before the completion lands.\n onMouseDown: (event) => {\n event.preventDefault();\n complete(zone);\n },\n role: \"option\",\n }),\n suggestions,\n };\n}\n","import { Receipt, type DomainKit, type Storage } from \"domainkit\";\nimport { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport {\n AccountsState,\n completionOf,\n placementOf,\n suggestionsFor,\n useAccounts,\n useDomainField,\n useZones,\n ZonesState,\n type Account,\n type AccountsController,\n type AccountsOptions,\n type ConnectAccountInput,\n type DomainFieldController,\n type DomainFieldOptions,\n type Placement,\n type Zone,\n type ZonesController,\n type ZonesOptions,\n} from \"./domain-field.ts\";\n\nexport type Snapshot = Transport.Snapshot;\nexport type Discovery = Transport.Discovery;\nexport type Candidate = Transport.Candidate;\n/** A provider as the snapshot describes it: an id, a display name, and its auth methods. */\nexport type Descriptor = Transport.Snapshot[\"providers\"][number];\nexport type MethodDescriptor = Descriptor[\"methods\"][number];\nexport type Field = NonNullable<MethodDescriptor[\"fields\"]>[number];\n\n/**\n * Where a domain stands with its DNS provider. `Disconnected` carries whatever\n * `connection.discover` found, so the UI can offer a connection the customer already has before\n * asking for another one.\n */\nexport type State = Data.TaggedEnum<{\n Loading: { readonly snapshot: Snapshot | null };\n Disconnected: { readonly snapshot: Snapshot; readonly discovery: Discovery | null };\n Connected: { readonly snapshot: Snapshot };\n Reconnect: { readonly snapshot: Snapshot };\n Submitting: { readonly snapshot: Snapshot | null; readonly discovery: Discovery | null };\n Redirecting: { readonly url: string };\n SelectionRequired: {\n readonly snapshot: Snapshot | null;\n readonly connectionId: string;\n readonly candidates: ReadonlyArray<Candidate>;\n };\n Failure: {\n readonly error: DomainKit.Error;\n readonly snapshot: Snapshot | null;\n readonly discovery: Discovery | null;\n /** The provider and method the customer was using, when a command failed rather than a read. */\n readonly attempt: Attempt | null;\n };\n}>;\nexport const State = Data.taggedEnum<State>();\n\n/** Which provider and method the failed command was for, so the form can answer beside it. */\nexport interface Attempt {\n readonly provider: string;\n readonly method: Storage.AuthMethod;\n}\n\nexport interface ConnectInput {\n readonly provider: string;\n readonly method: Storage.AuthMethod;\n /** Keyed by the descriptor's field names. Ignored by the interactive methods. */\n readonly values?: Readonly<Record<string, string>>;\n /** Where an interactive method returns the customer. */\n readonly returnTo?: string;\n}\n\nexport interface Controller {\n readonly domain: string;\n /**\n * What this domain's last apply landed, read once per receipt id and held here. `null` until\n * the snapshot names a receipt, or when the transport carries no provisioning group.\n */\n readonly receipt: Receipt.Model | null;\n /**\n * How many times a connection has been established for this domain on this surface: a token\n * connect that landed, or a load that followed this library's own redirect back. It only ever\n * grows, so a flow acts on a change rather than on a state that would fire again every render.\n */\n readonly established: number;\n readonly state: State;\n readonly snapshot: Snapshot | null;\n readonly discovery: Discovery | null;\n readonly providers: ReadonlyArray<Descriptor>;\n readonly connect: (input: ConnectInput) => void;\n /** Attach the domain to a connection this owner already has. */\n readonly reuse: (input: { readonly connectionId: string; readonly zone?: string }) => void;\n /** Answer `SelectionRequired` by naming the zone that serves the domain. */\n readonly select: (zone: string) => void;\n readonly detach: () => void;\n readonly disconnect: () => void;\n /** Re-inspect the domain, discarding any failure. */\n readonly refresh: () => void;\n /** Re-run the step that failed; without one, re-inspect. */\n readonly retry: () => void;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * Where an interactive method returns the customer. Defaults to the page they started from;\n * pass `null` to send none and let the server's `defaultReturnTo` decide.\n */\n readonly returnTo?: string | null;\n /**\n * Refuse every command that changes the connection. Defaults to the surrounding `readOnly`,\n * which is `DomainKit.Root`'s unless a `DomainKit.ReadOnly` narrows it.\n */\n readonly readOnly?: boolean;\n}\n\n/**\n * An interactive method leaves the page and comes back, so what the library knew is gone with it.\n * It writes down the domain it sent the customer away for, and the load that follows reads it once:\n * that, not a query parameter a host would have to keep, is how a return is told from a reload.\n */\nconst RETURNING = \"domainkit.returning\";\n\nconst markReturn = (domain: string): void => {\n try {\n sessionStorage.setItem(RETURNING, domain);\n } catch {\n // A browser with storage turned off simply loses the one-click return.\n }\n};\n\nconst tookReturn = (domain: string): boolean => {\n try {\n if (sessionStorage.getItem(RETURNING) !== domain) return false;\n sessionStorage.removeItem(RETURNING);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Read at connect time, not at render, so it is the page the customer is actually on. */\nconst currentUrl = (): string | null =>\n typeof window === \"undefined\" ? null : window.location.href;\n\nconst snapshotOf = (state: State): Snapshot | null => {\n switch (state._tag) {\n case \"Connected\":\n case \"Reconnect\":\n case \"Disconnected\":\n return state.snapshot;\n case \"Loading\":\n case \"Submitting\":\n case \"SelectionRequired\":\n case \"Failure\":\n return state.snapshot;\n case \"Redirecting\":\n return null;\n }\n};\n\nconst settled = (snapshot: Snapshot, discovery: Discovery | null): State => {\n switch (snapshot.status) {\n case \"connected\":\n return State.Connected({ snapshot });\n case \"reconnect\":\n return State.Reconnect({ snapshot });\n case \"disconnected\":\n return State.Disconnected({ discovery, snapshot });\n }\n};\n\n/**\n * The domain's connection, and the four ways to change it. Discovery runs on mount whenever the\n * transport declares it and the domain has no connection yet; a discovery failure is not the\n * customer's problem, so the provider list still renders.\n */\nexport function useController({ domain, readOnly: refused, returnTo }: Options): Controller {\n const { emit, navigate, revision, transport } = useDomainKit();\n const inherited = useReadOnly();\n // The surface is the host's now, so a control it renders anyway must not reach the transport:\n // every command that changes the connection is refused here rather than hidden up there.\n const readOnly = refused ?? inherited;\n const connection = transport.connection;\n const provisioning = transport.provisioning;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Loading({ snapshot: null }));\n\n // The snapshot and the discovery belong to the domain they were read for, so a controller\n // pointed at a new domain drops both while rendering rather than one effect later.\n // What was read travels with the domain it was read for, so a command or a reply that arrives\n // after the controller moved refuses to act: one domain's attachment must never be detached for\n // another.\n const held = useRef<{\n domain: string;\n snapshot: Snapshot | null;\n discovery: Discovery | null;\n }>({ discovery: null, domain, snapshot: null });\n const lastCommand = useRef<{ domain: string; run: () => void } | null>(null);\n // What the customer was doing when it failed, so the dialog can answer beside that method.\n const attempted = useRef<Attempt | null>(null);\n\n const [established, setEstablished] = useState(0);\n const [inspected, setInspected] = useState(domain);\n if (inspected !== domain) {\n setInspected(domain);\n runner.cancel();\n held.current = { discovery: null, domain, snapshot: null };\n lastCommand.current = null;\n setState(State.Loading({ snapshot: null }));\n }\n\n // A failure keeps what was already read: the customer's provider list, the domain in the\n // dialog's description, and the discovery that offered a connection they already have.\n const onFailure = useCallback(\n (error: DomainKit.Error) => {\n setState(\n State.Failure({\n attempt: attempted.current,\n discovery: held.current.discovery,\n error,\n snapshot: held.current.snapshot,\n }),\n );\n emit(Event.Failed({ domain, error }));\n },\n [domain, emit],\n );\n\n const load = useCallback(() => {\n if (connection === undefined) return;\n lastCommand.current = null;\n attempted.current = null;\n held.current = { discovery: null, domain, snapshot: null };\n // A refresh keeps the snapshot on screen; a domain change already cleared it.\n setState((previous) => State.Loading({ snapshot: snapshotOf(previous) }));\n runner.run(\n Effect.flatMap(connection.inspect(domain), (snapshot) =>\n snapshot.status === \"disconnected\"\n ? Effect.map(\n connection.discover(domain).pipe(Effect.catch(() => Effect.succeed(null))),\n (discovery) => ({ discovery, snapshot }),\n )\n : Effect.succeed({ discovery: null, snapshot }),\n ),\n {\n onFailure,\n onSuccess: ({ discovery, snapshot }) => {\n if (held.current.domain !== domain) return;\n held.current = { discovery, domain, snapshot };\n // The marker answers exactly one load: the one that came back. It is spent whatever\n // that load found, so an authorization the customer abandoned cannot leave it lying\n // there for an ordinary page view to read as a return weeks later.\n const returned = tookReturn(domain);\n if (returned && snapshot.status === \"connected\") {\n setEstablished((count) => count + 1);\n }\n setState(settled(snapshot, discovery));\n },\n },\n );\n }, [connection, domain, onFailure, runner]);\n\n useEffect(load, [load, revision]);\n\n const started = useCallback(\n (result: Transport.Started) => {\n if (held.current.domain !== domain) return;\n switch (result._tag) {\n case \"Connected\": {\n const snapshot = result.snapshot;\n setEstablished((count) => count + 1);\n // This controller is one domain's, so every command it sends carries that domain and\n // comes back with its snapshot. A reply without one connected an account alone, which\n // only a host calling the transport directly can do, so read the domain again.\n if (snapshot === null) {\n load();\n return;\n }\n held.current = { discovery: null, domain, snapshot };\n setState(settled(snapshot, null));\n if (snapshot.connectionId !== null) {\n emit(Event.Connected({ connectionId: snapshot.connectionId, domain, snapshot }));\n }\n return;\n }\n case \"Redirect\":\n markReturn(domain);\n setState(State.Redirecting({ url: result.authorizationUrl }));\n navigate(result.authorizationUrl);\n return;\n case \"SelectionRequired\":\n setState(\n State.SelectionRequired({\n candidates: result.candidates,\n connectionId: result.connectionId,\n snapshot: held.current.snapshot,\n }),\n );\n return;\n }\n },\n [domain, emit, load, navigate],\n );\n\n const submit = useCallback(\n (effect: Effect.Effect<Transport.Started, DomainKit.Error>, attempt: Attempt | null) => {\n if (held.current.domain !== domain) return;\n attempted.current = attempt;\n const command = () => {\n setState(\n State.Submitting({\n discovery: held.current.discovery,\n snapshot: held.current.snapshot,\n }),\n );\n runner.run(effect, { onFailure, onSuccess: started });\n };\n lastCommand.current = { domain, run: command };\n command();\n },\n [domain, onFailure, runner, started],\n );\n\n const connect = useCallback(\n (input: ConnectInput) => {\n if (connection === undefined || readOnly) return;\n const destination = input.returnTo ?? (returnTo === undefined ? currentUrl() : returnTo);\n const interactive = destination === null ? {} : { returnTo: destination };\n const method =\n input.method === \"token\"\n ? Transport.Method.token(input.values ?? {})\n : input.method === \"oauth\"\n ? Transport.Method.oauth(interactive)\n : Transport.Method.integration(interactive);\n // A domain whose connection the provider turned down is not asking for a second account:\n // proving the same provider again re-credits the connection it already has, and the domains\n // on it stay where they are. Starting instead would fail, because the domain is attached.\n const snapshot = held.current.snapshot;\n const stale =\n snapshot?.status === \"reconnect\" &&\n snapshot.provider === input.provider &&\n snapshot.connectionId !== null;\n submit(\n stale && snapshot?.connectionId != null\n ? connection.reconnect({ connectionId: snapshot.connectionId, method })\n : connection.start({ domain, method, provider: input.provider }),\n { method: input.method, provider: input.provider },\n );\n },\n [connection, domain, readOnly, returnTo, submit],\n );\n\n const reuse = useCallback(\n (input: { readonly connectionId: string; readonly zone?: string }) => {\n if (connection === undefined || readOnly) return;\n submit(\n connection.attach({\n connectionId: input.connectionId,\n domain,\n ...(input.zone === undefined ? {} : { zone: input.zone }),\n }),\n null,\n );\n },\n [connection, domain, readOnly, submit],\n );\n\n const select = useCallback(\n (zone: string) => {\n if (state._tag !== \"SelectionRequired\") return;\n reuse({ connectionId: state.connectionId, zone });\n },\n [reuse, state],\n );\n\n const release = useCallback(\n (effect: Effect.Effect<void, DomainKit.Error>, event: Event) => {\n if (held.current.domain !== domain) return;\n attempted.current = null;\n const command = () => {\n setState(\n State.Submitting({\n discovery: held.current.discovery,\n snapshot: held.current.snapshot,\n }),\n );\n runner.run(effect, {\n onFailure,\n onSuccess: () => {\n emit(event);\n load();\n },\n });\n };\n lastCommand.current = { domain, run: command };\n command();\n },\n [domain, emit, load, onFailure, runner],\n );\n\n const detach = useCallback(() => {\n const attachmentId = held.current.snapshot?.attachment?.id;\n if (readOnly || connection === undefined || attachmentId == null) return;\n if (held.current.domain !== domain) return;\n release(connection.detach(attachmentId), Event.Detached({ domain }));\n }, [connection, domain, readOnly, release]);\n\n const disconnect = useCallback(() => {\n const connectionId = held.current.snapshot?.connectionId;\n if (readOnly || connection === undefined || connectionId == null) return;\n if (held.current.domain !== domain) return;\n release(connection.disconnect(connectionId), Event.Disconnected({ connectionId, domain }));\n }, [connection, domain, readOnly, release]);\n\n const retry = useCallback(() => {\n const command = lastCommand.current;\n // Re-inspecting is a read, so it stays; rerunning the last write does not.\n if (readOnly || command === null || command.domain !== domain) load();\n else command.run();\n }, [domain, load, readOnly]);\n\n // One connection of this owner already serves the zone, so the customer has nothing left to\n // decide: the account they granted covers this domain too. Attaching here is what keeps a second\n // domain from meeting the connect dialog again. Each (domain, connection, zone) is tried once,\n // so an attach that failed, or one the customer undid with a detach, is not started over.\n const sighted = useRef<string | null>(null);\n useEffect(() => {\n if (readOnly || state._tag !== \"Disconnected\") return;\n const discovery = state.discovery;\n if (discovery === null || discovery._tag !== \"Resolved\") return;\n const sight = `${domain}|${discovery.connectionId}|${discovery.zone}`;\n if (sighted.current === sight) return;\n sighted.current = sight;\n reuse({ connectionId: discovery.connectionId, zone: discovery.zone });\n }, [domain, readOnly, reuse, state]);\n\n // The card names how many records this domain holds, which only the receipt knows. One read per\n // receipt id: the id changes when an apply lands, and nothing else moves it.\n const [receipt, setReceipt] = useState<Receipt.Model | null>(null);\n const receiptId = snapshotOf(state)?.lastReceiptId ?? null;\n const readReceipt = useRef<string | null>(null);\n useEffect(() => {\n if (receiptId === null) {\n readReceipt.current = null;\n setReceipt(null);\n return;\n }\n if (provisioning === undefined || readReceipt.current === receiptId) return;\n readReceipt.current = receiptId;\n runner.run(provisioning.receipt(Receipt.ReceiptId.make(receiptId)), {\n // A receipt the surface cannot read is one line of copy missing, not a failure the\n // customer has to answer, so the card renders without it.\n onFailure: () => setReceipt(null),\n onSuccess: (value) => setReceipt(value.id === receiptId ? value : null),\n });\n }, [provisioning, receiptId, runner]);\n\n return {\n connect,\n detach,\n disconnect,\n domain,\n established,\n discovery:\n state._tag === \"Disconnected\" || state._tag === \"Failure\" || state._tag === \"Submitting\"\n ? state.discovery\n : null,\n providers: snapshotOf(state)?.providers ?? [],\n receipt: receipt?.id === receiptId ? receipt : null,\n refresh: load,\n retry,\n reuse,\n select,\n snapshot: snapshotOf(state),\n state,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// Reading a connection\n// ---------------------------------------------------------------------------------------------\n\n/**\n * Whether a failure is already answered where it was raised: beside the method the customer used.\n * A surface rendering one outcome for the whole flow skips it, so the failure announces once.\n */\nexport const answeredInPlace = (controller: Controller): boolean =>\n controller.state._tag === \"Failure\" && controller.state.attempt !== null;\n\n/**\n * Whether the surface should read as connected: it is, or a command it started is in flight over a\n * connection that was. The provider row and the dialog it opened stay on screen for the length of\n * the command rather than vanishing under the customer half way through it.\n */\nexport const holdsConnection = (controller: Controller): boolean =>\n controller.state._tag === \"Connected\" ||\n (controller.state._tag === \"Submitting\" && controller.snapshot?.status === \"connected\");\n\n/**\n * Whether the provider turned the credential down, so the customer must prove the account again.\n * Proving it re-credits the connection the workspace already holds and leaves its domains where\n * they are, which is why the surface offers a reconnect rather than a second account.\n */\nexport const reconnect = (controller: Controller): boolean =>\n controller.state._tag === \"Reconnect\" ||\n (controller.state._tag === \"Submitting\" && controller.snapshot?.status === \"reconnect\");\n\n/**\n * The provider whose nameservers serve this domain, as the snapshot describes it. Discovery names\n * it by id; without a descriptor there is nothing to draw, so there is no host.\n */\nexport const hostProvider = (controller: Controller): Descriptor | null => {\n const discovery = controller.discovery;\n if (discovery === null || discovery._tag !== \"NotFound\" || discovery.host === null) return null;\n const named = discovery.host.provider;\n return controller.providers.find((entry) => entry.id === named) ?? null;\n};\n\n/** The descriptor for one provider id, or `null` when the snapshot describes no such provider. */\nexport const providerOf = (\n controller: Controller,\n providerId: string | null | undefined,\n): Descriptor | null =>\n providerId == null\n ? null\n : (controller.providers.find((entry) => entry.id === providerId) ?? null);\n\n/** The provider as the customer knows it, falling back to the id when the snapshot has no name. */\nexport const displayName = (controller: Controller, providerId: string): string =>\n providerOf(controller, providerId)?.name ?? providerId;\n\n/**\n * Whether the flow offers a connect surface: only when discovery names a host, always, or never.\n * `never` is a host that decides for itself, such as a domain already ready without DomainKit; a\n * connected domain keeps its status and its disconnect either way.\n */\nexport type Invitation = \"always\" | \"detected\" | \"never\";\n\n/**\n * Whether the connect surface has anything to offer for this domain: a provider that serves the\n * zone, a connection discovery already found, one the owner already holds, or a command already\n * running. Never while a connection is held, which is what `holdsConnection` answers. A host reads\n * it to order its own offers beside DomainKit's rather than competing with them.\n */\nexport const offering = (controller: Controller, connect: Invitation = \"detected\"): boolean => {\n // A surface that holds a connection is not offering one: the connected row is what renders, and\n // a host reading both must never see them claim different things about the same domain.\n if (holdsConnection(controller)) return false;\n const state = controller.state;\n // A command in flight owns the surface whatever discovery found: it is how the customer answers\n // a zone choice, a reconnect, or a redirect that came back.\n if (\n state._tag === \"Submitting\" ||\n state._tag === \"Redirecting\" ||\n state._tag === \"SelectionRequired\" ||\n state._tag === \"Reconnect\"\n ) {\n return true;\n }\n if (connect !== \"detected\") return connect === \"always\";\n const discovery = controller.discovery;\n return (\n hostProvider(controller) !== null ||\n (discovery !== null && discovery._tag !== \"NotFound\") ||\n (controller.snapshot?.reusable.length ?? 0) > 0\n );\n};\n\n/** A connection this owner already holds that would serve the domain, as one list to offer. */\nexport interface Reusable {\n readonly connectionId: string;\n /** The zone the connection would attach, when discovery named one. */\n readonly zone: string | undefined;\n readonly label: string;\n}\n\n/**\n * Every connection the customer can attach without proving anything: the one discovery resolved,\n * the candidates a zone choice is between, and the connections the snapshot lists as reusable.\n */\nexport const reusableConnections = (controller: Controller): ReadonlyArray<Reusable> => {\n const state = controller.state;\n const discovery = controller.discovery;\n const candidates =\n state._tag === \"SelectionRequired\"\n ? state.candidates.map((candidate) => ({ ...candidate, connectionId: state.connectionId }))\n : discovery !== null && discovery._tag === \"SelectionRequired\"\n ? discovery.candidates\n : [];\n const resolved = discovery !== null && discovery._tag === \"Resolved\" ? [discovery] : [];\n return [\n ...resolved.map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.label,\n zone: entry.zone,\n })),\n ...candidates.map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.label,\n zone: entry.zone,\n })),\n ...(controller.snapshot?.reusable ?? []).map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.provider,\n zone: undefined,\n })),\n ];\n};\n\n// ---------------------------------------------------------------------------------------------\n// Reading a provider's methods\n// ---------------------------------------------------------------------------------------------\n\n/** The fields one token method declares, split into what the surface asks for and what it hides. */\nexport interface MethodFields {\n readonly required: ReadonlyArray<Field>;\n /** The fields a provider does not need, which the surface keeps behind a disclosure. */\n readonly optional: ReadonlyArray<Field>;\n /** The field the provider's documentation link explains: the first secret, else the first field. */\n readonly explains: string | null;\n}\n\n/** One declared auth method, with the fields it asks for already arranged. */\nexport interface DescribedMethod {\n readonly kind: Storage.AuthMethod;\n readonly descriptor: MethodDescriptor;\n /** `null` for a method the customer clicks through, which asks for nothing on the page. */\n readonly fields: MethodFields | null;\n}\n\n/** What one provider offers, in the order the descriptor declares it. */\nexport interface DescribedMethods {\n /** The methods the customer clicks through: OAuth and the provider's own integration. */\n readonly interactive: ReadonlyArray<DescribedMethod>;\n /** The methods that ask for credentials on the page. */\n readonly typed: ReadonlyArray<DescribedMethod>;\n /**\n * Both kinds are on offer, so the surface shows the interactive one and a control that opens the\n * token form in its place: one decision at a time rather than a wall of alternatives.\n */\n readonly alternate: boolean;\n}\n\nconst fieldsOf = (method: MethodDescriptor): MethodFields | null => {\n const fields = method.fields;\n if (fields === null) return null;\n const required = fields.filter((field) => field.required);\n const optional = fields.filter((field) => !field.required);\n return {\n explains: (required.find((field) => field.secret) ?? required[0] ?? optional[0])?.name ?? null,\n optional,\n required,\n };\n};\n\n/** One provider's auth methods, arranged for a surface that asks for one decision at a time. */\nexport const describeMethods = (provider: Descriptor): DescribedMethods => {\n const described = provider.methods.map<DescribedMethod>((method) => ({\n descriptor: method,\n fields: fieldsOf(method),\n kind: method.kind,\n }));\n const interactive = described.filter((method) => method.fields === null);\n const typed = described.filter((method) => method.fields !== null);\n return { alternate: interactive.length > 0 && typed.length > 0, interactive, typed };\n};\n\n/**\n * The one field a rejected command was about, if any. A provider that turns down credentials is\n * answering the secret it was given, and it names no field, so the first secret carries the\n * answer; anything else is about the request rather than one input.\n */\nexport const rejectedField = (\n error: DomainKit.Error | null,\n fields: ReadonlyArray<Field>,\n): string | null => {\n if (error === null) return null;\n const reason = error.reason;\n if (reason._tag === \"InvalidInput\") {\n return fields.find((field) => field.name === reason.field)?.name ?? null;\n }\n if (reason._tag !== \"Unauthenticated\" && reason._tag !== \"Forbidden\") return null;\n return fields.find((field) => field.secret)?.name ?? null;\n};\n\n/** Whether a failure was raised by this provider's method, so the form answers beside it. */\nexport const attempted = (\n controller: Controller,\n provider: string,\n method: Storage.AuthMethod,\n): DomainKit.Error | null => {\n const state = controller.state;\n if (state._tag !== \"Failure\" || state.attempt === null) return null;\n return state.attempt.provider === provider && state.attempt.method === method\n ? state.error\n : null;\n};\n","/**\n * What a domain's requirements are, as data: the zone file they spell, the clipboard control a\n * value needs, and the standing one row reports. The table itself is the host's.\n */\nimport { DnsRecord, Verify, type Plan } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type Readiness = Transport.Readiness;\nexport type RequirementStatus = Readiness[\"requirements\"][number][\"status\"];\n\n// ---------------------------------------------------------------------------------------------\n// Zone file\n// ---------------------------------------------------------------------------------------------\n\nconst absolute = (value: string): string => (value.endsWith(\".\") ? value : `${value}.`);\n\nconst textEncoder = new TextEncoder();\n\nconst escapeTxtCharacter = (character: string): string => {\n if (character === '\"' || character === \"\\\\\") return `\\\\${character}`;\n const codePoint = character.codePointAt(0);\n if (codePoint !== undefined && (codePoint < 32 || codePoint === 127)) {\n return `\\\\${codePoint.toString().padStart(3, \"0\")}`;\n }\n return character;\n};\n\n/** TXT strings are capped at 255 bytes each, so long values are split and quoted per chunk. */\nconst txtValue = (value: string): string => {\n const chunks: Array<string> = [];\n let chunk = \"\";\n let byteLength = 0;\n for (const character of value) {\n const characterByteLength = textEncoder.encode(character).byteLength;\n if (byteLength + characterByteLength > 255) {\n chunks.push(chunk);\n chunk = \"\";\n byteLength = 0;\n }\n chunk += escapeTxtCharacter(character);\n byteLength += characterByteLength;\n }\n chunks.push(chunk);\n return chunks.map((part) => `\"${part}\"`).join(\" \");\n};\n\n/** The RR type as a zone file spells it. The tag and the type name are the same string. */\nconst rrType = (record: DnsRecord.Model): string => record._tag;\n\nconst zoneData = (record: DnsRecord.Model): string => {\n switch (record._tag) {\n case \"A\":\n case \"AAAA\":\n return record.address;\n case \"CNAME\":\n return absolute(record.target);\n case \"NS\":\n return absolute(record.nameserver);\n case \"TXT\":\n return txtValue(record.value);\n case \"MX\":\n return `${record.priority} ${absolute(record.exchange)}`;\n case \"CAA\":\n return `${record.flags} ${record.tag} \"${record.value}\"`;\n case \"SRV\":\n return `${record.priority} ${record.weight} ${record.port} ${absolute(record.target)}`;\n }\n};\n\nexport const toZoneFile = (records: ReadonlyArray<DnsRecord.Model>): string =>\n `${records\n .map(\n (record) =>\n `${absolute(record.name)}${record.ttl === null ? \"\" : ` ${record.ttl}`} IN ${rrType(record)} ${zoneData(record)}`,\n )\n .join(\"\\n\")}\\n`;\n\nconst downloadText = (filename: string, contents: string): void => {\n if (typeof document === \"undefined\") return;\n const blob = new Blob([contents], { type: \"text/plain;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.download = filename;\n anchor.href = url;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n};\n\nexport const downloadZoneFile = (domain: string, records: ReadonlyArray<DnsRecord.Model>): void =>\n downloadText(`${domain}.txt`, toZoneFile(records));\n\n// ---------------------------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------------------------\n\nexport const copyText = (value: string): Promise<boolean> => {\n if (typeof navigator === \"undefined\" || navigator.clipboard === undefined) {\n return Promise.resolve(false);\n }\n return navigator.clipboard.writeText(value).then(\n () => true,\n () => false,\n );\n};\n\nexport interface CopyController {\n readonly copied: boolean;\n readonly copy: () => void;\n}\n\nexport function useCopy(value: string, resetAfter = 2000): CopyController {\n const [copied, setCopied] = useState(false);\n const reset = useRef<ReturnType<typeof setTimeout>>(undefined);\n useEffect(() => () => clearTimeout(reset.current), []);\n return {\n copied,\n copy: () => {\n void copyText(value).then((ok) => {\n if (!ok) return;\n setCopied(true);\n clearTimeout(reset.current);\n reset.current = setTimeout(() => setCopied(false), resetAfter);\n });\n },\n };\n}\n\n/**\n * What a row has to say about one record: the operation a plan still awaiting its apply holds for\n * it, and the requirement the last observation stored for it. They are two facts, not one — a\n * pending plan says what will be written, an observation says what is there — so a surface renders\n * whichever of them its column is about rather than being handed a winner.\n */\nexport interface Standing {\n /** The pending plan's operation for this record, or `null` when no plan covers it. */\n readonly planned: Plan.Operation | null;\n /** The stored requirement, evidence included, or `null` when no observation covers it. */\n readonly observed: Readiness[\"requirements\"][number] | null;\n}\n\nexport interface Sources {\n /** A plan still awaiting its apply. Pass `null` once one has landed; readiness answers then. */\n readonly plan?: Plan.Model | null | undefined;\n readonly readiness?: Readiness | null | undefined;\n}\n\n/** Both facts a row can carry about one record, each `null` when nothing covers it. */\nexport const standingOf = (record: DnsRecord.Model, sources: Sources): Standing => ({\n planned: sources.plan?.operations.find((entry) => DnsRecord.equals(entry.record, record)) ?? null,\n observed:\n sources.readiness?.requirements.find((requirement) =>\n DnsRecord.equals(requirement.record, record),\n ) ?? null,\n});\n\n/**\n * A stable React key for a requirement: type, name, and data identify a record. It is\n * `Verify.requirementKey` from the core package, which is the `key` every readiness requirement\n * carries, so a row and the observation about it are paired by the same string.\n */\nexport const identity = Verify.requirementKey;\n\n/**\n * A requirement set keyed by everything it carries, for memos that decide whether to re-send it.\n * `identity` is deliberately narrower: it answers \"is this the same record\" for a React key, while\n * a plan and an observation are built from `ttl`, `policy`, and `purpose` as well. `policy` in\n * particular decides whether a name may hold anything else, so readiness turns on it.\n */\nexport const requirementsKey = (records: ReadonlyArray<DnsRecord.Model>): string =>\n JSON.stringify(records);\n","import { DnsRecord, type Receipt } from \"domainkit\";\nimport { useCallback } from \"react\";\n\nimport { pendingPlan, planOf, State, useAttempt, type Controller } from \"./attempt.ts\";\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { requirementsKey } from \"./records.ts\";\n\nexport { pendingPlan, planOf, State };\nexport type { Controller };\n\nexport interface Options {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n readonly onApplied?: (receipt: Receipt.Model) => void;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\n/**\n * Plan, approve, apply; `approve` authorizes the digest and applies it in the same action.\n * Requirements identify themselves by content, so an inline array does not abandon the attempt.\n * Every field counts: a plan turns on `policy`, and `ttl` and `purpose` ride the wire with it.\n */\nconst keyOf = (domain: string, requirements: ReadonlyArray<DnsRecord.Model>): string =>\n [domain, requirementsKey(requirements)].join(\"|\");\n\nexport function useController({ domain, onApplied, readOnly, requirements }: Options): Controller {\n const { transport } = useDomainKit();\n const group = transport.provisioning;\n return useAttempt({\n domain,\n key: keyOf(domain, requirements),\n done: (receipt) => Event.Applied({ domain, receipt }),\n group,\n onDone: onApplied,\n readOnly,\n plan: useCallback(\n () => (group === undefined ? null : group.plan({ domain, requirements })),\n [domain, group, requirements],\n ),\n });\n}\n","import { DnsRecord, DomainName, Verify, type DomainKit } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as DateTime from \"effect/DateTime\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { requirementsKey } from \"./records.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport type Readiness = Transport.Readiness;\nexport type HostEvidence = Readiness[\"host\"][number];\nexport type Requirement = Readiness[\"requirements\"][number];\nexport type Evidence = Requirement[\"evidence\"][number];\n\n/** Counts across a readiness's requirements, from the core package. Pure, and total over `null`. */\nexport const summary = Verify.summary;\nexport type Summary = Verify.Summary;\n\n/**\n * What the observer read back for the requirement's name, or `null` when it read nothing back at\n * all. Host evidence reports a status the host reached rather than values read off a name, and an\n * `unknown` observation is a lookup that never answered, which is not the same as finding nothing.\n */\nexport const valuesOf = (evidence: Evidence): ReadonlyArray<string> | null =>\n evidence._tag === \"Host\" || evidence.status === \"unknown\" ? null : evidence.values;\n\n/**\n * Readiness rides on the state rather than a ref, so it can never outlive the render that\n * produced it: a controller pointed at a new domain has no readiness in the very first frame.\n */\nexport type State = Data.TaggedEnum<{\n Idle: {};\n Observing: { readonly readiness: Readiness | null };\n Observed: { readonly readiness: Readiness };\n Failure: { readonly error: DomainKit.Error; readonly readiness: Readiness | null };\n}>;\nexport const State = Data.taggedEnum<State>();\n\nconst readinessOf = (state: State): Readiness | null =>\n state._tag === \"Idle\" ? null : state.readiness;\n\nexport interface Controller {\n readonly state: State;\n /** The latest readiness, kept while a new observation runs. */\n readonly readiness: Readiness | null;\n readonly observe: () => void;\n /** Observe again after a failure. */\n readonly retry: () => void;\n /** Whether this controller re-observes at `nextCheckAt` while mounted. */\n readonly polling: boolean;\n}\n\n/**\n * Readiness the host already holds, and how to ask it for a fresh one. A host that observes on its\n * own clock — a cron, a durable job, a server render — supplies the stored fact rather than letting\n * every mounted surface make an observation of its own.\n */\nexport interface Supplied {\n /** Readiness for this controller's domain; one read for another domain is discarded. */\n readonly readiness: Readiness | null;\n /** What `observe` and `retry` call. Absent means the surface cannot ask, and both do nothing. */\n readonly observe?: (() => void) | undefined;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * What to look for. Supplied requirements win over the attachment's latest provisioning receipt,\n * which is what lets a domain with no attachment be verified at all.\n */\n readonly requirements?: ReadonlyArray<DnsRecord.Model>;\n /** Re-observe at each `nextCheckAt` while mounted. Default true. */\n readonly polling?: boolean;\n /**\n * Take readiness from the host instead of observing. The controller then makes no observation on\n * mount, sets no timer, and reports `polling: false`; `observe` and `retry` call the host's.\n */\n readonly supplied?: Supplied | undefined;\n}\n\n/**\n * One name, however the host spelled it. Readiness is stored under `DomainName`'s normalised form,\n * so the comparison runs through the same boundary rather than a second spelling rule of its own.\n * A value that boundary rejects is compared as written, which is the strictest thing left to do.\n */\nconst sameDomain = (one: string, other: string): boolean => {\n const left = DomainName.fromString(one);\n const right = DomainName.fromString(other);\n return Option.isSome(left) && Option.isSome(right) ? left.value === right.value : one === other;\n};\n\n/**\n * Observe once on mount, then follow the readiness's own `nextCheckAt` while polling is on — or,\n * given `supplied`, report the host's readiness and leave the clock to it.\n */\nexport function useController({\n domain,\n polling = true,\n requirements,\n supplied,\n}: Options): Controller {\n const { emit, revision, transport } = useDomainKit();\n const verification = transport.verification;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Idle());\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n // Requirements identify themselves by content, so a host writing the array inline does not\n // rebuild `observe` on every render and set the mount effect observing in a loop. The key covers\n // every field, because `policy` and `ttl` ride the wire and `policy` decides readiness.\n const signature = requirements === undefined ? null : requirementsKey(requirements);\n const requested = useMemo(\n () => (requirements === undefined ? undefined : { requirements }),\n [signature],\n );\n\n // Readiness belongs to the domain that was observed. Dropping it while rendering, rather than\n // in an effect, keeps the first frame for a new domain free of the previous one's evidence.\n // The domain travels with it, so an answer that arrives after the controller moved refuses\n // itself rather than hanging one domain's evidence under another's name.\n const held = useRef(domain);\n const [observed, setObserved] = useState(domain);\n if (observed !== domain) {\n setObserved(domain);\n held.current = domain;\n setState(State.Idle());\n }\n\n // The option's identity is the host's to churn, so the callbacks depend on the two facts in it\n // rather than on the object: whether the host owns the clock, and what it wants called.\n const hostOwned = supplied !== undefined;\n const hostObserve = supplied?.observe;\n // Readiness belongs to the domain it was read for, exactly as an observed one does. A host that\n // re-renders with a new domain before its own read lands would otherwise hang the previous\n // domain's evidence under the new name, and `Domain.useFlow` would plan from its drift.\n const offered = supplied?.readiness ?? null;\n const hostReadiness = offered !== null && sameDomain(offered.domain, domain) ? offered : null;\n\n const observe = useCallback(() => {\n // The host owns the clock, so asking for a new reading is asking the host for one.\n if (hostOwned) {\n hostObserve?.();\n return;\n }\n if (verification === undefined) return;\n clearTimeout(timer.current);\n setState((previous) => State.Observing({ readiness: readinessOf(previous) }));\n runner.run(\n requested === undefined\n ? verification.observe(domain)\n : verification.observe(domain, requested),\n {\n onFailure: (error) => {\n if (held.current !== domain) return;\n setState((previous) => State.Failure({ error, readiness: readinessOf(previous) }));\n emit(Event.Failed({ domain, error }));\n },\n onSuccess: (readiness) => {\n if (held.current !== domain) return;\n setState(State.Observed({ readiness }));\n },\n },\n );\n }, [domain, emit, hostObserve, hostOwned, requested, runner, verification]);\n\n useEffect(() => {\n if (hostOwned) return;\n observe();\n }, [hostOwned, observe, revision]);\n\n useEffect(() => {\n // A controller that observed for itself and is then handed a supplied readiness stops here:\n // its last observation's `nextCheckAt` is not a schedule the host asked for, and the cleanup\n // of the previous run clears the timer that observation already set.\n if (hostOwned || !polling || state._tag !== \"Observed\") return;\n const next = state.readiness.nextCheckAt;\n if (next === null) return;\n const delay = Math.max(0, DateTime.toEpochMillis(next) - Date.now());\n timer.current = setTimeout(observe, delay);\n return () => clearTimeout(timer.current);\n }, [hostOwned, observe, polling, state]);\n\n useEffect(() => () => clearTimeout(timer.current), []);\n\n // A supplied readiness is a fact, not a state machine: the host has either read one or not.\n // The internal state stays `Idle` under it, which is what keeps the timer effect asleep.\n const suppliedState = useMemo(\n () => (hostReadiness === null ? State.Idle() : State.Observed({ readiness: hostReadiness })),\n [hostReadiness],\n );\n\n return {\n observe,\n polling: !hostOwned && polling,\n readiness: hostOwned ? hostReadiness : readinessOf(state),\n retry: observe,\n state: hostOwned ? suppliedState : state,\n };\n}\n","/**\n * The whole lifecycle for one domain in one hook: connect, add the records, observe, clean up.\n * `useFlow` runs the four controllers together and plans as soon as the domain is attached with\n * nothing applied, and again when an observation reads an applied record back missing or wrong, so\n * the styled surface is only markup.\n */\nimport { Receipt, type DnsRecord, type Plan } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as DateTime from \"effect/DateTime\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport * as Cleanup from \"./cleanup.ts\";\nimport * as Connect from \"./connect.ts\";\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport * as Provision from \"./provision.ts\";\nimport { identity, requirementsKey } from \"./records.ts\";\nimport * as Verify from \"./verify.ts\";\n\n/**\n * What DomainKit has to say about this domain. A host reads `connected` and `offering` to order\n * its own offers beside DomainKit's: an offer of its own competes while `offering` is true, and a\n * domain DomainKit holds needs none.\n */\nexport interface FlowState {\n readonly connection: Connect.State[\"_tag\"];\n readonly provisioning: Provision.State[\"_tag\"];\n /**\n * DomainKit holds a connection for this domain, including while a command it started over that\n * connection is still running. `offering` is never true at the same time.\n */\n readonly connected: boolean;\n /** The connect surface has something to offer, so a host's own offer would compete with it. */\n readonly offering: boolean;\n /** Who holds the connection, or whose nameservers serve the zone. */\n readonly provider: string | null;\n /**\n * The account the records go to, as the provider labelled the zone when the domain was attached.\n * `null` until there is an attachment.\n */\n readonly label: string | null;\n /**\n * The apply receipt this domain's latest provisioning attempt produced, which is what cleanup\n * plans from. A host's own \"remove this domain\" surface offers cleanup only when there is one.\n */\n readonly receiptId: Receipt.ReceiptId | null;\n /** `receiptId !== null`: DomainKit applied records here and can prove which. */\n readonly applied: boolean;\n /**\n * The surface may read this domain but not write to it, so a host can say why rather than\n * leaving a customer in front of a page with nothing on it.\n */\n readonly readOnly: boolean;\n}\n\nexport interface FlowOptions {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n /**\n * Offer the connect surface even when discovery names no host, for a host application that lets\n * a customer connect a provider the domain's nameservers do not point at, or `never` for a\n * domain the host has already settled another way. Defaults to `detected`.\n */\n readonly connect?: Connect.Invitation;\n readonly onApplied?: (receipt: Receipt.Model) => void;\n readonly onCleaned?: (receipt: Receipt.Model) => void;\n /**\n * Where an interactive provider flow returns the customer. Defaults to the page they started\n * from; pass `null` to let the server's `defaultReturnTo` decide.\n */\n readonly returnTo?: string | null;\n /** Report this domain's state without the controls that change it. Defaults to the root's. */\n readonly readOnly?: boolean;\n /**\n * Take readiness from the host instead of observing. A host that observes on its own clock — a\n * cron, a durable job, a server render that already read `Verify.latest` — supplies the stored\n * fact, and the flow makes no observation on mount and sets no timer. `flow.verification.observe`\n * and `retry` call the host's `observe`, or do nothing when it supplies none. Drift replanning\n * runs off the supplied readiness exactly as it does off an observed one.\n */\n readonly verification?: Verify.Supplied;\n}\n\nexport interface Flow {\n readonly domain: string;\n /** What the host asked for, as the surface renders it row by row. */\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n readonly state: FlowState;\n readonly connection: Connect.Controller;\n readonly provisioning: Provision.Controller;\n /** Bound to the domain's latest apply receipt, which is the only thing cleanup may undo. */\n readonly cleanup: Cleanup.Controller;\n readonly verification: Verify.Controller;\n /** The plan the rows report, which is one still awaiting its apply. */\n readonly plan: Plan.Model | null;\n readonly readiness: Verify.Readiness | null;\n /** Which capability groups the transport declares, so a surface renders only what it can run. */\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n /** What the flow was told to offer when discovery names no host. */\n readonly invitation: Connect.Invitation;\n}\n\n/** Built from primitives alone, so the memo that reports it depends on exactly those. */\nconst flowState = (input: {\n readonly connected: boolean;\n readonly label: string | null;\n readonly offering: boolean;\n readonly planning: Provision.State[\"_tag\"];\n readonly provider: string | null;\n readonly readOnly: boolean;\n readonly receipt: string | null;\n readonly status: Connect.State[\"_tag\"];\n}): FlowState => ({\n applied: input.receipt !== null,\n connected: input.connected,\n connection: input.status,\n label: input.label,\n offering: input.offering,\n provider: input.provider,\n provisioning: input.planning,\n readOnly: input.readOnly,\n receiptId: input.receipt === null ? null : Receipt.ReceiptId.make(input.receipt),\n});\n\n/**\n * A removal this flow is carrying out, at whatever step it reached. A cleanup that failed halfway\n * has taken records away, and offering them back would contradict what the customer asked for, so\n * the intent stands until the plan is declined or the flow is mounted again.\n */\nconst removing = (cleanup: Cleanup.State): boolean =>\n cleanup._tag !== \"Idle\" && cleanup._tag !== \"Rejecting\" && cleanup._tag !== \"Rejected\";\n\n/**\n * Which records an applied domain lost, keyed by the records themselves rather than by when they\n * were read, so every observation that reports the same drift is one reason to plan. `null` when\n * there is nothing to add back:\n *\n * - the observation was stored before the apply, so it is evidence about a zone from before the\n * records were written rather than about records that went missing since. An observation that\n * read the zone before the apply and stored after it is interrupted instead: the apply starts a\n * new one, and the runner drops whatever it replaced;\n * - this flow is the one taking the records away;\n * - every requirement was found.\n */\nconst driftKey = (\n readiness: Verify.Readiness | null,\n receipt: Receipt.Model | null,\n cleanup: Cleanup.State,\n): string | null => {\n if (readiness === null || receipt === null) return null;\n if (DateTime.isLessThan(readiness.checkedAt, receipt.appliedAt)) return null;\n if (removing(cleanup)) return null;\n const drifted = readiness.requirements\n .filter(({ status }) => status === \"missing\" || status === \"mismatch\")\n .map(({ record, status }) => `${identity(record)} ${status}`)\n .sort();\n return drifted.length === 0 ? null : drifted.join(\"\\n\");\n};\n\nexport function useFlow({\n connect = \"detected\",\n domain,\n onApplied,\n onCleaned,\n readOnly,\n requirements,\n returnTo,\n verification: supplied,\n}: FlowOptions): Flow {\n const { capabilities } = useDomainKit();\n const inherited = useReadOnly();\n const surfaceReadOnly = readOnly ?? inherited;\n // The flow's own flag reaches its controllers, so a read-only domain among writable ones\n // refuses commands rather than only reporting that it should.\n const connection = Connect.useController({\n domain,\n readOnly: surfaceReadOnly,\n ...(returnTo === undefined ? {} : { returnTo }),\n });\n const refresh = connection.refresh;\n // The flow knows what it asked for, so a domain with no attachment can still be verified.\n const verification = Verify.useController({\n domain,\n requirements,\n ...(supplied === undefined ? {} : { supplied }),\n });\n const observe = verification.observe;\n const provisioning = Provision.useController({\n domain,\n readOnly: surfaceReadOnly,\n onApplied: useCallback(\n (receipt: Receipt.Model) => {\n refresh();\n // The zone holds records it did not a moment ago, so the flow reads it again rather than\n // waiting for the next poll. Observing also interrupts an observation that overlapped the\n // apply, whose evidence is about the zone as it was before the writes landed.\n observe();\n onApplied?.(receipt);\n },\n [observe, onApplied, refresh],\n ),\n requirements,\n });\n const receiptId = connection.snapshot?.lastReceiptId ?? null;\n const cleanup = Cleanup.useController({\n domain,\n readOnly: surfaceReadOnly,\n ...(onCleaned === undefined ? {} : { onCleaned }),\n ...(receiptId === null ? {} : { receiptId: Receipt.ReceiptId.make(receiptId) }),\n });\n\n // The plan is what the table is: an attached domain with nothing applied to it yet has records\n // that are still a proposal, and the rows say so. An applied domain plans again once an\n // observation reads a record back missing or wrong, so a customer whose records were deleted at\n // the provider is offered them again instead of a count of what once landed. The signature is\n // what makes that one call per reason to make it — the domain, the connection that landed, what\n // the host asked for, the receipt, and which records drifted — rather than one per render or one\n // per poll.\n const attached = connection.snapshot?.attachment != null;\n const drift = driftKey(verification.readiness, connection.receipt, cleanup.state);\n const signature =\n surfaceReadOnly ||\n !capabilities.includes(\"provisioning\") ||\n !attached ||\n (receiptId !== null && drift === null)\n ? null\n : [\n domain,\n connection.established,\n requirementsKey(requirements),\n receiptId ?? \"\",\n drift ?? \"\",\n ].join(\"|\");\n const planned = useRef<string | null>(null);\n const buildPlan = provisioning.plan;\n useEffect(() => {\n // A flow that cannot plan forgets what it planned, so pointing it back at a domain it once\n // planned for builds a plan again rather than leaving that domain with none.\n if (signature === null) {\n planned.current = null;\n return;\n }\n if (planned.current === signature) return;\n planned.current = signature;\n buildPlan();\n }, [buildPlan, signature]);\n\n // The same predicates the surface renders on, so the state a host reads and the surface a\n // customer sees never disagree, including while a disconnect is in flight.\n const connected = Connect.holdsConnection(connection);\n const offering = Connect.offering(connection, connect);\n const provider = connection.snapshot?.provider ?? Connect.hostProvider(connection)?.id ?? null;\n return {\n capabilities,\n cleanup,\n connection,\n domain,\n invitation: connect,\n plan: Provision.pendingPlan(provisioning.state),\n provisioning,\n readiness: verification.readiness,\n requirements,\n state: flowState({\n connected,\n label: connection.snapshot?.attachment?.label ?? null,\n offering,\n planning: provisioning.state._tag,\n provider,\n readOnly: surfaceReadOnly,\n receipt: receiptId,\n status: connection.state._tag,\n }),\n verification,\n };\n}\n","/**\n * What a flow says when a step ends badly: a heading the customer reads first, then what to do\n * about it. Both come from the catalog, chosen by the error's reason, so nothing renders a tag,\n * a status literal, or a reason name.\n *\n * const describe = Outcome.useDescribe();\n * const words = describe(error, { provider: \"Cloudflare\" });\n */\nimport type { DomainKit } from \"domainkit\";\n\nimport { useMessages } from \"./domain-kit.tsx\";\nimport type { Catalog, Outcome, OutcomeContext } from \"./messages.ts\";\nimport { outcome } from \"./messages.ts\";\n\nexport type { Outcome, OutcomeContext };\n\n/** The catalog's title and description for one failure. */\nexport const describe = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): Outcome => outcome(error, catalog, context);\n\n/**\n * `describe` bound to the catalog `DomainKit.Root` holds. The reason alone cannot name the\n * provider a customer typed a token for, so the surface supplies it in the context.\n */\nexport function useDescribe(): (error: DomainKit.Error, context?: OutcomeContext) => Outcome {\n const messages = useMessages();\n return (error, context = {}) => outcome(error, messages, context);\n}\n","/**\n * The fake transport `@domainkit/react` tests render against: an in-memory `domainkit/server`\n * with memory storage and a fake provider, recording every call.\n */\nimport { Testing } from \"domainkit/testing\";\n\nexport const transport = Testing.transport;\nexport type RecordedCall = Testing.RecordedCall;\nexport type RecordingTransport = Testing.RecordingTransport;\nexport type TransportOptions = Testing.TransportOptions;\n","import type { DomainKit } from \"domainkit\";\nimport * as Data from \"effect/Data\";\n\n/**\n * The failed member every controller state shares. It carries the `DomainKit.Error` itself, so a\n * host reads `error.reason`, `error.category`, and `error.isRetryable` instead of parsing text.\n */\nexport type Failure = Data.TaggedEnum<{\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const Failure = Data.taggedEnum<Failure>();\n\n/** A defect that escaped the transport, in the shape the rest of the UI already handles. */\nexport const isFailure = (state: { readonly _tag: string }): state is Failure =>\n state._tag === \"Failure\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["mergeMessages","State","useController","currentUrl","State","useController","useController","Connect.useController","Verify.useController","Provision.useController","Cleanup.useController","Connect.holdsConnection","offering","Connect.offering","Connect.hostProvider","Provision.pendingPlan"],"sources":["../src/messages.ts","../src/domain-kit.tsx","../src/events.ts","../src/task.ts","../src/attempt.ts","../src/cleanup.ts","../src/domain-field.ts","../src/connect.ts","../src/records.ts","../src/provision.ts","../src/verify.ts","../src/domain.ts","../src/outcome.ts","../src/testing.ts","../src/failure.ts"],"sourcesContent":["/**\n * Every string the package can put on screen. Nothing renders a `_tag`, a reason name, or a\n * status literal directly: each one arrives here first, so a host translates the whole surface by\n * passing `messages` to `DomainKit.Root`.\n */\nimport type { DnsRecord, DomainKit, Plan, Reason, Receipt, Storage } from \"domainkit\";\n\nexport interface Catalog {\n // Actions\n readonly connect: string;\n /** The token method's button, which carries the verb rather than the method's own label. */\n readonly methodToken: string;\n readonly methodOAuth: (provider: string) => string;\n readonly methodIntegration: (provider: string) => string;\n readonly disconnect: string;\n readonly detach: string;\n readonly cancel: string;\n readonly close: string;\n readonly retry: string;\n readonly approve: string;\n /** The provisioning dialog's primary action: what it adds, and how many. */\n readonly addRecords: (count: number) => string;\n readonly decline: string;\n /** Why the primary action is unavailable: every operation the plan holds is blocked. */\n readonly everyRecordConflicts: string;\n readonly reviewChanges: string;\n readonly cleanUp: string;\n readonly checkDns: string;\n readonly checkAgain: string;\n readonly moreActions: string;\n /** Reveals the fields a provider does not need, such as an account id. */\n readonly moreOptions: string;\n /** Reveals the providers the dialog narrowed away. */\n readonly useAnotherProvider: string;\n /** Opens the token form where a provider also offers a method the customer clicks through. */\n readonly useTokenInstead: string;\n /** Returns from one method's form to the provider's methods. */\n readonly back: string;\n /** The connected card's identity: who holds the connection and which account it reaches. */\n readonly connectedAccount: (provider: string, account: string) => string;\n /** How many records this domain's apply receipt proves DomainKit added. */\n readonly recordsAdded: (count: number) => string;\n readonly needsReconnect: string;\n /** The disconnect dialog's scope question, when the connection serves other domains too. */\n readonly disconnectScope: string;\n readonly disconnectThisDomain: string;\n readonly disconnectEveryDomain: (count: number) => string;\n readonly copy: string;\n readonly copied: string;\n readonly copyZone: string;\n readonly download: string;\n readonly useConnection: (label: string) => string;\n readonly chooseZone: string;\n /** The domain field's listbox, named for a customer reading it with assistive technology. */\n readonly zoneSuggestions: string;\n /** Which account a typed domain's records will go to. */\n readonly recordsGoTo: (provider: string, account: string) => string;\n /** A typed domain no connected account reaches; the customer adds the records by hand. */\n readonly notInConnectedAccount: string;\n /** A held connection whose credential the provider turned down. */\n readonly reconnectAccount: (account: string) => string;\n readonly getToken: string;\n\n // Progress\n readonly loading: string;\n readonly connecting: string;\n readonly redirecting: string;\n readonly detaching: string;\n readonly disconnecting: string;\n readonly planning: string;\n readonly approving: string;\n readonly applying: string;\n readonly rejecting: string;\n readonly planningCleanup: string;\n readonly cleaning: string;\n readonly observing: string;\n\n // Connection\n readonly connectTitle: (provider: string) => string;\n /** The dialog heading, and the trigger, when no provider is named yet. */\n readonly connectAnyTitle: string;\n /** What the disconnected prompt says about the provider whose nameservers serve the domain. */\n readonly hostDetected: (provider: string) => string;\n readonly connectDescription: (domain: string) => string;\n readonly connectedTo: (provider: string) => string;\n /** Shown where a connect control would be when the customer may not connect. */\n readonly notConnected: string;\n /**\n * What a customer who may read the domain but not write to it is told in place of the connect\n * control, so the surface explains the gap rather than leaving an empty row.\n */\n readonly administratorConnects: (provider: string) => string;\n readonly reconnectRequired: (provider: string) => string;\n readonly disconnectTitle: (provider: string) => string;\n /**\n * What disconnecting means, in the present. The default names DomainKit as what stops managing\n * the records; a host application overrides the key to name itself.\n */\n readonly disconnectConsent: (domain: string, provider: string) => string;\n /**\n * The option inside the disconnect dialog, over the records it would remove. Only this domain's\n * apply receipt proves what DomainKit created, so the words say which records go.\n */\n readonly disconnectWithCleanup: (count: number) => string;\n /** What the listed records do when that option is off. */\n readonly disconnectKeepsRecords: (provider: string) => string;\n readonly detachConsent: string;\n readonly detached: string;\n readonly reusableConnections: string;\n readonly authenticationAlternative: string;\n readonly discoveredConnection: (label: string) => string;\n readonly discoveryAmbiguous: string;\n readonly discoveryNotFound: (nameservers: ReadonlyArray<string>) => string;\n readonly noProviders: string;\n readonly fieldLabel: (name: string) => string;\n readonly optionalField: string;\n\n // Plan review\n readonly planTitle: string;\n readonly planConsent: string;\n readonly cleanupTitle: string;\n readonly cleanupConsent: string;\n readonly noChanges: string;\n readonly planExpires: (at: string) => string;\n readonly declinedBy: (actor: string) => string;\n readonly declineReason: (reason: string) => string;\n readonly operation: (operation: Plan.Operation) => string;\n readonly conflictReason: (reason: Plan.Conflict[\"reason\"]) => string;\n /** What to do about a conflict, in the row that reports it. */\n readonly conflictAdvice: (reason: Plan.Conflict[\"reason\"]) => string;\n /** What a pending plan holds for one row: a write, a record already there, or a blocker. */\n readonly planStatus: (operation: Plan.Operation) => string;\n readonly attemptStatus: (status: Storage.AttemptStatus) => string;\n\n // Records\n readonly recordsCaption: (domain: string) => string;\n readonly headingType: string;\n readonly headingName: string;\n readonly headingValue: string;\n readonly headingStatus: string;\n /** The column that says what a pending plan will do, rendered only while one is pending. */\n readonly headingPlan: string;\n readonly headingPurpose: string;\n readonly priority: (priority: number) => string;\n readonly ttl: (seconds: number) => string;\n readonly recordType: (record: DnsRecord.Observed) => string;\n\n // Receipts\n readonly applied: (receipt: Receipt.Model) => string;\n readonly cleaned: (receipt: Receipt.Model) => string;\n readonly partiallyAppliedTitle: string;\n readonly partiallyApplied: string;\n readonly partiallyCleanedTitle: string;\n readonly partiallyCleaned: string;\n readonly receiptOutcome: (outcome: Receipt.Outcome) => string;\n readonly skippedReason: (reason: Receipt.Skipped[\"reason\"]) => string;\n\n // Verification\n readonly requirementStatus: (status: Storage.RequirementStatus) => string;\n readonly overall: (overall: Storage.Overall) => string;\n readonly evidenceSource: (evidence: EvidenceLike) => string;\n readonly hostEvidenceStatus: (status: \"failed\" | \"ok\" | \"pending\") => string;\n /** What the requirement asks for, shown when an observation disagrees with it. */\n readonly expectedValue: (value: string) => string;\n /** What one observer actually read back for that name. */\n readonly observedValues: (values: ReadonlyArray<string>) => string;\n readonly observedNothing: string;\n readonly checkedAt: (at: string) => string;\n readonly nextCheckAt: (at: string) => string;\n readonly hostEvidence: string;\n readonly noEvidence: string;\n\n // Failures, rendered from the error's reason: a heading and the sentence under it\n readonly invalidInput: (reason: Reason.InvalidInput, context: OutcomeContext) => Outcome;\n readonly unauthenticated: (reason: Reason.Unauthenticated, context: OutcomeContext) => Outcome;\n readonly forbidden: (reason: Reason.Forbidden, context: OutcomeContext) => Outcome;\n readonly notFound: (reason: Reason.NotFound, context: OutcomeContext) => Outcome;\n readonly conflict: (reason: Reason.Conflict, context: OutcomeContext) => Outcome;\n readonly stale: (reason: Reason.Stale, context: OutcomeContext) => Outcome;\n readonly batchStale: (reason: Reason.BatchStale, context: OutcomeContext) => Outcome;\n readonly expired: (reason: Reason.Expired, context: OutcomeContext) => Outcome;\n readonly busy: (reason: Reason.Busy, context: OutcomeContext) => Outcome;\n readonly providerRejected: (reason: Reason.ProviderRejected, context: OutcomeContext) => Outcome;\n readonly providerUnavailable: (\n reason: Reason.ProviderUnavailable,\n context: OutcomeContext,\n ) => Outcome;\n readonly providerConflict: (reason: Reason.ProviderConflict, context: OutcomeContext) => Outcome;\n readonly unsupported: (reason: Reason.Unsupported, context: OutcomeContext) => Outcome;\n readonly reconnect: (reason: Reason.Reconnect, context: OutcomeContext) => Outcome;\n readonly storageFailed: (reason: Reason.StorageFailed, context: OutcomeContext) => Outcome;\n readonly cryptoFailed: (reason: Reason.CryptoFailed, context: OutcomeContext) => Outcome;\n readonly resolverFailed: (reason: Reason.ResolverFailed, context: OutcomeContext) => Outcome;\n}\n\n/** What an outcome says: a heading the customer reads first, then what to do about it. */\nexport interface Outcome {\n readonly title: string;\n /** What to do about it. Absent where the title has already said the whole of it. */\n readonly description?: string;\n}\n\n/**\n * What the flow was doing when it failed. The reason alone cannot name the provider a customer\n * typed a token for, so the part that renders the outcome supplies it.\n */\nexport interface OutcomeContext {\n /** The provider's display name, when the flow knows which one the customer acted on. */\n readonly provider?: string;\n readonly domain?: string;\n}\n\n/** The evidence shapes `Verify` produces, structurally, so the catalog needs no service import. */\nexport type EvidenceLike =\n | { readonly _tag: \"Host\"; readonly source: string; readonly label: string }\n | { readonly _tag: \"Provider\"; readonly provider: string }\n | { readonly _tag: \"PublicDns\"; readonly resolver: string };\n\nconst entity: Readonly<Record<Reason.NotFound[\"entity\"], string>> = {\n approval: \"approval\",\n attachment: \"domain attachment\",\n batch: \"domain setup\",\n authorization: \"provider authorization\",\n connection: \"provider connection\",\n continuation: \"sign-in attempt\",\n plan: \"plan\",\n provider: \"provider\",\n receipt: \"receipt\",\n record: \"DNS record\",\n zone: \"DNS zone\",\n};\n\nconst expiredEntity: Readonly<Record<Reason.Expired[\"entity\"], string>> = {\n approval: \"approval\",\n continuation: \"sign-in attempt\",\n credential: \"provider credential\",\n plan: \"plan\",\n};\n\nconst recordTypes: Readonly<Record<Exclude<DnsRecord.Observed[\"_tag\"], \"Opaque\">, string>> = {\n A: \"A\",\n AAAA: \"AAAA\",\n CAA: \"CAA\",\n CNAME: \"CNAME\",\n MX: \"MX\",\n NS: \"NS\",\n SRV: \"SRV\",\n TXT: \"TXT\",\n};\n\n/** The provider the customer acted on, or a neutral stand-in when the flow does not know it. */\nconst named = (provider: string | undefined): string => provider ?? \"The provider\";\n\n/** The domain the failure is about, or a neutral stand-in. */\nconst where = (domain: string | undefined): string => domain ?? \"this domain\";\n\n/** `accountId` reads as \"Account id\" until a host names the field itself. */\nconst humanize = (name: string): string => {\n const spaced = name\n .replaceAll(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replaceAll(/[_-]+/g, \" \")\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n};\n\nexport const english: Catalog = {\n connect: \"Connect\",\n methodToken: \"Connect with an API token\",\n methodOAuth: (provider) => `Continue with ${provider}`,\n methodIntegration: (provider) => `Install the ${provider} integration`,\n disconnect: \"Disconnect\",\n detach: \"Detach domain\",\n cancel: \"Cancel\",\n close: \"Close\",\n retry: \"Try again\",\n approve: \"Approve\",\n addRecords: (count) => (count === 1 ? \"Add 1 record\" : `Add ${count} records`),\n decline: \"Decline\",\n everyRecordConflicts: \"Resolve the records above at your provider, then check again.\",\n reviewChanges: \"Review changes\",\n cleanUp: \"Remove records\",\n checkDns: \"Check DNS\",\n checkAgain: \"Check again\",\n moreActions: \"More actions\",\n moreOptions: \"Add an account id\",\n useAnotherProvider: \"Use a different provider\",\n useTokenInstead: \"Use an API token instead\",\n back: \"Back\",\n connectedAccount: (provider, account) => `${provider} · ${account}`,\n recordsAdded: (count) => (count === 1 ? \"1 added\" : `${count} added`),\n needsReconnect: \"Needs reconnecting\",\n disconnectScope: \"This connection serves other domains.\",\n disconnectThisDomain: \"Only this domain\",\n disconnectEveryDomain: (count) => `All ${count} domains`,\n copy: \"Copy\",\n copied: \"Copied\",\n copyZone: \"Copy zone file\",\n download: \"Download\",\n useConnection: (label) => `Use ${label}`,\n chooseZone: \"Choose the zone that serves this domain\",\n zoneSuggestions: \"Zones your connected accounts serve\",\n recordsGoTo: (provider, account) => `Records go to ${provider} through ${account}.`,\n notInConnectedAccount: \"Not in a connected account.\",\n reconnectAccount: (account) => `Reconnect ${account}`,\n getToken: \"Where do I find this?\",\n\n loading: \"Loading…\",\n connecting: \"Connecting…\",\n redirecting: \"Opening the provider…\",\n detaching: \"Detaching…\",\n disconnecting: \"Disconnecting…\",\n planning: \"Preparing DNS changes…\",\n approving: \"Approving…\",\n applying: \"Adding records…\",\n rejecting: \"Declining…\",\n planningCleanup: \"Preparing cleanup…\",\n cleaning: \"Removing records…\",\n observing: \"Checking DNS…\",\n\n connectTitle: (provider) => `Connect ${provider}`,\n connectAnyTitle: \"Connect a DNS provider\",\n hostDetected: (provider) => `${provider} DNS detected`,\n connectDescription: (domain) => `Authorize DNS changes for ${domain}.`,\n connectedTo: (provider) => `${provider} connected`,\n notConnected: \"No DNS provider is connected.\",\n administratorConnects: (provider) => `An administrator can connect ${provider}`,\n reconnectRequired: (provider) => `${provider} needs to be reconnected`,\n disconnectTitle: (provider) => `Disconnect ${provider}?`,\n disconnectConsent: (domain, provider) =>\n `DomainKit stops managing DNS for ${domain} through ${provider}.`,\n disconnectWithCleanup: (count) =>\n count === 1\n ? \"Remove the 1 record DomainKit added\"\n : `Remove the ${count} records DomainKit added`,\n disconnectKeepsRecords: (provider) => `Records stay in ${provider}.`,\n detachConsent: \"This domain is detached from the provider. Existing DNS records are preserved.\",\n detached: \"Domain detached. DNS records were preserved.\",\n reusableConnections: \"Connections you already have\",\n authenticationAlternative: \"or\",\n discoveredConnection: (label) => `${label} already serves this domain`,\n discoveryAmbiguous: \"More than one connection can serve this domain. Pick one.\",\n discoveryNotFound: (nameservers) =>\n nameservers.length === 0\n ? \"No connected provider serves this domain yet.\"\n : `No connected provider serves this domain. Its nameservers are ${nameservers.join(\", \")}.`,\n noProviders: \"No DNS providers are available.\",\n fieldLabel: humanize,\n optionalField: \"optional\",\n\n planTitle: \"Review DNS changes\",\n planConsent: \"Review the exact DNS operations before approving this plan.\",\n cleanupTitle: \"Review the records to remove\",\n cleanupConsent: \"Only records the apply receipt proves DomainKit created will be deleted.\",\n noChanges: \"No changes needed\",\n planExpires: (at) => `This plan expires at ${at}.`,\n declinedBy: (actor) => `Declined by ${actor}. Build a new plan to continue.`,\n declineReason: (reason) => `Reason: ${reason}`,\n operation: (operation) => {\n switch (operation._tag) {\n case \"Create\":\n return \"Add\";\n case \"Noop\":\n return \"Already in place\";\n case \"Delete\":\n return \"Remove\";\n case \"Conflict\":\n return \"Blocked\";\n }\n },\n conflictReason: (reason) => {\n switch (reason) {\n case \"spf-conflict\":\n return \"This name has a different SPF record or more than one SPF record.\";\n case \"exclusive-name\":\n return \"Another record already owns this name.\";\n case \"cname-collision\":\n return \"A CNAME cannot share a name with other records.\";\n case \"value-mismatch\":\n return \"A record with this name holds a different value.\";\n case \"opaque\":\n return \"A record here uses a form DomainKit will not overwrite.\";\n case \"missing\":\n return \"The record this plan expected is gone.\";\n }\n },\n conflictAdvice: (reason) => {\n switch (reason) {\n case \"spf-conflict\":\n return \"Review the SPF records at your provider and keep one matching policy, then check again.\";\n case \"exclusive-name\":\n return \"Remove the record on that name at your provider, then check again.\";\n case \"cname-collision\":\n return \"Remove the other records on that name at your provider, then check again.\";\n case \"value-mismatch\":\n return \"Point that record at this value at your provider, or remove it and check again.\";\n case \"opaque\":\n return \"Remove that record at your provider, then check again.\";\n case \"missing\":\n return \"Check again to build a plan from what is there now.\";\n }\n },\n planStatus: (operation) => {\n switch (operation._tag) {\n case \"Create\":\n return \"Will add\";\n case \"Noop\":\n return \"Already set\";\n case \"Delete\":\n return \"Will remove\";\n case \"Conflict\":\n return \"Conflict\";\n }\n },\n attemptStatus: (status) => {\n switch (status) {\n case \"planned\":\n return \"Awaiting review\";\n case \"approved\":\n return \"Approved\";\n case \"applying\":\n return \"Applying\";\n case \"complete\":\n return \"Applied\";\n case \"partial\":\n return \"Partly applied\";\n case \"failed\":\n return \"Failed\";\n case \"expired\":\n return \"Expired\";\n case \"rejected\":\n return \"Declined\";\n }\n },\n\n recordsCaption: (domain) => `DNS records for ${domain}`,\n headingType: \"Type\",\n headingName: \"Name\",\n headingValue: \"Value\",\n headingStatus: \"Status\",\n headingPlan: \"Plan\",\n headingPurpose: \"Purpose\",\n priority: (priority) => `Priority ${priority}`,\n ttl: (seconds) => `TTL ${seconds}s`,\n recordType: (record) => (record._tag === \"Opaque\" ? record.type : recordTypes[record._tag]),\n\n applied: (receipt) =>\n receipt.status === \"complete\" ? \"DNS records added.\" : \"Some DNS records were not added.\",\n cleaned: (receipt) =>\n receipt.status === \"complete\" ? \"DNS records removed.\" : \"Some DNS records were not removed.\",\n partiallyAppliedTitle: \"Some DNS changes did not land\",\n partiallyApplied: \"Review what applied, then retry. Retrying is safe.\",\n partiallyCleanedTitle: \"Some DNS records are still there\",\n partiallyCleaned: \"Review what is left, then retry. Retrying is safe.\",\n receiptOutcome: (outcome) => {\n switch (outcome._tag) {\n case \"Applied\":\n return \"Done\";\n case \"Skipped\":\n return \"Skipped\";\n case \"Failed\":\n return outcome.message;\n }\n },\n skippedReason: (reason) => {\n switch (reason) {\n case \"noop\":\n return \"The record was already in place.\";\n case \"not-approved\":\n return \"The approval left this operation out.\";\n case \"not-attempted\":\n return \"An earlier operation failed before this one ran.\";\n }\n },\n\n requirementStatus: (status) => {\n switch (status) {\n case \"satisfied\":\n return \"Found\";\n case \"missing\":\n return \"Missing\";\n case \"mismatch\":\n return \"Different value\";\n case \"unknown\":\n return \"Not checked\";\n }\n },\n overall: (overall) => {\n switch (overall) {\n case \"ready\":\n return \"Ready\";\n case \"pending\":\n return \"Pending\";\n case \"failed\":\n return \"Failed\";\n }\n },\n evidenceSource: (evidence) => {\n switch (evidence._tag) {\n case \"Host\":\n return evidence.label;\n case \"Provider\":\n return `${evidence.provider} records`;\n case \"PublicDns\":\n return `Public DNS via ${evidence.resolver}`;\n }\n },\n hostEvidenceStatus: (status) => {\n switch (status) {\n case \"ok\":\n return \"Ready\";\n case \"pending\":\n return \"Pending\";\n case \"failed\":\n return \"Failed\";\n }\n },\n expectedValue: (value) => `Expected ${value}`,\n observedValues: (values) => `Found ${values.join(\", \")}`,\n observedNothing: \"Found nothing\",\n checkedAt: (at) => `Checked ${at}`,\n nextCheckAt: (at) => `Next check ${at}`,\n hostEvidence: \"Other checks\",\n noEvidence: \"Nothing has been checked yet.\",\n\n invalidInput: (reason) => ({\n description: reason.message,\n title:\n reason.field === undefined\n ? \"Check what you entered\"\n : `Check the ${humanize(reason.field).toLowerCase()}`,\n }),\n // The dialog's heading already names the provider, so the outcome answers about the credential\n // and nothing else. A longer title wraps in the column beside the retry, and a second line under\n // it repeats what the title said.\n unauthenticated: () => ({\n title: \"Token not accepted\",\n }),\n forbidden: (_reason, context) => ({\n description: `The connection needs permission to edit DNS for ${where(context.domain)}.`,\n title: \"This connection can't change DNS here\",\n }),\n notFound: (reason) => ({\n description: \"Reload the page and start this step again.\",\n title: `That ${entity[reason.entity]} no longer exists`,\n }),\n conflict: (reason) => ({\n description: \"Review what the zone already holds, then build a new plan.\",\n title:\n reason.operations.length === 1\n ? \"A record is in the way\"\n : `${reason.operations.length} records are in the way`,\n }),\n stale: () => ({\n description: \"Review the new plan before you apply it.\",\n title: \"The zone changed since you reviewed\",\n }),\n batchStale: () => ({\n description: \"Open it again to see where it stands.\",\n title: \"This setup changed since you reviewed it\",\n }),\n expired: (reason) => ({\n description: \"Start this step again.\",\n title: `That ${expiredEntity[reason.entity]} expired`,\n }),\n busy: () => ({\n description: \"Wait for it to finish, then try again.\",\n title: \"Another change is running\",\n }),\n providerRejected: (reason, context) => ({\n description: reason.message,\n title: `${named(context.provider ?? reason.provider)} refused the change`,\n }),\n providerUnavailable: (reason, context) => ({\n description: \"Nothing changed. Try again in a minute.\",\n title: `${named(context.provider ?? reason.provider)} isn't responding`,\n }),\n providerConflict: (reason, context) => ({\n description: \"Remove or rename that record at the provider, then try again.\",\n title: `${named(context.provider ?? reason.provider)} already holds a conflicting record`,\n }),\n unsupported: (reason, context) => ({\n description: \"Nothing changed. This step needs a provider that can do it.\",\n title: `${named(context.provider ?? reason.provider)} cannot ${reason.operation}`,\n }),\n reconnect: (reason, context) => ({\n description: \"The stored credential no longer works. Connect again to continue.\",\n title: `Reconnect ${named(context.provider ?? reason.provider)}`,\n }),\n storageFailed: () => ({\n description: \"Nothing changed. Try again.\",\n title: \"The change could not be saved\",\n }),\n cryptoFailed: () => ({\n description: \"Connect the provider again to replace it.\",\n title: \"A stored credential could not be read\",\n }),\n resolverFailed: (reason) => ({\n description: \"The lookup failed, which says nothing about your DNS. Try again in a moment.\",\n title: `DNS lookups through ${reason.resolver} failed`,\n }),\n};\n\nexport const merge = (overrides: Partial<Catalog> = {}): Catalog => ({ ...english, ...overrides });\n\n/** The title and description for a failure, chosen by the error's reason. */\nexport const outcome = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): Outcome => {\n const reason = error.reason;\n switch (reason._tag) {\n case \"InvalidInput\":\n return catalog.invalidInput(reason, context);\n case \"Unauthenticated\":\n return catalog.unauthenticated(reason, context);\n case \"Forbidden\":\n return catalog.forbidden(reason, context);\n case \"NotFound\":\n return catalog.notFound(reason, context);\n case \"Conflict\":\n return catalog.conflict(reason, context);\n case \"Stale\":\n return catalog.stale(reason, context);\n case \"BatchStale\":\n return catalog.batchStale(reason, context);\n case \"Expired\":\n return catalog.expired(reason, context);\n case \"Busy\":\n return catalog.busy(reason, context);\n case \"ProviderRejected\":\n return catalog.providerRejected(reason, context);\n case \"ProviderUnavailable\":\n return catalog.providerUnavailable(reason, context);\n case \"ProviderConflict\":\n return catalog.providerConflict(reason, context);\n case \"Unsupported\":\n return catalog.unsupported(reason, context);\n case \"Reconnect\":\n return catalog.reconnect(reason, context);\n case \"StorageFailed\":\n return catalog.storageFailed(reason, context);\n case \"CryptoFailed\":\n return catalog.cryptoFailed(reason, context);\n case \"ResolverFailed\":\n return catalog.resolverFailed(reason, context);\n }\n};\n\n/** The same failure as one sentence, for a host that renders text rather than a card. */\nexport const failure = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): string => {\n const { description, title } = outcome(error, catalog, context);\n return description === undefined ? `${title}.` : `${title}. ${description}`;\n};\n","import { Transport } from \"domainkit/client\";\nimport * as Effect from \"effect/Effect\";\nimport {\n createContext,\n useCallback,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport type { Listener } from \"./events.ts\";\nimport type { Catalog } from \"./messages.ts\";\nimport { merge as mergeMessages } from \"./messages.ts\";\n\nexport interface RootProps {\n readonly children: ReactNode;\n readonly messages?: Partial<Catalog>;\n /** Where an interactive provider flow sends the customer. Defaults to `window.location`. */\n readonly navigate?: (url: string) => void;\n readonly onEvent?: Listener;\n /**\n * Report the domain's state without the controls that change it, for a customer who may read\n * the domain but not write to it. Capability gating already hides a group the transport does\n * not declare; this covers authorization the transport cannot express, such as a member of an\n * organisation. Every flow carries it on `FlowState.readOnly`, so a surface can explain it.\n */\n readonly readOnly?: boolean;\n /** Bump to re-inspect every mounted domain after a change the UI did not make. */\n readonly revision?: number;\n /** The transport, by value. Rebuilding it inline on every render does not restart controllers. */\n readonly transport: Transport.Interface;\n}\n\ninterface ContextValue {\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n readonly emit: Listener;\n readonly messages: Catalog;\n readonly navigate: (url: string) => void;\n readonly readOnly: boolean;\n readonly revision: number;\n readonly transport: Transport.Interface;\n}\n\nconst Context = createContext<ContextValue | null>(null);\n\nconst navigateInBrowser = (url: string): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\"DomainKit provider authorization requires a browser or a `navigate` prop\");\n }\n window.location.assign(url);\n};\n\nexport interface StableTransport {\n readonly transport: Transport.Interface;\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n}\n\ntype Method = (...args: ReadonlyArray<never>) => Effect.Effect<unknown, unknown>;\n\n/**\n * A transport whose identity survives re-renders. Each method reads the newest transport when it\n * runs, so a host may write `<DomainKit.Root transport={Transport.fromFetch(\"/api/domainkit\")}>`\n * inline and controllers still see one transport for the whole mount. Swapping in a transport\n * that declares different capability groups rebuilds it, and every controller re-runs.\n */\nconst useStableTransport = (transport: Transport.Interface): StableTransport => {\n const latest = useRef(transport);\n useLayoutEffect(() => {\n latest.current = transport;\n });\n const signature = Transport.capabilities(transport).join(\",\");\n return useMemo(() => {\n const capabilities = Transport.capabilities(latest.current);\n const stable = Object.fromEntries(\n capabilities.map((capability) => {\n const group = latest.current[capability] as unknown as Record<string, Method>;\n return [\n capability,\n Object.fromEntries(\n Object.keys(group).map((name) => [\n name,\n (...args: ReadonlyArray<never>) =>\n Effect.suspend(() => {\n const live = latest.current[capability] as unknown as Record<string, Method>;\n const method = live[name];\n if (method === undefined) {\n throw new Error(`The transport no longer declares ${capability}.${name}`);\n }\n return method(...args);\n }),\n ]),\n ),\n ];\n }),\n ) as Transport.Interface;\n return { capabilities, transport: stable };\n }, [signature]);\n};\n\n/**\n * The transport, the catalog, and the two host callbacks every hook below reads. It renders no\n * element of its own: `@domainkit/react` supplies behaviour, state, copy, and accessibility, and\n * the host application supplies the markup.\n */\nexport function Root({\n children,\n messages,\n navigate = navigateInBrowser,\n onEvent,\n readOnly = false,\n revision = 0,\n transport,\n}: RootProps): ReactElement {\n const { capabilities, transport: stable } = useStableTransport(transport);\n const onEventRef = useRef(onEvent);\n useLayoutEffect(() => {\n onEventRef.current = onEvent;\n }, [onEvent]);\n const emit = useCallback<Listener>((event) => {\n try {\n onEventRef.current?.(event);\n } catch {\n // Host observers are best-effort and cannot change a completed operation's outcome.\n }\n }, []);\n const value: ContextValue = {\n capabilities,\n emit,\n messages: mergeMessages(messages),\n navigate,\n readOnly,\n revision,\n transport: stable,\n };\n return <Context.Provider value={value}>{children}</Context.Provider>;\n}\n\nexport function useDomainKit(): ContextValue {\n const value = useContext(Context);\n if (value === null) {\n throw new Error(\"DomainKit hooks must be called inside DomainKit.Root\");\n }\n return value;\n}\n\n/** The catalog `DomainKit.Root` holds, with the host's overrides already merged in. */\nexport function useMessages(): Catalog {\n return useDomainKit().messages;\n}\n\n/** The transport `DomainKit.Root` holds, with the identity it keeps for the whole mount. */\nexport function useTransport(): Transport.Interface {\n return useDomainKit().transport;\n}\n\nconst ReadOnlyContext = createContext<boolean | null>(null);\n\n/** Narrow one subtree to read-only without touching the rest of the page. */\nexport function ReadOnly({\n children,\n value,\n}: {\n readonly children: ReactNode;\n readonly value: boolean;\n}) {\n return <ReadOnlyContext.Provider value={value}>{children}</ReadOnlyContext.Provider>;\n}\n\n/** Whether this surface may offer controls that change the domain. */\nexport function useReadOnly(): boolean {\n const scoped = useContext(ReadOnlyContext);\n const root = useDomainKit().readOnly;\n return scoped ?? root;\n}\n\n/** Which capability groups the host's transport declares, for gating a surface of your own. */\nexport function useCapabilities(): ReadonlyArray<Transport.Capability> {\n return useDomainKit().capabilities;\n}\n","import type { DomainKit, Receipt } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\n\n/** What a customer finished doing, for host notifications, analytics, and audit trails. */\nexport type Event = Data.TaggedEnum<{\n Connected: {\n readonly domain: string;\n readonly connectionId: string;\n readonly snapshot: Transport.Snapshot;\n };\n Detached: { readonly domain: string };\n Disconnected: { readonly domain: string; readonly connectionId: string };\n Applied: { readonly domain: string; readonly receipt: Receipt.Model };\n Cleaned: { readonly domain: string; readonly receipt: Receipt.Model };\n Declined: { readonly domain: string; readonly attempt: Transport.Attempt };\n Failed: { readonly domain: string; readonly error: DomainKit.Error };\n}>;\nexport const Event = Data.taggedEnum<Event>();\n\nexport type Listener = (event: Event) => void;\n","/**\n * The one place the package leaves Effect. Every controller runs its transport calls through\n * `useRunner`, which interrupts the call in flight when a newer one starts or the component\n * unmounts, and drops results that arrive after either.\n */\nimport { DomainKit, Reason } from \"domainkit\";\nimport * as Effect from \"effect/Effect\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nexport interface Runner {\n /**\n * Run `effect`, replacing whatever this runner had in flight. `onSuccess` and `onFailure` fire\n * only while this call is still the newest and the component is mounted.\n */\n readonly run: <A>(\n effect: Effect.Effect<A, DomainKit.Error>,\n handlers: {\n readonly onSuccess: (value: A) => void;\n readonly onFailure: (error: DomainKit.Error) => void;\n },\n ) => void;\n /** Stop the call in flight without starting another. */\n readonly cancel: () => void;\n}\n\n/** A defect is not a lifecycle failure; report it in the shape the UI already renders. */\nconst defect = (cause: unknown): DomainKit.Error =>\n new DomainKit.Error({\n reason: new Reason.ProviderUnavailable({\n provider: \"domainkit\",\n message: `The transport failed: ${String(cause)}`,\n }),\n });\n\ninterface Live {\n readonly id: number;\n interrupt: (() => void) | null;\n}\n\nexport function useRunner(): Runner {\n const state = useRef<{ mounted: boolean; next: number; live: Live | null }>({\n live: null,\n mounted: true,\n next: 0,\n });\n useEffect(() => {\n const current = state.current;\n current.mounted = true;\n return () => {\n current.mounted = false;\n current.live?.interrupt?.();\n current.live = null;\n };\n }, []);\n return useMemo<Runner>(() => {\n const stop = () => {\n state.current.live?.interrupt?.();\n state.current.live = null;\n };\n return {\n cancel: stop,\n run: (effect, handlers) => {\n stop();\n const live: Live = { id: (state.current.next += 1), interrupt: null };\n state.current.live = live;\n const interrupt = Effect.runCallback(effect, {\n onExit: (exit) => {\n if (state.current.live?.id !== live.id || !state.current.mounted) return;\n state.current.live = null;\n if (Exit.isSuccess(exit)) {\n handlers.onSuccess(exit.value);\n return;\n }\n // Read both before the interrupt guard: it narrows `exit` to the success side.\n const cause = exit.cause;\n const error = Exit.findErrorOption(exit);\n if (Exit.hasInterrupts(exit)) return;\n handlers.onFailure(Option.isSome(error) ? error.value : defect(cause));\n },\n });\n // A synchronous effect already ran `onExit` and cleared `live`; only a call still in\n // flight needs an interrupt handle.\n if (state.current.live?.id === live.id) live.interrupt = () => interrupt();\n },\n };\n }, []);\n}\n","/**\n * The plan -> approve -> apply machine both `Provision` and `Cleanup` run. They differ only in\n * which plan they build and which event they emit when the receipt lands, so the machine lives\n * here once and each namespace exports its own controller over it.\n */\nimport type { Approval, DomainKit, Plan, Receipt } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport type State = Data.TaggedEnum<{\n Idle: {};\n Planning: {};\n Planned: { readonly plan: Plan.Model };\n Approving: { readonly plan: Plan.Model };\n Applying: { readonly plan: Plan.Model; readonly approval: Approval.Model };\n Applied: { readonly plan: Plan.Model | null; readonly receipt: Receipt.Model };\n Rejecting: { readonly plan: Plan.Model };\n Rejected: { readonly plan: Plan.Model; readonly attempt: Transport.Attempt };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const State = Data.taggedEnum<State>();\n\n/** The verbs `Provision` and `Cleanup` share on the wire. */\nexport interface Group {\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Effect.Effect<Approval.Model, DomainKit.Error>;\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Effect.Effect<Transport.Attempt, DomainKit.Error>;\n readonly apply: (\n approvalId: Approval.ApprovalId,\n ) => Effect.Effect<Receipt.Model, DomainKit.Error>;\n}\n\nexport interface Controller {\n readonly state: State;\n /** Build a plan. The plan itself rides on the state, from `Planned` through `Applied`. */\n readonly plan: () => void;\n /** Authorize the digest and apply it. Pass `operationIds` to approve part of the plan. */\n readonly approve: (operationIds?: ReadonlyArray<Plan.OperationId>) => void;\n /** Decline the plan. Terminal: approving it afterwards fails `Stale`. */\n readonly reject: (reason?: string) => void;\n /** Apply the approval this controller already holds. */\n readonly apply: () => void;\n /** Re-plan when the zone moved under the plan, otherwise re-run the step that failed. */\n readonly retry: () => void;\n readonly reset: () => void;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * Identifies the inputs this attempt is for. When it changes the attempt is abandoned, because a\n * plan, approval, and receipt only mean anything for the inputs that produced them.\n */\n readonly key: string;\n readonly group: Group | undefined;\n /** The plan call, or `null` when this flow has nothing to plan yet. */\n readonly plan: () => Effect.Effect<Plan.Model, DomainKit.Error> | null;\n readonly done: (receipt: Receipt.Model) => Event;\n readonly onDone: ((receipt: Receipt.Model) => void) | undefined;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly: boolean | undefined;\n}\n\n/** Reasons that mean the plan itself is gone: retrying the same step would fail the same way. */\nconst needsNewPlan = (error: DomainKit.Error): boolean =>\n error.reason._tag === \"Stale\" ||\n error.reason._tag === \"Expired\" ||\n error.reason._tag === \"Conflict\";\n\n/** The plan an attempt holds, whatever step it is on; `null` before there is one. */\nexport const planOf = (state: State): Plan.Model | null => {\n switch (state._tag) {\n case \"Planned\":\n case \"Approving\":\n case \"Applying\":\n case \"Rejecting\":\n case \"Rejected\":\n case \"Applied\":\n return state.plan;\n case \"Idle\":\n case \"Planning\":\n case \"Failure\":\n return null;\n }\n};\n\n/**\n * The plan still awaiting its apply, which is what a row of records reports; `null` once one has\n * landed, because from then on an observation answers instead.\n */\nexport const pendingPlan = (state: State): Plan.Model | null => {\n switch (state._tag) {\n case \"Planned\":\n case \"Approving\":\n case \"Applying\":\n return state.plan;\n case \"Idle\":\n case \"Planning\":\n case \"Applied\":\n case \"Rejecting\":\n case \"Rejected\":\n case \"Failure\":\n return null;\n }\n};\n\nexport function useAttempt(options: Options): Controller {\n const { domain, done, group, key, onDone } = options;\n const { emit } = useDomainKit();\n const inherited = useReadOnly();\n // Every step of an attempt is a write, planning included: a plan is an attempt the server\n // records. A read-only surface may render a button anyway, so the refusal lives here.\n const readOnly = options.readOnly ?? inherited;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Idle());\n // The key travels with what it produced, so a command raised before the reset commits still\n // refuses to run: a plan built for one domain must never be approved for another.\n const held = useRef<{\n key: string;\n plan: Plan.Model | null;\n approval: Approval.Model | null;\n }>({ approval: null, key, plan: null });\n const lastCommand = useRef<{ key: string; run: () => void } | null>(null);\n const build = useRef(options.plan);\n useEffect(() => {\n build.current = options.plan;\n });\n\n // Abandoning while rendering, not one effect later, is what makes the guards below sound: a\n // reply that lands in between finds the new key already recorded and drops itself.\n const [current, setCurrent] = useState(key);\n if (current !== key) {\n setCurrent(key);\n runner.cancel();\n held.current = { approval: null, key, plan: null };\n lastCommand.current = null;\n setState(State.Idle());\n }\n\n const onFailure = useCallback(\n (error: DomainKit.Error) => {\n setState(State.Failure({ error }));\n emit(Event.Failed({ domain, error }));\n },\n [domain, emit],\n );\n\n const applyWith = useCallback(\n (plan: Plan.Model, approval: Approval.Model) => {\n if (readOnly || group === undefined || held.current.key !== key) return;\n const command = () => {\n setState(State.Applying({ approval, plan }));\n runner.run(group.apply(approval.id), {\n onFailure,\n onSuccess: (receipt) => {\n setState(State.Applied({ plan, receipt }));\n emit(done(receipt));\n onDone?.(receipt);\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [done, emit, group, key, onDone, onFailure, readOnly, runner],\n );\n\n const buildPlan = useCallback(() => {\n if (readOnly) return;\n const effect = build.current();\n if (effect === null) return;\n const command = () => {\n setState(State.Planning());\n runner.run(effect, {\n onFailure,\n onSuccess: (plan) => {\n if (held.current.key !== key) return;\n held.current = { approval: null, key, plan };\n setState(State.Planned({ plan }));\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n }, [key, onFailure, readOnly, runner]);\n\n const approve = useCallback(\n (operationIds?: ReadonlyArray<Plan.OperationId>) => {\n const plan = held.current.plan;\n if (readOnly || group === undefined || plan === null || held.current.key !== key) return;\n const command = () => {\n setState(State.Approving({ plan }));\n runner.run(\n group.approve({\n planId: plan.id,\n ...(operationIds === undefined ? {} : { operationIds }),\n }),\n {\n onFailure,\n onSuccess: (approval) => {\n if (held.current.key !== key) return;\n held.current = { approval, key, plan };\n applyWith(plan, approval);\n },\n },\n );\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [applyWith, group, key, onFailure, readOnly, runner],\n );\n\n const reject = useCallback(\n (reason?: string) => {\n const plan = held.current.plan;\n if (readOnly || group === undefined || plan === null || held.current.key !== key) return;\n const command = () => {\n setState(State.Rejecting({ plan }));\n runner.run(group.reject({ planId: plan.id, ...(reason === undefined ? {} : { reason }) }), {\n onFailure,\n onSuccess: (attempt) => {\n setState(State.Rejected({ attempt, plan }));\n emit(Event.Declined({ attempt, domain }));\n },\n });\n };\n lastCommand.current = { key, run: command };\n command();\n },\n [domain, emit, group, key, onFailure, readOnly, runner],\n );\n\n const apply = useCallback(() => {\n const { approval, plan } = held.current;\n if (readOnly || approval === null || plan === null) return;\n applyWith(plan, approval);\n }, [applyWith]);\n\n const retry = useCallback(() => {\n // Every step of an attempt is a write, so read-only has nothing to retry.\n if (readOnly) return;\n if (state._tag === \"Failure\" && needsNewPlan(state.error)) {\n held.current = { approval: null, key, plan: null };\n buildPlan();\n return;\n }\n const command = lastCommand.current;\n if (command === null || command.key !== key) buildPlan();\n else command.run();\n }, [buildPlan, key, readOnly, state]);\n\n const reset = useCallback(() => {\n runner.cancel();\n held.current = { approval: null, key, plan: null };\n lastCommand.current = null;\n setState(State.Idle());\n }, [key, runner]);\n\n return { apply, approve, plan: buildPlan, reject, reset, retry, state };\n}\n","import { DomainKit, Reason, Receipt } from \"domainkit\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback } from \"react\";\n\nimport { pendingPlan, planOf, State, useAttempt, type Controller } from \"./attempt.ts\";\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\n\nexport { pendingPlan, planOf, State };\nexport type { Controller };\n\nexport interface Options {\n readonly domain: string;\n /** Which apply to undo. Without it, the domain's latest provisioning receipt. */\n readonly receiptId?: Receipt.ReceiptId;\n readonly onCleaned?: (receipt: Receipt.Model) => void;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\n/**\n * Cleanup is bound to a receipt: it removes only what an apply proved DomainKit created. When the\n * host does not name one, the controller reads the domain's latest from the snapshot.\n */\nexport function useController({ domain, onCleaned, readOnly, receiptId }: Options): Controller {\n const { transport } = useDomainKit();\n const group = transport.cleanup;\n const connection = transport.connection;\n return useAttempt({\n domain,\n key: [domain, receiptId ?? \"\"].join(\"|\"),\n done: (receipt) => Event.Cleaned({ domain, receipt }),\n group,\n onDone: onCleaned,\n readOnly,\n plan: useCallback(() => {\n if (group === undefined) return null;\n if (receiptId !== undefined) return group.plan(receiptId);\n if (connection === undefined) return null;\n return Effect.flatMap(connection.inspect(domain), (snapshot) =>\n snapshot.lastReceiptId === null\n ? Effect.fail(\n new DomainKit.Error({\n reason: new Reason.NotFound({ entity: \"receipt\", id: snapshot.domain }),\n }),\n )\n : group.plan(Receipt.ReceiptId.make(snapshot.lastReceiptId)),\n );\n }, [connection, domain, group, receiptId]),\n });\n}\n","/**\n * Adding a domain is one input. The zones every connected account reaches load when the field\n * mounts, typing filters them, Tab completes the highlighted one while keeping whatever subdomain\n * was typed in front of it, and the surface names the account the records will go to.\n *\n * The listbox is built here rather than on a combobox primitive because the completion rule is not\n * a selection model: a suggestion never replaces what the customer typed, it finishes it, and a\n * domain outside every zone leaves the input a plain text field.\n */\nimport type { DomainKit } from \"domainkit\";\nimport { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type AriaAttributes,\n type FocusEventHandler,\n type FormEventHandler,\n type KeyboardEventHandler,\n type MouseEventHandler,\n} from \"react\";\n\nimport type { Descriptor } from \"./connect.ts\";\nimport { useDomainKit, useMessages, useReadOnly } from \"./domain-kit.tsx\";\nimport { useRunner } from \"./task.ts\";\n\nexport type Zone = Transport.Zone;\nexport type Account = Transport.Zones[\"connections\"][number];\nexport type AuthMethod = Descriptor[\"methods\"][number];\n\n/** Where a domain's records would go: the connection that serves it, and in which zone. */\nexport interface Placement {\n readonly connectionId: string;\n readonly zone: string;\n}\n\n// ---------------------------------------------------------------------------------------------\n// useZones\n// ---------------------------------------------------------------------------------------------\n\nexport type ZonesState = Data.TaggedEnum<{\n Loading: {};\n Ready: {\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const ZonesState = Data.taggedEnum<ZonesState>();\n\nexport interface ZonesController {\n readonly state: ZonesState;\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n readonly refresh: () => void;\n}\n\nexport interface ZonesOptions {\n /** Only this provider's connections. Omit for every connection this owner holds. */\n readonly provider?: string;\n}\n\nconst nothing = {\n connections: [] as ReadonlyArray<Account>,\n providers: [] as ReadonlyArray<Descriptor>,\n zones: [] as ReadonlyArray<Zone>,\n};\n\n/**\n * Every zone this owner's connections reach. A connection whose credential the provider turned\n * down is listed in `connections` as `reconnect` and contributes no zones, so one dead account\n * never costs the customer the others.\n */\nexport function useZones({ provider }: ZonesOptions = {}): ZonesController {\n const { revision, transport } = useDomainKit();\n const connection = transport.connection;\n const runner = useRunner();\n const [state, setState] = useState<ZonesState>(ZonesState.Loading());\n\n const load = useCallback(() => {\n if (connection === undefined) return;\n setState(ZonesState.Loading());\n runner.run(connection.zones(provider === undefined ? {} : { provider }), {\n onFailure: (error) => setState(ZonesState.Failure({ error })),\n onSuccess: (listing) =>\n setState(\n ZonesState.Ready({\n connections: listing.connections,\n providers: listing.providers,\n zones: listing.zones,\n }),\n ),\n });\n }, [connection, provider, runner]);\n\n useEffect(load, [load, revision]);\n\n const held = state._tag === \"Ready\" ? state : nothing;\n return {\n connections: held.connections,\n providers: held.providers,\n refresh: load,\n state,\n zones: held.zones,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// useAccounts\n// ---------------------------------------------------------------------------------------------\n\nexport interface ConnectAccountInput {\n readonly provider: string;\n readonly method: AuthMethod[\"kind\"];\n /** Keyed by the descriptor's field names. Ignored by the interactive methods. */\n readonly values?: Readonly<Record<string, string>>;\n}\n\nexport type AccountsState = Data.TaggedEnum<{\n Loading: {};\n Ready: {};\n Submitting: { readonly provider: string };\n Redirecting: { readonly url: string };\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const AccountsState = Data.taggedEnum<AccountsState>();\n\nexport interface AccountsController {\n readonly state: AccountsState;\n readonly zones: ReadonlyArray<Zone>;\n readonly connections: ReadonlyArray<Account>;\n readonly providers: ReadonlyArray<Descriptor>;\n /** Connect a provider with no domain attached. The account is what the customer is granting. */\n readonly connect: (input: ConnectAccountInput) => void;\n /**\n * Prove an account again for a connection the owner already holds. The connection and its\n * domains stay; only the credential behind it is replaced.\n */\n readonly reconnect: (input: ConnectAccountInput & { readonly connectionId: string }) => void;\n readonly refresh: () => void;\n}\n\nexport interface AccountsOptions {\n /** Where an interactive method returns the customer. Defaults to the page they started from. */\n readonly returnTo?: string | null;\n /** Refuse the commands that grant an account. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\nconst currentUrl = (): string | null =>\n typeof window === \"undefined\" ? null : window.location.href;\n\n/**\n * The accounts this owner holds, and the one way to add another: connect a provider without naming\n * a domain. A token method finishes in place; an interactive one redirects and comes back through\n * the library's own callback, which lands on `returnTo`.\n */\nexport function useAccounts({\n readOnly: refused,\n returnTo,\n}: AccountsOptions = {}): AccountsController {\n const { navigate, transport } = useDomainKit();\n const inherited = useReadOnly();\n // Granting an account is a write like any other, so the refusal lives here rather than in the\n // markup a host wrote.\n const readOnly = refused ?? inherited;\n const connection = transport.connection;\n const runner = useRunner();\n const listing = useZones();\n const [command, setCommand] = useState<AccountsState | null>(null);\n\n const refresh = listing.refresh;\n const submit = useCallback(\n (input: ConnectAccountInput & { readonly connectionId?: string }) => {\n if (connection === undefined || readOnly) return;\n const destination = returnTo === undefined ? currentUrl() : returnTo;\n const interactive = destination === null ? {} : { returnTo: destination };\n const method =\n input.method === \"token\"\n ? Transport.Method.token(input.values ?? {})\n : input.method === \"oauth\"\n ? Transport.Method.oauth(interactive)\n : Transport.Method.integration(interactive);\n setCommand(AccountsState.Submitting({ provider: input.provider }));\n const granting =\n input.connectionId === undefined\n ? connection.start({ method, provider: input.provider })\n : connection.reconnect({ connectionId: input.connectionId, method });\n runner.run(granting, {\n onFailure: (error) => setCommand(AccountsState.Failure({ error })),\n onSuccess: (started) => {\n if (started._tag === \"Redirect\") {\n setCommand(AccountsState.Redirecting({ url: started.authorizationUrl }));\n navigate(started.authorizationUrl);\n return;\n }\n // A selection is about a domain and this flow names none, so the account is connected.\n setCommand(null);\n refresh();\n },\n });\n },\n [connection, navigate, readOnly, refresh, returnTo, runner],\n );\n const connect = useCallback((input: ConnectAccountInput) => submit(input), [submit]);\n const reconnect = useCallback(\n (input: ConnectAccountInput & { readonly connectionId: string }) => submit(input),\n [submit],\n );\n\n const state =\n command ??\n (listing.state._tag === \"Loading\"\n ? AccountsState.Loading()\n : listing.state._tag === \"Failure\"\n ? AccountsState.Failure({ error: listing.state.error })\n : AccountsState.Ready());\n\n return {\n connect,\n reconnect,\n connections: listing.connections,\n providers: listing.providers,\n refresh,\n state,\n zones: listing.zones,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// Matching\n// ---------------------------------------------------------------------------------------------\n\nconst normalize = (value: string): string => value.trim().toLowerCase().replace(/\\.$/, \"\");\n\n/**\n * The zone a value already sits in: the longest listed zone the value is at or under. Two accounts\n * can serve the same zone, so `preferred` names the one the customer picked and wins among equals;\n * without it the first listed account answers.\n */\nexport const placementOf = (\n value: string,\n zones: ReadonlyArray<Zone>,\n preferred?: Placement | null,\n): { readonly zone: Zone; readonly placement: Placement } | null => {\n const domain = normalize(value);\n if (domain === \"\") return null;\n const matching = zones.filter((candidate) => {\n const zone = normalize(candidate.zone);\n return domain === zone || domain.endsWith(`.${zone}`);\n });\n const longest = matching.reduce(\n (best, candidate) =>\n best === null || normalize(candidate.zone).length > normalize(best.zone).length\n ? candidate\n : best,\n null as Zone | null,\n );\n if (longest === null) return null;\n const closest = matching.filter(\n (candidate) => normalize(candidate.zone) === normalize(longest.zone),\n );\n const best =\n closest.find(\n (candidate) =>\n preferred != null &&\n candidate.connectionId === preferred.connectionId &&\n normalize(candidate.zone) === normalize(preferred.zone),\n ) ??\n closest[0] ??\n longest;\n return { placement: { connectionId: best.connectionId, zone: best.zone }, zone: best };\n};\n\n/**\n * What the customer typed in front of the zone they are reaching for. \"mail.ex\" against\n * `example.com` is the subdomain \"mail\"; \"ex\" on its own is none.\n */\nconst subdomainOf = (value: string, zone: string): string => {\n const typed = normalize(value);\n const target = normalize(zone);\n if (typed === \"\" || target.startsWith(typed)) return \"\";\n const cut = typed.lastIndexOf(\".\");\n if (cut < 0) return \"\";\n const head = typed.slice(0, cut);\n const tail = typed.slice(cut + 1);\n return target.startsWith(tail) ? head : \"\";\n};\n\n/** Zones the typed value is reaching for: a prefix of the zone, or a subdomain of one. */\nexport const suggestionsFor = (value: string, zones: ReadonlyArray<Zone>): ReadonlyArray<Zone> => {\n const typed = normalize(value);\n if (typed === \"\") return zones;\n return zones.filter((candidate) => {\n const zone = normalize(candidate.zone);\n if (zone.startsWith(typed)) return true;\n const cut = typed.lastIndexOf(\".\");\n if (cut < 0) return false;\n const tail = typed.slice(cut + 1);\n return tail !== \"\" && zone.startsWith(tail);\n });\n};\n\n/** The value a suggestion completes to: whatever subdomain was typed, then the zone. */\nexport const completionOf = (value: string, zone: Zone): string => {\n const subdomain = subdomainOf(value, zone.zone);\n return subdomain === \"\" ? zone.zone : `${subdomain}.${zone.zone}`;\n};\n\n// ---------------------------------------------------------------------------------------------\n// useDomainField\n// ---------------------------------------------------------------------------------------------\n\nconst optionId = (listId: string, zone: Zone): string =>\n `${listId}-${zone.connectionId}-${zone.zone}`;\n\nexport interface DomainFieldOptions {\n /** Every zone the surface offers, which `useZones` or `useAccounts` already holds. */\n readonly zones: ReadonlyArray<Zone>;\n readonly value: string;\n readonly onChange: (value: string) => void;\n /**\n * Fires when the value or the account it resolves to changes, so a host holds the two together\n * and submits them together. It reports the value as typed, not only the placement, because a\n * form needs the name the customer is on as well as where its records would go.\n */\n readonly onResolve?: (input: {\n readonly domain: string;\n readonly connection: Placement | null;\n }) => void;\n /** The input's id. The listbox and its options are named from it; one is generated otherwise. */\n readonly id?: string;\n}\n\n/** The props one suggestion carries, so the option is a listbox option to a screen reader. */\nexport interface OptionProps {\n readonly \"aria-selected\": boolean;\n readonly id: string;\n readonly onMouseDown: MouseEventHandler<Element>;\n readonly role: \"option\";\n}\n\nexport interface DomainFieldController {\n /** Whether the listbox is showing: the customer opened it and there is something in it. */\n readonly open: boolean;\n /** The zones the typed value is reaching for, in the order they were listed. */\n readonly suggestions: ReadonlyArray<Zone>;\n /** The suggestion Tab and Enter would complete, or `null` when the list is empty. */\n readonly highlighted: Zone | null;\n /** The zone the value already sits in, with the account its records would go to. */\n readonly found: { readonly zone: Zone; readonly placement: Placement } | null;\n /** Finish the name from one suggestion, keeping whatever subdomain was typed in front of it. */\n readonly complete: (zone: Zone) => void;\n readonly close: () => void;\n readonly inputProps: {\n readonly \"aria-activedescendant\": AriaAttributes[\"aria-activedescendant\"];\n readonly \"aria-autocomplete\": \"list\";\n readonly \"aria-controls\": string;\n readonly \"aria-expanded\": boolean;\n readonly autoComplete: \"off\";\n readonly id: string;\n readonly onChange: FormEventHandler<HTMLInputElement>;\n readonly onFocus: FocusEventHandler<HTMLInputElement>;\n readonly onKeyDown: KeyboardEventHandler<HTMLInputElement>;\n readonly role: \"combobox\";\n readonly type: \"text\";\n readonly value: string;\n };\n readonly listboxProps: {\n readonly \"aria-label\": string;\n readonly hidden: boolean;\n readonly id: string;\n readonly role: \"listbox\";\n };\n readonly optionProps: (zone: Zone) => OptionProps;\n}\n\n/**\n * One input over every zone the workspace's accounts reach, as props rather than markup. Arrow\n * keys move the highlight, Tab or Enter completes it, Escape closes the list, and `found` says\n * where the records will go.\n */\nexport function useDomainField({\n id,\n onChange,\n onResolve,\n value,\n zones,\n}: DomainFieldOptions): DomainFieldController {\n const messages = useMessages();\n const generated = useId();\n const inputId = id ?? generated;\n const listId = `${inputId}-suggestions`;\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(0);\n // Which account the customer completed from, so a zone two accounts both serve stays the one\n // they picked rather than whichever the listing happens to hold first. `placementOf` honours it\n // only while the value still sits in that zone, so a value that moves — whether the customer\n // typed it or the host set it — loses the preference by the same rule.\n const [chosen, setChosen] = useState<Placement | null>(null);\n const suggestions = suggestionsFor(value, zones);\n const highlighted = suggestions[Math.min(active, Math.max(suggestions.length - 1, 0))] ?? null;\n const found = placementOf(value, zones, chosen);\n const showing = open && suggestions.length > 0;\n\n // One report per value and placement: a re-render that changes neither says nothing.\n const placement = found?.placement ?? null;\n const connectionId = placement?.connectionId ?? null;\n const placedIn = placement?.zone ?? null;\n const announced = useRef<string | null>(null);\n useEffect(() => {\n const signature = `${value}|${connectionId ?? \"\"}|${placedIn ?? \"\"}`;\n if (announced.current === signature) return;\n announced.current = signature;\n onResolve?.({\n connection:\n connectionId === null || placedIn === null ? null : { connectionId, zone: placedIn },\n domain: value,\n });\n }, [connectionId, onResolve, placedIn, value]);\n\n const complete = (zone: Zone) => {\n onChange(completionOf(value, zone));\n setChosen({ connectionId: zone.connectionId, zone: zone.zone });\n setOpen(false);\n setActive(0);\n };\n\n return {\n close: () => setOpen(false),\n complete,\n found,\n highlighted,\n inputProps: {\n \"aria-activedescendant\":\n showing && highlighted !== null ? optionId(listId, highlighted) : undefined,\n \"aria-autocomplete\": \"list\",\n \"aria-controls\": listId,\n \"aria-expanded\": showing,\n autoComplete: \"off\",\n id: inputId,\n onChange: (event) => {\n onChange((event.target as HTMLInputElement).value);\n setActive(0);\n setOpen(true);\n },\n onFocus: () => setOpen(true),\n onKeyDown: (event) => {\n if (event.key === \"Escape\") {\n setOpen(false);\n return;\n }\n if (suggestions.length === 0) return;\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActive((index) => (index + 1) % suggestions.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setOpen(true);\n setActive((index) => (index + suggestions.length - 1) % suggestions.length);\n return;\n }\n // Tab and Enter finish the name rather than choosing one: what the customer typed in\n // front of the zone stays in front of it.\n if ((event.key === \"Tab\" || event.key === \"Enter\") && showing && highlighted !== null) {\n event.preventDefault();\n complete(highlighted);\n }\n },\n role: \"combobox\",\n type: \"text\",\n value,\n },\n listboxProps: {\n \"aria-label\": messages.zoneSuggestions,\n hidden: !showing,\n id: listId,\n role: \"listbox\",\n },\n open: showing,\n optionProps: (zone) => ({\n \"aria-selected\": zone === highlighted,\n id: optionId(listId, zone),\n // The press must not take focus off the input before the completion lands.\n onMouseDown: (event) => {\n event.preventDefault();\n complete(zone);\n },\n role: \"option\",\n }),\n suggestions,\n };\n}\n","import { Receipt, type DomainKit, type Storage } from \"domainkit\";\nimport { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport {\n AccountsState,\n completionOf,\n placementOf,\n suggestionsFor,\n useAccounts,\n useDomainField,\n useZones,\n ZonesState,\n type Account,\n type AccountsController,\n type AccountsOptions,\n type ConnectAccountInput,\n type DomainFieldController,\n type DomainFieldOptions,\n type Placement,\n type Zone,\n type ZonesController,\n type ZonesOptions,\n} from \"./domain-field.ts\";\n\nexport type Snapshot = Transport.Snapshot;\nexport type Discovery = Transport.Discovery;\nexport type Candidate = Transport.Candidate;\n/** A provider as the snapshot describes it: an id, a display name, and its auth methods. */\nexport type Descriptor = Transport.Snapshot[\"providers\"][number];\nexport type MethodDescriptor = Descriptor[\"methods\"][number];\nexport type Field = NonNullable<MethodDescriptor[\"fields\"]>[number];\n\n/**\n * Where a domain stands with its DNS provider. `Disconnected` carries whatever\n * `connection.discover` found, so the UI can offer a connection the customer already has before\n * asking for another one.\n */\nexport type State = Data.TaggedEnum<{\n Loading: { readonly snapshot: Snapshot | null };\n Disconnected: { readonly snapshot: Snapshot; readonly discovery: Discovery | null };\n Connected: { readonly snapshot: Snapshot };\n Reconnect: { readonly snapshot: Snapshot };\n Submitting: { readonly snapshot: Snapshot | null; readonly discovery: Discovery | null };\n Redirecting: { readonly url: string };\n SelectionRequired: {\n readonly snapshot: Snapshot | null;\n readonly connectionId: string;\n readonly candidates: ReadonlyArray<Candidate>;\n };\n Failure: {\n readonly error: DomainKit.Error;\n readonly snapshot: Snapshot | null;\n readonly discovery: Discovery | null;\n /** The provider and method the customer was using, when a command failed rather than a read. */\n readonly attempt: Attempt | null;\n };\n}>;\nexport const State = Data.taggedEnum<State>();\n\n/** Which provider and method the failed command was for, so the form can answer beside it. */\nexport interface Attempt {\n readonly provider: string;\n readonly method: Storage.AuthMethod;\n}\n\nexport interface ConnectInput {\n readonly provider: string;\n readonly method: Storage.AuthMethod;\n /** Keyed by the descriptor's field names. Ignored by the interactive methods. */\n readonly values?: Readonly<Record<string, string>>;\n /** Where an interactive method returns the customer. */\n readonly returnTo?: string;\n}\n\nexport interface Controller {\n readonly domain: string;\n /**\n * What this domain's last apply landed, read once per receipt id and held here. `null` until\n * the snapshot names a receipt, or when the transport carries no provisioning group.\n */\n readonly receipt: Receipt.Model | null;\n /**\n * How many times a connection has been established for this domain on this surface: a token\n * connect that landed, or a load that followed this library's own redirect back. It only ever\n * grows, so a flow acts on a change rather than on a state that would fire again every render.\n */\n readonly established: number;\n readonly state: State;\n readonly snapshot: Snapshot | null;\n readonly discovery: Discovery | null;\n readonly providers: ReadonlyArray<Descriptor>;\n readonly connect: (input: ConnectInput) => void;\n /** Attach the domain to a connection this owner already has. */\n readonly reuse: (input: { readonly connectionId: string; readonly zone?: string }) => void;\n /** Answer `SelectionRequired` by naming the zone that serves the domain. */\n readonly select: (zone: string) => void;\n readonly detach: () => void;\n readonly disconnect: () => void;\n /** Re-inspect the domain, discarding any failure. */\n readonly refresh: () => void;\n /** Re-run the step that failed; without one, re-inspect. */\n readonly retry: () => void;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * Where an interactive method returns the customer. Defaults to the page they started from;\n * pass `null` to send none and let the server's `defaultReturnTo` decide.\n */\n readonly returnTo?: string | null;\n /**\n * Refuse every command that changes the connection. Defaults to the surrounding `readOnly`,\n * which is `DomainKit.Root`'s unless a `DomainKit.ReadOnly` narrows it.\n */\n readonly readOnly?: boolean;\n}\n\n/**\n * An interactive method leaves the page and comes back, so what the library knew is gone with it.\n * It writes down the domain it sent the customer away for, and the load that follows reads it once:\n * that, not a query parameter a host would have to keep, is how a return is told from a reload.\n */\nconst RETURNING = \"domainkit.returning\";\n\nconst markReturn = (domain: string): void => {\n try {\n sessionStorage.setItem(RETURNING, domain);\n } catch {\n // A browser with storage turned off simply loses the one-click return.\n }\n};\n\nconst tookReturn = (domain: string): boolean => {\n try {\n if (sessionStorage.getItem(RETURNING) !== domain) return false;\n sessionStorage.removeItem(RETURNING);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Read at connect time, not at render, so it is the page the customer is actually on. */\nconst currentUrl = (): string | null =>\n typeof window === \"undefined\" ? null : window.location.href;\n\nconst snapshotOf = (state: State): Snapshot | null => {\n switch (state._tag) {\n case \"Connected\":\n case \"Reconnect\":\n case \"Disconnected\":\n return state.snapshot;\n case \"Loading\":\n case \"Submitting\":\n case \"SelectionRequired\":\n case \"Failure\":\n return state.snapshot;\n case \"Redirecting\":\n return null;\n }\n};\n\nconst settled = (snapshot: Snapshot, discovery: Discovery | null): State => {\n switch (snapshot.status) {\n case \"connected\":\n return State.Connected({ snapshot });\n case \"reconnect\":\n return State.Reconnect({ snapshot });\n case \"disconnected\":\n return State.Disconnected({ discovery, snapshot });\n }\n};\n\n/**\n * The domain's connection, and the four ways to change it. Discovery runs on mount whenever the\n * transport declares it and the domain has no connection yet; a discovery failure is not the\n * customer's problem, so the provider list still renders.\n */\nexport function useController({ domain, readOnly: refused, returnTo }: Options): Controller {\n const { emit, navigate, revision, transport } = useDomainKit();\n const inherited = useReadOnly();\n // The surface is the host's now, so a control it renders anyway must not reach the transport:\n // every command that changes the connection is refused here rather than hidden up there.\n const readOnly = refused ?? inherited;\n const connection = transport.connection;\n const provisioning = transport.provisioning;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Loading({ snapshot: null }));\n\n // The snapshot and the discovery belong to the domain they were read for, so a controller\n // pointed at a new domain drops both while rendering rather than one effect later.\n // What was read travels with the domain it was read for, so a command or a reply that arrives\n // after the controller moved refuses to act: one domain's attachment must never be detached for\n // another.\n const held = useRef<{\n domain: string;\n snapshot: Snapshot | null;\n discovery: Discovery | null;\n }>({ discovery: null, domain, snapshot: null });\n const lastCommand = useRef<{ domain: string; run: () => void } | null>(null);\n // What the customer was doing when it failed, so the dialog can answer beside that method.\n const attempted = useRef<Attempt | null>(null);\n\n const [established, setEstablished] = useState(0);\n const [inspected, setInspected] = useState(domain);\n if (inspected !== domain) {\n setInspected(domain);\n runner.cancel();\n held.current = { discovery: null, domain, snapshot: null };\n lastCommand.current = null;\n setState(State.Loading({ snapshot: null }));\n }\n\n // A failure keeps what was already read: the customer's provider list, the domain in the\n // dialog's description, and the discovery that offered a connection they already have.\n const onFailure = useCallback(\n (error: DomainKit.Error) => {\n setState(\n State.Failure({\n attempt: attempted.current,\n discovery: held.current.discovery,\n error,\n snapshot: held.current.snapshot,\n }),\n );\n emit(Event.Failed({ domain, error }));\n },\n [domain, emit],\n );\n\n const load = useCallback(() => {\n if (connection === undefined) return;\n lastCommand.current = null;\n attempted.current = null;\n held.current = { discovery: null, domain, snapshot: null };\n // A refresh keeps the snapshot on screen; a domain change already cleared it.\n setState((previous) => State.Loading({ snapshot: snapshotOf(previous) }));\n runner.run(\n Effect.flatMap(connection.inspect(domain), (snapshot) =>\n snapshot.status === \"disconnected\"\n ? Effect.map(\n connection.discover(domain).pipe(Effect.catch(() => Effect.succeed(null))),\n (discovery) => ({ discovery, snapshot }),\n )\n : Effect.succeed({ discovery: null, snapshot }),\n ),\n {\n onFailure,\n onSuccess: ({ discovery, snapshot }) => {\n if (held.current.domain !== domain) return;\n held.current = { discovery, domain, snapshot };\n // The marker answers exactly one load: the one that came back. It is spent whatever\n // that load found, so an authorization the customer abandoned cannot leave it lying\n // there for an ordinary page view to read as a return weeks later.\n const returned = tookReturn(domain);\n if (returned && snapshot.status === \"connected\") {\n setEstablished((count) => count + 1);\n }\n setState(settled(snapshot, discovery));\n },\n },\n );\n }, [connection, domain, onFailure, runner]);\n\n useEffect(load, [load, revision]);\n\n const started = useCallback(\n (result: Transport.Started) => {\n if (held.current.domain !== domain) return;\n switch (result._tag) {\n case \"Connected\": {\n const snapshot = result.snapshot;\n setEstablished((count) => count + 1);\n // This controller is one domain's, so every command it sends carries that domain and\n // comes back with its snapshot. A reply without one connected an account alone, which\n // only a host calling the transport directly can do, so read the domain again.\n if (snapshot === null) {\n load();\n return;\n }\n held.current = { discovery: null, domain, snapshot };\n setState(settled(snapshot, null));\n if (snapshot.connectionId !== null) {\n emit(Event.Connected({ connectionId: snapshot.connectionId, domain, snapshot }));\n }\n return;\n }\n case \"Redirect\":\n markReturn(domain);\n setState(State.Redirecting({ url: result.authorizationUrl }));\n navigate(result.authorizationUrl);\n return;\n case \"SelectionRequired\":\n setState(\n State.SelectionRequired({\n candidates: result.candidates,\n connectionId: result.connectionId,\n snapshot: held.current.snapshot,\n }),\n );\n return;\n }\n },\n [domain, emit, load, navigate],\n );\n\n const submit = useCallback(\n (effect: Effect.Effect<Transport.Started, DomainKit.Error>, attempt: Attempt | null) => {\n if (held.current.domain !== domain) return;\n attempted.current = attempt;\n const command = () => {\n setState(\n State.Submitting({\n discovery: held.current.discovery,\n snapshot: held.current.snapshot,\n }),\n );\n runner.run(effect, { onFailure, onSuccess: started });\n };\n lastCommand.current = { domain, run: command };\n command();\n },\n [domain, onFailure, runner, started],\n );\n\n const connect = useCallback(\n (input: ConnectInput) => {\n if (connection === undefined || readOnly) return;\n const destination = input.returnTo ?? (returnTo === undefined ? currentUrl() : returnTo);\n const interactive = destination === null ? {} : { returnTo: destination };\n const method =\n input.method === \"token\"\n ? Transport.Method.token(input.values ?? {})\n : input.method === \"oauth\"\n ? Transport.Method.oauth(interactive)\n : Transport.Method.integration(interactive);\n // A domain whose connection the provider turned down is not asking for a second account:\n // proving the same provider again re-credits the connection it already has, and the domains\n // on it stay where they are. Starting instead would fail, because the domain is attached.\n const snapshot = held.current.snapshot;\n const stale =\n snapshot?.status === \"reconnect\" &&\n snapshot.provider === input.provider &&\n snapshot.connectionId !== null;\n submit(\n stale && snapshot?.connectionId != null\n ? connection.reconnect({ connectionId: snapshot.connectionId, method })\n : connection.start({ domain, method, provider: input.provider }),\n { method: input.method, provider: input.provider },\n );\n },\n [connection, domain, readOnly, returnTo, submit],\n );\n\n const reuse = useCallback(\n (input: { readonly connectionId: string; readonly zone?: string }) => {\n if (connection === undefined || readOnly) return;\n submit(\n connection.attach({\n connectionId: input.connectionId,\n domain,\n ...(input.zone === undefined ? {} : { zone: input.zone }),\n }),\n null,\n );\n },\n [connection, domain, readOnly, submit],\n );\n\n const select = useCallback(\n (zone: string) => {\n if (state._tag !== \"SelectionRequired\") return;\n reuse({ connectionId: state.connectionId, zone });\n },\n [reuse, state],\n );\n\n const release = useCallback(\n (effect: Effect.Effect<void, DomainKit.Error>, event: Event) => {\n if (held.current.domain !== domain) return;\n attempted.current = null;\n const command = () => {\n setState(\n State.Submitting({\n discovery: held.current.discovery,\n snapshot: held.current.snapshot,\n }),\n );\n runner.run(effect, {\n onFailure,\n onSuccess: () => {\n emit(event);\n load();\n },\n });\n };\n lastCommand.current = { domain, run: command };\n command();\n },\n [domain, emit, load, onFailure, runner],\n );\n\n const detach = useCallback(() => {\n const attachmentId = held.current.snapshot?.attachment?.id;\n if (readOnly || connection === undefined || attachmentId == null) return;\n if (held.current.domain !== domain) return;\n release(connection.detach(attachmentId), Event.Detached({ domain }));\n }, [connection, domain, readOnly, release]);\n\n const disconnect = useCallback(() => {\n const connectionId = held.current.snapshot?.connectionId;\n if (readOnly || connection === undefined || connectionId == null) return;\n if (held.current.domain !== domain) return;\n release(connection.disconnect(connectionId), Event.Disconnected({ connectionId, domain }));\n }, [connection, domain, readOnly, release]);\n\n const retry = useCallback(() => {\n const command = lastCommand.current;\n // Re-inspecting is a read, so it stays; rerunning the last write does not.\n if (readOnly || command === null || command.domain !== domain) load();\n else command.run();\n }, [domain, load, readOnly]);\n\n // One connection of this owner already serves the zone, so the customer has nothing left to\n // decide: the account they granted covers this domain too. Attaching here is what keeps a second\n // domain from meeting the connect dialog again. Each (domain, connection, zone) is tried once,\n // so an attach that failed, or one the customer undid with a detach, is not started over.\n const sighted = useRef<string | null>(null);\n useEffect(() => {\n if (readOnly || state._tag !== \"Disconnected\") return;\n const discovery = state.discovery;\n if (discovery === null || discovery._tag !== \"Resolved\") return;\n const sight = `${domain}|${discovery.connectionId}|${discovery.zone}`;\n if (sighted.current === sight) return;\n sighted.current = sight;\n reuse({ connectionId: discovery.connectionId, zone: discovery.zone });\n }, [domain, readOnly, reuse, state]);\n\n // The card names how many records this domain holds, which only the receipt knows. One read per\n // receipt id: the id changes when an apply lands, and nothing else moves it.\n const [receipt, setReceipt] = useState<Receipt.Model | null>(null);\n const receiptId = snapshotOf(state)?.lastReceiptId ?? null;\n const readReceipt = useRef<string | null>(null);\n useEffect(() => {\n if (receiptId === null) {\n readReceipt.current = null;\n setReceipt(null);\n return;\n }\n if (provisioning === undefined || readReceipt.current === receiptId) return;\n readReceipt.current = receiptId;\n runner.run(provisioning.receipt(Receipt.ReceiptId.make(receiptId)), {\n // A receipt the surface cannot read is one line of copy missing, not a failure the\n // customer has to answer, so the card renders without it.\n onFailure: () => setReceipt(null),\n onSuccess: (value) => setReceipt(value.id === receiptId ? value : null),\n });\n }, [provisioning, receiptId, runner]);\n\n return {\n connect,\n detach,\n disconnect,\n domain,\n established,\n discovery:\n state._tag === \"Disconnected\" || state._tag === \"Failure\" || state._tag === \"Submitting\"\n ? state.discovery\n : null,\n providers: snapshotOf(state)?.providers ?? [],\n receipt: receipt?.id === receiptId ? receipt : null,\n refresh: load,\n retry,\n reuse,\n select,\n snapshot: snapshotOf(state),\n state,\n };\n}\n\n// ---------------------------------------------------------------------------------------------\n// Reading a connection\n// ---------------------------------------------------------------------------------------------\n\n/**\n * Whether a failure is already answered where it was raised: beside the method the customer used.\n * A surface rendering one outcome for the whole flow skips it, so the failure announces once.\n */\nexport const answeredInPlace = (controller: Controller): boolean =>\n controller.state._tag === \"Failure\" && controller.state.attempt !== null;\n\n/**\n * Whether the surface should read as connected: it is, or a command it started is in flight over a\n * connection that was. The provider row and the dialog it opened stay on screen for the length of\n * the command rather than vanishing under the customer half way through it.\n */\nexport const holdsConnection = (controller: Controller): boolean =>\n controller.state._tag === \"Connected\" ||\n (controller.state._tag === \"Submitting\" && controller.snapshot?.status === \"connected\");\n\n/**\n * Whether the provider turned the credential down, so the customer must prove the account again.\n * Proving it re-credits the connection the workspace already holds and leaves its domains where\n * they are, which is why the surface offers a reconnect rather than a second account.\n */\nexport const reconnect = (controller: Controller): boolean =>\n controller.state._tag === \"Reconnect\" ||\n (controller.state._tag === \"Submitting\" && controller.snapshot?.status === \"reconnect\");\n\n/**\n * The provider whose nameservers serve this domain, as the snapshot describes it. Discovery names\n * it by id; without a descriptor there is nothing to draw, so there is no host.\n */\nexport const hostProvider = (controller: Controller): Descriptor | null => {\n const discovery = controller.discovery;\n if (discovery === null || discovery._tag !== \"NotFound\" || discovery.host === null) return null;\n const named = discovery.host.provider;\n return controller.providers.find((entry) => entry.id === named) ?? null;\n};\n\n/** The descriptor for one provider id, or `null` when the snapshot describes no such provider. */\nexport const providerOf = (\n controller: Controller,\n providerId: string | null | undefined,\n): Descriptor | null =>\n providerId == null\n ? null\n : (controller.providers.find((entry) => entry.id === providerId) ?? null);\n\n/** The provider as the customer knows it, falling back to the id when the snapshot has no name. */\nexport const displayName = (controller: Controller, providerId: string): string =>\n providerOf(controller, providerId)?.name ?? providerId;\n\n/**\n * Whether the flow offers a connect surface: only when discovery names a host, always, or never.\n * `never` is a host that decides for itself, such as a domain already ready without DomainKit; a\n * connected domain keeps its status and its disconnect either way.\n */\nexport type Invitation = \"always\" | \"detected\" | \"never\";\n\n/**\n * Whether the connect surface has anything to offer for this domain: a provider that serves the\n * zone, a connection discovery already found, one the owner already holds, or a command already\n * running. Never while a connection is held, which is what `holdsConnection` answers. A host reads\n * it to order its own offers beside DomainKit's rather than competing with them.\n */\nexport const offering = (controller: Controller, connect: Invitation = \"detected\"): boolean => {\n // A surface that holds a connection is not offering one: the connected row is what renders, and\n // a host reading both must never see them claim different things about the same domain.\n if (holdsConnection(controller)) return false;\n const state = controller.state;\n // A command in flight owns the surface whatever discovery found: it is how the customer answers\n // a zone choice, a reconnect, or a redirect that came back.\n if (\n state._tag === \"Submitting\" ||\n state._tag === \"Redirecting\" ||\n state._tag === \"SelectionRequired\" ||\n state._tag === \"Reconnect\"\n ) {\n return true;\n }\n if (connect !== \"detected\") return connect === \"always\";\n const discovery = controller.discovery;\n return (\n hostProvider(controller) !== null ||\n (discovery !== null && discovery._tag !== \"NotFound\") ||\n (controller.snapshot?.reusable.length ?? 0) > 0\n );\n};\n\n/** A connection this owner already holds that would serve the domain, as one list to offer. */\nexport interface Reusable {\n readonly connectionId: string;\n /** The zone the connection would attach, when discovery named one. */\n readonly zone: string | undefined;\n readonly label: string;\n}\n\n/**\n * Every connection the customer can attach without proving anything: the one discovery resolved,\n * the candidates a zone choice is between, and the connections the snapshot lists as reusable.\n */\nexport const reusableConnections = (controller: Controller): ReadonlyArray<Reusable> => {\n const state = controller.state;\n const discovery = controller.discovery;\n const candidates =\n state._tag === \"SelectionRequired\"\n ? state.candidates.map((candidate) => ({ ...candidate, connectionId: state.connectionId }))\n : discovery !== null && discovery._tag === \"SelectionRequired\"\n ? discovery.candidates\n : [];\n const resolved = discovery !== null && discovery._tag === \"Resolved\" ? [discovery] : [];\n return [\n ...resolved.map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.label,\n zone: entry.zone,\n })),\n ...candidates.map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.label,\n zone: entry.zone,\n })),\n ...(controller.snapshot?.reusable ?? []).map((entry) => ({\n connectionId: entry.connectionId,\n label: entry.provider,\n zone: undefined,\n })),\n ];\n};\n\n// ---------------------------------------------------------------------------------------------\n// Reading a provider's methods\n// ---------------------------------------------------------------------------------------------\n\n/** The fields one token method declares, split into what the surface asks for and what it hides. */\nexport interface MethodFields {\n readonly required: ReadonlyArray<Field>;\n /** The fields a provider does not need, which the surface keeps behind a disclosure. */\n readonly optional: ReadonlyArray<Field>;\n /** The field the provider's documentation link explains: the first secret, else the first field. */\n readonly explains: string | null;\n}\n\n/** One declared auth method, with the fields it asks for already arranged. */\nexport interface DescribedMethod {\n readonly kind: Storage.AuthMethod;\n readonly descriptor: MethodDescriptor;\n /** `null` for a method the customer clicks through, which asks for nothing on the page. */\n readonly fields: MethodFields | null;\n}\n\n/** What one provider offers, in the order the descriptor declares it. */\nexport interface DescribedMethods {\n /** The methods the customer clicks through: OAuth and the provider's own integration. */\n readonly interactive: ReadonlyArray<DescribedMethod>;\n /** The methods that ask for credentials on the page. */\n readonly typed: ReadonlyArray<DescribedMethod>;\n /**\n * Both kinds are on offer, so the surface shows the interactive one and a control that opens the\n * token form in its place: one decision at a time rather than a wall of alternatives.\n */\n readonly alternate: boolean;\n}\n\nconst fieldsOf = (method: MethodDescriptor): MethodFields | null => {\n const fields = method.fields;\n if (fields === null) return null;\n const required = fields.filter((field) => field.required);\n const optional = fields.filter((field) => !field.required);\n return {\n explains: (required.find((field) => field.secret) ?? required[0] ?? optional[0])?.name ?? null,\n optional,\n required,\n };\n};\n\n/** One provider's auth methods, arranged for a surface that asks for one decision at a time. */\nexport const describeMethods = (provider: Descriptor): DescribedMethods => {\n const described = provider.methods.map<DescribedMethod>((method) => ({\n descriptor: method,\n fields: fieldsOf(method),\n kind: method.kind,\n }));\n const interactive = described.filter((method) => method.fields === null);\n const typed = described.filter((method) => method.fields !== null);\n return { alternate: interactive.length > 0 && typed.length > 0, interactive, typed };\n};\n\n/**\n * The one field a rejected command was about, if any. A provider that turns down credentials is\n * answering the secret it was given, and it names no field, so the first secret carries the\n * answer; anything else is about the request rather than one input.\n */\nexport const rejectedField = (\n error: DomainKit.Error | null,\n fields: ReadonlyArray<Field>,\n): string | null => {\n if (error === null) return null;\n const reason = error.reason;\n if (reason._tag === \"InvalidInput\") {\n return fields.find((field) => field.name === reason.field)?.name ?? null;\n }\n if (reason._tag !== \"Unauthenticated\" && reason._tag !== \"Forbidden\") return null;\n return fields.find((field) => field.secret)?.name ?? null;\n};\n\n/** Whether a failure was raised by this provider's method, so the form answers beside it. */\nexport const attempted = (\n controller: Controller,\n provider: string,\n method: Storage.AuthMethod,\n): DomainKit.Error | null => {\n const state = controller.state;\n if (state._tag !== \"Failure\" || state.attempt === null) return null;\n return state.attempt.provider === provider && state.attempt.method === method\n ? state.error\n : null;\n};\n","/**\n * What a domain's requirements are, as data: the zone file they spell, the clipboard control a\n * value needs, and the standing one row reports. The table itself is the host's.\n */\nimport { DnsRecord, Verify, type Plan } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type Readiness = Transport.Readiness;\nexport type RequirementStatus = Readiness[\"requirements\"][number][\"status\"];\n\n// ---------------------------------------------------------------------------------------------\n// Zone file\n// ---------------------------------------------------------------------------------------------\n\nconst absolute = (value: string): string => (value.endsWith(\".\") ? value : `${value}.`);\n\nconst textEncoder = new TextEncoder();\n\nconst escapeTxtCharacter = (character: string): string => {\n if (character === '\"' || character === \"\\\\\") return `\\\\${character}`;\n const codePoint = character.codePointAt(0);\n if (codePoint !== undefined && (codePoint < 32 || codePoint === 127)) {\n return `\\\\${codePoint.toString().padStart(3, \"0\")}`;\n }\n return character;\n};\n\n/** TXT strings are capped at 255 bytes each, so long values are split and quoted per chunk. */\nconst txtValue = (value: string): string => {\n const chunks: Array<string> = [];\n let chunk = \"\";\n let byteLength = 0;\n for (const character of value) {\n const characterByteLength = textEncoder.encode(character).byteLength;\n if (byteLength + characterByteLength > 255) {\n chunks.push(chunk);\n chunk = \"\";\n byteLength = 0;\n }\n chunk += escapeTxtCharacter(character);\n byteLength += characterByteLength;\n }\n chunks.push(chunk);\n return chunks.map((part) => `\"${part}\"`).join(\" \");\n};\n\n/** The RR type as a zone file spells it. The tag and the type name are the same string. */\nconst rrType = (record: DnsRecord.Model): string => record._tag;\n\nconst zoneData = (record: DnsRecord.Model): string => {\n switch (record._tag) {\n case \"A\":\n case \"AAAA\":\n return record.address;\n case \"CNAME\":\n return absolute(record.target);\n case \"NS\":\n return absolute(record.nameserver);\n case \"TXT\":\n return txtValue(record.value);\n case \"MX\":\n return `${record.priority} ${absolute(record.exchange)}`;\n case \"CAA\":\n return `${record.flags} ${record.tag} \"${record.value}\"`;\n case \"SRV\":\n return `${record.priority} ${record.weight} ${record.port} ${absolute(record.target)}`;\n }\n};\n\nexport const toZoneFile = (records: ReadonlyArray<DnsRecord.Model>): string =>\n `${records\n .map(\n (record) =>\n `${absolute(record.name)}${record.ttl === null ? \"\" : ` ${record.ttl}`} IN ${rrType(record)} ${zoneData(record)}`,\n )\n .join(\"\\n\")}\\n`;\n\nconst downloadText = (filename: string, contents: string): void => {\n if (typeof document === \"undefined\") return;\n const blob = new Blob([contents], { type: \"text/plain;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.download = filename;\n anchor.href = url;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n};\n\nexport const downloadZoneFile = (domain: string, records: ReadonlyArray<DnsRecord.Model>): void =>\n downloadText(`${domain}.txt`, toZoneFile(records));\n\n// ---------------------------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------------------------\n\nexport const copyText = (value: string): Promise<boolean> => {\n if (typeof navigator === \"undefined\" || navigator.clipboard === undefined) {\n return Promise.resolve(false);\n }\n return navigator.clipboard.writeText(value).then(\n () => true,\n () => false,\n );\n};\n\nexport interface CopyController {\n readonly copied: boolean;\n readonly copy: () => void;\n}\n\nexport function useCopy(value: string, resetAfter = 2000): CopyController {\n const [copied, setCopied] = useState(false);\n const reset = useRef<ReturnType<typeof setTimeout>>(undefined);\n useEffect(() => () => clearTimeout(reset.current), []);\n return {\n copied,\n copy: () => {\n void copyText(value).then((ok) => {\n if (!ok) return;\n setCopied(true);\n clearTimeout(reset.current);\n reset.current = setTimeout(() => setCopied(false), resetAfter);\n });\n },\n };\n}\n\n/**\n * What a row has to say about one record: the operation a plan still awaiting its apply holds for\n * it, and the requirement the last observation stored for it. They are two facts, not one — a\n * pending plan says what will be written, an observation says what is there — so a surface renders\n * whichever of them its column is about rather than being handed a winner.\n */\nexport interface Standing {\n /** The pending plan's operation for this record, or `null` when no plan covers it. */\n readonly planned: Plan.Operation | null;\n /** The stored requirement, evidence included, or `null` when no observation covers it. */\n readonly observed: Readiness[\"requirements\"][number] | null;\n}\n\nexport interface Sources {\n /** A plan still awaiting its apply. Pass `null` once one has landed; readiness answers then. */\n readonly plan?: Plan.Model | null | undefined;\n readonly readiness?: Readiness | null | undefined;\n}\n\n/** Both facts a row can carry about one record, each `null` when nothing covers it. */\nexport const standingOf = (record: DnsRecord.Model, sources: Sources): Standing => ({\n planned: sources.plan?.operations.find((entry) => DnsRecord.equals(entry.record, record)) ?? null,\n observed:\n sources.readiness?.requirements.find((requirement) =>\n DnsRecord.equals(requirement.record, record),\n ) ?? null,\n});\n\n/**\n * A stable React key for a requirement: type, name, and data identify a record. It is\n * `Verify.requirementKey` from the core package, which is the `key` every readiness requirement\n * carries, so a row and the observation about it are paired by the same string.\n */\nexport const identity = Verify.requirementKey;\n\n/**\n * A requirement set keyed by everything it carries, for memos that decide whether to re-send it.\n * `identity` is deliberately narrower: it answers \"is this the same record\" for a React key, while\n * a plan and an observation are built from `ttl`, `policy`, and `purpose` as well. `policy` in\n * particular decides whether a name may hold anything else, so readiness turns on it.\n */\nexport const requirementsKey = (records: ReadonlyArray<DnsRecord.Model>): string =>\n JSON.stringify(records);\n","import { DnsRecord, type Receipt } from \"domainkit\";\nimport { useCallback } from \"react\";\n\nimport { pendingPlan, planOf, State, useAttempt, type Controller } from \"./attempt.ts\";\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { requirementsKey } from \"./records.ts\";\n\nexport { pendingPlan, planOf, State };\nexport type { Controller };\n\nexport interface Options {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n readonly onApplied?: (receipt: Receipt.Model) => void;\n /** Refuse every step. Defaults to the surrounding `readOnly`. */\n readonly readOnly?: boolean;\n}\n\n/**\n * Plan, approve, apply; `approve` authorizes the digest and applies it in the same action.\n * Requirements identify themselves by content, so an inline array does not abandon the attempt.\n * Every field counts: a plan turns on `policy`, and `ttl` and `purpose` ride the wire with it.\n */\nconst keyOf = (domain: string, requirements: ReadonlyArray<DnsRecord.Model>): string =>\n [domain, requirementsKey(requirements)].join(\"|\");\n\nexport function useController({ domain, onApplied, readOnly, requirements }: Options): Controller {\n const { transport } = useDomainKit();\n const group = transport.provisioning;\n return useAttempt({\n domain,\n key: keyOf(domain, requirements),\n done: (receipt) => Event.Applied({ domain, receipt }),\n group,\n onDone: onApplied,\n readOnly,\n plan: useCallback(\n () => (group === undefined ? null : group.plan({ domain, requirements })),\n [domain, group, requirements],\n ),\n });\n}\n","import { DnsRecord, DomainName, Verify, type DomainKit } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as Data from \"effect/Data\";\nimport * as DateTime from \"effect/DateTime\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useDomainKit } from \"./domain-kit.tsx\";\nimport { Event } from \"./events.ts\";\nimport { requirementsKey } from \"./records.ts\";\nimport { useRunner } from \"./task.ts\";\n\nexport type Readiness = Transport.Readiness;\nexport type HostEvidence = Readiness[\"host\"][number];\nexport type Requirement = Readiness[\"requirements\"][number];\nexport type Evidence = Requirement[\"evidence\"][number];\n\n/** Counts across a readiness's requirements, from the core package. Pure, and total over `null`. */\nexport const summary = Verify.summary;\nexport type Summary = Verify.Summary;\n\n/**\n * What the observer read back for the requirement's name, or `null` when it read nothing back at\n * all. Host evidence reports a status the host reached rather than values read off a name, and an\n * `unknown` observation is a lookup that never answered, which is not the same as finding nothing.\n */\nexport const valuesOf = (evidence: Evidence): ReadonlyArray<string> | null =>\n evidence._tag === \"Host\" || evidence.status === \"unknown\" ? null : evidence.values;\n\n/**\n * Readiness rides on the state rather than a ref, so it can never outlive the render that\n * produced it: a controller pointed at a new domain has no readiness in the very first frame.\n */\nexport type State = Data.TaggedEnum<{\n Idle: {};\n Observing: { readonly readiness: Readiness | null };\n Observed: { readonly readiness: Readiness };\n Failure: { readonly error: DomainKit.Error; readonly readiness: Readiness | null };\n}>;\nexport const State = Data.taggedEnum<State>();\n\nconst readinessOf = (state: State): Readiness | null =>\n state._tag === \"Idle\" ? null : state.readiness;\n\nexport interface Controller {\n readonly state: State;\n /** The latest readiness, kept while a new observation runs. */\n readonly readiness: Readiness | null;\n readonly observe: () => void;\n /** Observe again after a failure. */\n readonly retry: () => void;\n /** Whether this controller re-observes at `nextCheckAt` while mounted. */\n readonly polling: boolean;\n}\n\n/**\n * Readiness the host already holds, and how to ask it for a fresh one. A host that observes on its\n * own clock — a cron, a durable job, a server render — supplies the stored fact rather than letting\n * every mounted surface make an observation of its own.\n */\nexport interface Supplied {\n /** Readiness for this controller's domain; one read for another domain is discarded. */\n readonly readiness: Readiness | null;\n /** What `observe` and `retry` call. Absent means the surface cannot ask, and both do nothing. */\n readonly observe?: (() => void) | undefined;\n}\n\nexport interface Options {\n readonly domain: string;\n /**\n * What to look for. Supplied requirements win over the attachment's latest provisioning receipt,\n * which is what lets a domain with no attachment be verified at all.\n */\n readonly requirements?: ReadonlyArray<DnsRecord.Model>;\n /** Re-observe at each `nextCheckAt` while mounted. Default true. */\n readonly polling?: boolean;\n /**\n * Take readiness from the host instead of observing. The controller then makes no observation on\n * mount, sets no timer, and reports `polling: false`; `observe` and `retry` call the host's.\n */\n readonly supplied?: Supplied | undefined;\n}\n\n/**\n * One name, however the host spelled it. Readiness is stored under `DomainName`'s normalised form,\n * so the comparison runs through the same boundary rather than a second spelling rule of its own.\n * A value that boundary rejects is compared as written, which is the strictest thing left to do.\n */\nconst sameDomain = (one: string, other: string): boolean => {\n const left = DomainName.fromString(one);\n const right = DomainName.fromString(other);\n return Option.isSome(left) && Option.isSome(right) ? left.value === right.value : one === other;\n};\n\n/**\n * Observe once on mount, then follow the readiness's own `nextCheckAt` while polling is on — or,\n * given `supplied`, report the host's readiness and leave the clock to it.\n */\nexport function useController({\n domain,\n polling = true,\n requirements,\n supplied,\n}: Options): Controller {\n const { emit, revision, transport } = useDomainKit();\n const verification = transport.verification;\n const runner = useRunner();\n const [state, setState] = useState<State>(State.Idle());\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n // Requirements identify themselves by content, so a host writing the array inline does not\n // rebuild `observe` on every render and set the mount effect observing in a loop. The key covers\n // every field, because `policy` and `ttl` ride the wire and `policy` decides readiness.\n const signature = requirements === undefined ? null : requirementsKey(requirements);\n const requested = useMemo(\n () => (requirements === undefined ? undefined : { requirements }),\n [signature],\n );\n\n // Readiness belongs to the domain that was observed. Dropping it while rendering, rather than\n // in an effect, keeps the first frame for a new domain free of the previous one's evidence.\n // The domain travels with it, so an answer that arrives after the controller moved refuses\n // itself rather than hanging one domain's evidence under another's name.\n const held = useRef(domain);\n const [observed, setObserved] = useState(domain);\n if (observed !== domain) {\n setObserved(domain);\n held.current = domain;\n setState(State.Idle());\n }\n\n // The option's identity is the host's to churn, so the callbacks depend on the two facts in it\n // rather than on the object: whether the host owns the clock, and what it wants called.\n const hostOwned = supplied !== undefined;\n const hostObserve = supplied?.observe;\n // Readiness belongs to the domain it was read for, exactly as an observed one does. A host that\n // re-renders with a new domain before its own read lands would otherwise hang the previous\n // domain's evidence under the new name, and `Domain.useFlow` would plan from its drift.\n const offered = supplied?.readiness ?? null;\n const hostReadiness = offered !== null && sameDomain(offered.domain, domain) ? offered : null;\n\n const observe = useCallback(() => {\n // The host owns the clock, so asking for a new reading is asking the host for one.\n if (hostOwned) {\n hostObserve?.();\n return;\n }\n if (verification === undefined) return;\n clearTimeout(timer.current);\n setState((previous) => State.Observing({ readiness: readinessOf(previous) }));\n runner.run(\n requested === undefined\n ? verification.observe(domain)\n : verification.observe(domain, requested),\n {\n onFailure: (error) => {\n if (held.current !== domain) return;\n setState((previous) => State.Failure({ error, readiness: readinessOf(previous) }));\n emit(Event.Failed({ domain, error }));\n },\n onSuccess: (readiness) => {\n if (held.current !== domain) return;\n setState(State.Observed({ readiness }));\n },\n },\n );\n }, [domain, emit, hostObserve, hostOwned, requested, runner, verification]);\n\n useEffect(() => {\n if (hostOwned) return;\n observe();\n }, [hostOwned, observe, revision]);\n\n useEffect(() => {\n // A controller that observed for itself and is then handed a supplied readiness stops here:\n // its last observation's `nextCheckAt` is not a schedule the host asked for, and the cleanup\n // of the previous run clears the timer that observation already set.\n if (hostOwned || !polling || state._tag !== \"Observed\") return;\n const next = state.readiness.nextCheckAt;\n if (next === null) return;\n const delay = Math.max(0, DateTime.toEpochMillis(next) - Date.now());\n timer.current = setTimeout(observe, delay);\n return () => clearTimeout(timer.current);\n }, [hostOwned, observe, polling, state]);\n\n useEffect(() => () => clearTimeout(timer.current), []);\n\n // A supplied readiness is a fact, not a state machine: the host has either read one or not.\n // The internal state stays `Idle` under it, which is what keeps the timer effect asleep.\n const suppliedState = useMemo(\n () => (hostReadiness === null ? State.Idle() : State.Observed({ readiness: hostReadiness })),\n [hostReadiness],\n );\n\n return {\n observe,\n polling: !hostOwned && polling,\n readiness: hostOwned ? hostReadiness : readinessOf(state),\n retry: observe,\n state: hostOwned ? suppliedState : state,\n };\n}\n","/**\n * The whole lifecycle for one domain in one hook: connect, add the records, observe, clean up.\n * `useFlow` runs the four controllers together and plans as soon as the domain is attached with\n * nothing applied, and again when an observation reads an applied record back missing or wrong, so\n * the styled surface is only markup.\n */\nimport { Receipt, type DnsRecord, type Plan } from \"domainkit\";\nimport type { Transport } from \"domainkit/client\";\nimport * as DateTime from \"effect/DateTime\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport * as Cleanup from \"./cleanup.ts\";\nimport * as Connect from \"./connect.ts\";\nimport { useDomainKit, useReadOnly } from \"./domain-kit.tsx\";\nimport * as Provision from \"./provision.ts\";\nimport { identity, requirementsKey } from \"./records.ts\";\nimport * as Verify from \"./verify.ts\";\n\n/**\n * What DomainKit has to say about this domain. A host reads `connected` and `offering` to order\n * its own offers beside DomainKit's: an offer of its own competes while `offering` is true, and a\n * domain DomainKit holds needs none.\n */\nexport interface FlowState {\n readonly connection: Connect.State[\"_tag\"];\n readonly provisioning: Provision.State[\"_tag\"];\n /**\n * DomainKit holds a connection for this domain, including while a command it started over that\n * connection is still running. `offering` is never true at the same time.\n */\n readonly connected: boolean;\n /** The connect surface has something to offer, so a host's own offer would compete with it. */\n readonly offering: boolean;\n /** Who holds the connection, or whose nameservers serve the zone. */\n readonly provider: string | null;\n /**\n * The account the records go to, as the provider labelled the zone when the domain was attached.\n * `null` until there is an attachment.\n */\n readonly label: string | null;\n /**\n * The apply receipt this domain's latest provisioning attempt produced, which is what cleanup\n * plans from. A host's own \"remove this domain\" surface offers cleanup only when there is one.\n */\n readonly receiptId: Receipt.ReceiptId | null;\n /** `receiptId !== null`: DomainKit applied records here and can prove which. */\n readonly applied: boolean;\n /**\n * The surface may read this domain but not write to it, so a host can say why rather than\n * leaving a customer in front of a page with nothing on it.\n */\n readonly readOnly: boolean;\n}\n\nexport interface FlowOptions {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n /**\n * Offer the connect surface even when discovery names no host, for a host application that lets\n * a customer connect a provider the domain's nameservers do not point at, or `never` for a\n * domain the host has already settled another way. Defaults to `detected`.\n */\n readonly connect?: Connect.Invitation;\n readonly onApplied?: (receipt: Receipt.Model) => void;\n readonly onCleaned?: (receipt: Receipt.Model) => void;\n /**\n * Where an interactive provider flow returns the customer. Defaults to the page they started\n * from; pass `null` to let the server's `defaultReturnTo` decide.\n */\n readonly returnTo?: string | null;\n /** Report this domain's state without the controls that change it. Defaults to the root's. */\n readonly readOnly?: boolean;\n /**\n * Take readiness from the host instead of observing. A host that observes on its own clock — a\n * cron, a durable job, a server render that already read `Verify.latest` — supplies the stored\n * fact, and the flow makes no observation on mount and sets no timer. `flow.verification.observe`\n * and `retry` call the host's `observe`, or do nothing when it supplies none. Drift replanning\n * runs off the supplied readiness exactly as it does off an observed one.\n */\n readonly verification?: Verify.Supplied;\n}\n\nexport interface Flow {\n readonly domain: string;\n /** What the host asked for, as the surface renders it row by row. */\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n readonly state: FlowState;\n readonly connection: Connect.Controller;\n readonly provisioning: Provision.Controller;\n /** Bound to the domain's latest apply receipt, which is the only thing cleanup may undo. */\n readonly cleanup: Cleanup.Controller;\n readonly verification: Verify.Controller;\n /** The plan the rows report, which is one still awaiting its apply. */\n readonly plan: Plan.Model | null;\n readonly readiness: Verify.Readiness | null;\n /** Which capability groups the transport declares, so a surface renders only what it can run. */\n readonly capabilities: ReadonlyArray<Transport.Capability>;\n /** What the flow was told to offer when discovery names no host. */\n readonly invitation: Connect.Invitation;\n}\n\n/** Built from primitives alone, so the memo that reports it depends on exactly those. */\nconst flowState = (input: {\n readonly connected: boolean;\n readonly label: string | null;\n readonly offering: boolean;\n readonly planning: Provision.State[\"_tag\"];\n readonly provider: string | null;\n readonly readOnly: boolean;\n readonly receipt: string | null;\n readonly status: Connect.State[\"_tag\"];\n}): FlowState => ({\n applied: input.receipt !== null,\n connected: input.connected,\n connection: input.status,\n label: input.label,\n offering: input.offering,\n provider: input.provider,\n provisioning: input.planning,\n readOnly: input.readOnly,\n receiptId: input.receipt === null ? null : Receipt.ReceiptId.make(input.receipt),\n});\n\n/**\n * A removal this flow is carrying out, at whatever step it reached. A cleanup that failed halfway\n * has taken records away, and offering them back would contradict what the customer asked for, so\n * the intent stands until the plan is declined or the flow is mounted again.\n */\nconst removing = (cleanup: Cleanup.State): boolean =>\n cleanup._tag !== \"Idle\" && cleanup._tag !== \"Rejecting\" && cleanup._tag !== \"Rejected\";\n\n/**\n * Which records an applied domain lost, keyed by the records themselves rather than by when they\n * were read, so every observation that reports the same drift is one reason to plan. `null` when\n * there is nothing to add back:\n *\n * - the observation was stored before the apply, so it is evidence about a zone from before the\n * records were written rather than about records that went missing since. An observation that\n * read the zone before the apply and stored after it is interrupted instead: the apply starts a\n * new one, and the runner drops whatever it replaced;\n * - this flow is the one taking the records away;\n * - every requirement was found.\n */\nconst driftKey = (\n readiness: Verify.Readiness | null,\n receipt: Receipt.Model | null,\n cleanup: Cleanup.State,\n): string | null => {\n if (readiness === null || receipt === null) return null;\n if (DateTime.isLessThan(readiness.checkedAt, receipt.appliedAt)) return null;\n if (removing(cleanup)) return null;\n const drifted = readiness.requirements\n .filter(({ status }) => status === \"missing\" || status === \"mismatch\")\n .map(({ record, status }) => `${identity(record)} ${status}`)\n .sort();\n return drifted.length === 0 ? null : drifted.join(\"\\n\");\n};\n\nexport function useFlow({\n connect = \"detected\",\n domain,\n onApplied,\n onCleaned,\n readOnly,\n requirements,\n returnTo,\n verification: supplied,\n}: FlowOptions): Flow {\n const { capabilities } = useDomainKit();\n const inherited = useReadOnly();\n const surfaceReadOnly = readOnly ?? inherited;\n // The flow's own flag reaches its controllers, so a read-only domain among writable ones\n // refuses commands rather than only reporting that it should.\n const connection = Connect.useController({\n domain,\n readOnly: surfaceReadOnly,\n ...(returnTo === undefined ? {} : { returnTo }),\n });\n const refresh = connection.refresh;\n // The flow knows what it asked for, so a domain with no attachment can still be verified.\n const verification = Verify.useController({\n domain,\n requirements,\n ...(supplied === undefined ? {} : { supplied }),\n });\n const observe = verification.observe;\n const provisioning = Provision.useController({\n domain,\n readOnly: surfaceReadOnly,\n onApplied: useCallback(\n (receipt: Receipt.Model) => {\n refresh();\n // The zone holds records it did not a moment ago, so the flow reads it again rather than\n // waiting for the next poll. Observing also interrupts an observation that overlapped the\n // apply, whose evidence is about the zone as it was before the writes landed.\n observe();\n onApplied?.(receipt);\n },\n [observe, onApplied, refresh],\n ),\n requirements,\n });\n const receiptId = connection.snapshot?.lastReceiptId ?? null;\n const cleanup = Cleanup.useController({\n domain,\n readOnly: surfaceReadOnly,\n ...(onCleaned === undefined ? {} : { onCleaned }),\n ...(receiptId === null ? {} : { receiptId: Receipt.ReceiptId.make(receiptId) }),\n });\n\n // The plan is what the table is: an attached domain with nothing applied to it yet has records\n // that are still a proposal, and the rows say so. An applied domain plans again once an\n // observation reads a record back missing or wrong, so a customer whose records were deleted at\n // the provider is offered them again instead of a count of what once landed. The signature is\n // what makes that one call per reason to make it — the domain, the connection that landed, what\n // the host asked for, the receipt, and which records drifted — rather than one per render or one\n // per poll.\n const attached = connection.snapshot?.attachment != null;\n const drift = driftKey(verification.readiness, connection.receipt, cleanup.state);\n const signature =\n surfaceReadOnly ||\n !capabilities.includes(\"provisioning\") ||\n !attached ||\n (receiptId !== null && drift === null)\n ? null\n : [\n domain,\n connection.established,\n requirementsKey(requirements),\n receiptId ?? \"\",\n drift ?? \"\",\n ].join(\"|\");\n const planned = useRef<string | null>(null);\n const buildPlan = provisioning.plan;\n useEffect(() => {\n // A flow that cannot plan forgets what it planned, so pointing it back at a domain it once\n // planned for builds a plan again rather than leaving that domain with none.\n if (signature === null) {\n planned.current = null;\n return;\n }\n if (planned.current === signature) return;\n planned.current = signature;\n buildPlan();\n }, [buildPlan, signature]);\n\n // The same predicates the surface renders on, so the state a host reads and the surface a\n // customer sees never disagree, including while a disconnect is in flight.\n const connected = Connect.holdsConnection(connection);\n const offering = Connect.offering(connection, connect);\n const provider = connection.snapshot?.provider ?? Connect.hostProvider(connection)?.id ?? null;\n return {\n capabilities,\n cleanup,\n connection,\n domain,\n invitation: connect,\n plan: Provision.pendingPlan(provisioning.state),\n provisioning,\n readiness: verification.readiness,\n requirements,\n state: flowState({\n connected,\n label: connection.snapshot?.attachment?.label ?? null,\n offering,\n planning: provisioning.state._tag,\n provider,\n readOnly: surfaceReadOnly,\n receipt: receiptId,\n status: connection.state._tag,\n }),\n verification,\n };\n}\n","/**\n * What a flow says when a step ends badly: a heading the customer reads first, then what to do\n * about it. Both come from the catalog, chosen by the error's reason, so nothing renders a tag,\n * a status literal, or a reason name.\n *\n * const describe = Outcome.useDescribe();\n * const words = describe(error, { provider: \"Cloudflare\" });\n */\nimport type { DomainKit } from \"domainkit\";\n\nimport { useMessages } from \"./domain-kit.tsx\";\nimport type { Catalog, Outcome, OutcomeContext } from \"./messages.ts\";\nimport { outcome } from \"./messages.ts\";\n\nexport type { Outcome, OutcomeContext };\n\n/** The catalog's title and description for one failure. */\nexport const describe = (\n error: DomainKit.Error,\n catalog: Catalog,\n context: OutcomeContext = {},\n): Outcome => outcome(error, catalog, context);\n\n/**\n * `describe` bound to the catalog `DomainKit.Root` holds. The reason alone cannot name the\n * provider a customer typed a token for, so the surface supplies it in the context.\n */\nexport function useDescribe(): (error: DomainKit.Error, context?: OutcomeContext) => Outcome {\n const messages = useMessages();\n return (error, context = {}) => outcome(error, messages, context);\n}\n","/**\n * The fake transport `@domainkit/react` tests render against: an in-memory `domainkit/server`\n * with memory storage and a fake provider, recording every call.\n */\nimport { Testing } from \"domainkit/testing\";\n\nexport const transport = Testing.transport;\nexport type RecordedCall = Testing.RecordedCall;\nexport type RecordingTransport = Testing.RecordingTransport;\nexport type TransportOptions = Testing.TransportOptions;\n","import type { DomainKit } from \"domainkit\";\nimport * as Data from \"effect/Data\";\n\n/**\n * The failed member every controller state shares. It carries the `DomainKit.Error` itself, so a\n * host reads `error.reason`, `error.category`, and `error.isRetryable` instead of parsing text.\n */\nexport type Failure = Data.TaggedEnum<{\n Failure: { readonly error: DomainKit.Error };\n}>;\nexport const Failure = Data.taggedEnum<Failure>();\n\n/** A defect that escaped the transport, in the shape the rest of the UI already handles. */\nexport const isFailure = (state: { readonly _tag: string }): state is Failure =>\n state._tag === \"Failure\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@domainkit/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Headless React hooks for custom-domain setup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"custom-domains",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"react",
|
|
11
11
|
"typescript"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://
|
|
13
|
+
"homepage": "https://domain-kit.dev",
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/AryaLabsHQ/domainkit/issues"
|
|
16
16
|
},
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"typecheck": "tsc --noEmit"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"domainkit": "^0.
|
|
46
|
+
"domainkit": "^0.20.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@testing-library/react": "16.3.1",
|
|
50
50
|
"@testing-library/user-event": "14.6.1",
|
|
51
51
|
"@types/react": "19.2.14",
|
|
52
52
|
"@types/react-dom": "19.2.3",
|
|
53
|
-
"effect": "4.0.0
|
|
53
|
+
"effect": "4.0.0",
|
|
54
54
|
"jsdom": "26.1.0",
|
|
55
55
|
"react": "19.2.4",
|
|
56
56
|
"react-dom": "19.2.4",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"vitest": "5.0.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"effect": ">=4.0.0
|
|
63
|
+
"effect": ">=4.0.0 <5.0.0",
|
|
64
64
|
"react": ">=19.0.0 <20.0.0",
|
|
65
65
|
"react-dom": ">=19.0.0 <20.0.0"
|
|
66
66
|
},
|