@domainkit/react 0.8.0 → 0.9.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 +128 -36
- package/dist/index.d.mts +1219 -1308
- package/dist/index.mjs +2016 -1614
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1185 -1023
- package/package.json +2 -10
package/dist/index.mjs
CHANGED
|
@@ -1,37 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { RegistryProvider, useAtomSet, useAtomValue } from "@effect/atom-react";
|
|
4
|
-
import { DomainName, Transport } from "domainkit";
|
|
5
|
-
import * as Data from "effect/Data";
|
|
3
|
+
import { DnsRecord, DomainKit, Reason, Receipt } from "domainkit";
|
|
6
4
|
import * as Effect from "effect/Effect";
|
|
7
|
-
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
8
5
|
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import { Transport } from "domainkit/client";
|
|
9
8
|
import { useRender } from "@base-ui/react/use-render";
|
|
10
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import * as Exit from "effect/Exit";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
11
12
|
import { Dialog } from "@base-ui/react/dialog";
|
|
12
|
-
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
13
|
-
import { Menu } from "@base-ui/react/menu";
|
|
14
13
|
import { Popover } from "@base-ui/react/popover";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const failureFromError = (error) => Failure.Failure({
|
|
18
|
-
message: error.message,
|
|
19
|
-
operation: error.operation,
|
|
20
|
-
retry: error.retry
|
|
21
|
-
});
|
|
22
|
-
const failureFromDefect = (operation, message) => Failure.Failure({
|
|
23
|
-
message,
|
|
24
|
-
operation,
|
|
25
|
-
retry: "safe"
|
|
26
|
-
});
|
|
27
|
-
const recordsIdentity = (records) => JSON.stringify(records.map(({ id, name, priority, type, value }) => ({
|
|
28
|
-
id,
|
|
29
|
-
name,
|
|
30
|
-
priority,
|
|
31
|
-
type,
|
|
32
|
-
value
|
|
33
|
-
})));
|
|
34
|
-
//#endregion
|
|
14
|
+
import * as DateTime from "effect/DateTime";
|
|
15
|
+
import { Testing } from "domainkit/testing";
|
|
35
16
|
//#region src/composition.tsx
|
|
36
17
|
function usePart(defaultTagName, componentProps, state, internalProps) {
|
|
37
18
|
const { className, render, style, ...externalProps } = componentProps;
|
|
@@ -45,6 +26,12 @@ function usePart(defaultTagName, componentProps, state, internalProps) {
|
|
|
45
26
|
};
|
|
46
27
|
return useRender(parameters);
|
|
47
28
|
}
|
|
29
|
+
/** A part with no state of its own: one tag, one `data-domainkit-part`, host props on top. */
|
|
30
|
+
function leafPart(defaultTagName, part) {
|
|
31
|
+
return function Leaf(props) {
|
|
32
|
+
return usePart(defaultTagName, props, {}, { "data-domainkit-part": part });
|
|
33
|
+
};
|
|
34
|
+
}
|
|
48
35
|
//#endregion
|
|
49
36
|
//#region src/icons.tsx
|
|
50
37
|
function Glyph({ children }) {
|
|
@@ -60,6 +47,7 @@ function Glyph({ children }) {
|
|
|
60
47
|
});
|
|
61
48
|
}
|
|
62
49
|
const defaultIcons = {
|
|
50
|
+
close: /* @__PURE__ */ jsxs(Glyph, { children: [/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }), /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })] }),
|
|
63
51
|
copied: /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }),
|
|
64
52
|
copy: /* @__PURE__ */ jsxs(Glyph, { children: [/* @__PURE__ */ jsx("rect", {
|
|
65
53
|
height: "14",
|
|
@@ -72,14 +60,37 @@ const defaultIcons = {
|
|
|
72
60
|
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
73
61
|
/* @__PURE__ */ jsx("path", { d: "m7 10 5 5 5-5" }),
|
|
74
62
|
/* @__PURE__ */ jsx("path", { d: "M12 15V3" })
|
|
75
|
-
] })
|
|
63
|
+
] }),
|
|
64
|
+
external: /* @__PURE__ */ jsxs(Glyph, { children: [
|
|
65
|
+
/* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
|
|
66
|
+
/* @__PURE__ */ jsx("path", { d: "M10 14 21 3" }),
|
|
67
|
+
/* @__PURE__ */ jsx("path", { d: "M21 14v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5" })
|
|
68
|
+
] }),
|
|
69
|
+
failure: /* @__PURE__ */ jsxs(Glyph, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx("circle", {
|
|
71
|
+
cx: "12",
|
|
72
|
+
cy: "12",
|
|
73
|
+
r: "9"
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ jsx("path", { d: "M15 9 9 15" }),
|
|
76
|
+
/* @__PURE__ */ jsx("path", { d: "m9 9 6 6" })
|
|
77
|
+
] }),
|
|
78
|
+
pending: /* @__PURE__ */ jsxs(Glyph, { children: [/* @__PURE__ */ jsx("circle", {
|
|
79
|
+
cx: "12",
|
|
80
|
+
cy: "12",
|
|
81
|
+
r: "9"
|
|
82
|
+
}), /* @__PURE__ */ jsx("path", { d: "M12 7v5l3 2" })] }),
|
|
83
|
+
success: /* @__PURE__ */ jsxs(Glyph, { children: [/* @__PURE__ */ jsx("circle", {
|
|
84
|
+
cx: "12",
|
|
85
|
+
cy: "12",
|
|
86
|
+
r: "9"
|
|
87
|
+
}), /* @__PURE__ */ jsx("path", { d: "m8.5 12.5 2.5 2.5 4.5-5" })] })
|
|
76
88
|
};
|
|
77
89
|
const IconsContext = createContext(defaultIcons);
|
|
78
90
|
function IconsProvider({ children, icons }) {
|
|
79
91
|
const value = useMemo(() => ({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
download: icons?.download ?? defaultIcons.download
|
|
92
|
+
...defaultIcons,
|
|
93
|
+
...icons
|
|
83
94
|
}), [icons]);
|
|
84
95
|
return /* @__PURE__ */ jsx(IconsContext.Provider, {
|
|
85
96
|
value,
|
|
@@ -93,54 +104,237 @@ function useIcons() {
|
|
|
93
104
|
//#region src/messages.ts
|
|
94
105
|
var messages_exports = /* @__PURE__ */ __exportAll({
|
|
95
106
|
english: () => english,
|
|
107
|
+
failure: () => failure,
|
|
96
108
|
merge: () => merge
|
|
97
109
|
});
|
|
110
|
+
const entity = {
|
|
111
|
+
approval: "approval",
|
|
112
|
+
attachment: "domain attachment",
|
|
113
|
+
authorization: "provider authorization",
|
|
114
|
+
connection: "provider connection",
|
|
115
|
+
continuation: "sign-in attempt",
|
|
116
|
+
plan: "plan",
|
|
117
|
+
provider: "provider",
|
|
118
|
+
receipt: "receipt",
|
|
119
|
+
record: "DNS record",
|
|
120
|
+
zone: "DNS zone"
|
|
121
|
+
};
|
|
122
|
+
const expiredEntity = {
|
|
123
|
+
approval: "approval",
|
|
124
|
+
continuation: "sign-in attempt",
|
|
125
|
+
credential: "provider credential",
|
|
126
|
+
plan: "plan"
|
|
127
|
+
};
|
|
128
|
+
const recordTypes = {
|
|
129
|
+
A: "A",
|
|
130
|
+
AAAA: "AAAA",
|
|
131
|
+
CAA: "CAA",
|
|
132
|
+
CNAME: "CNAME",
|
|
133
|
+
MX: "MX",
|
|
134
|
+
NS: "NS",
|
|
135
|
+
SRV: "SRV",
|
|
136
|
+
TXT: "TXT"
|
|
137
|
+
};
|
|
138
|
+
/** `accountId` reads as "Account id" until a host names the field itself. */
|
|
139
|
+
const humanize = (name) => {
|
|
140
|
+
const spaced = name.replaceAll(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll(/[_-]+/g, " ").trim();
|
|
141
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
|
|
142
|
+
};
|
|
98
143
|
const english = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
automaticUnavailable: "Automatic connection is not available for this domain",
|
|
144
|
+
connect: "Connect",
|
|
145
|
+
connectWith: (method) => method,
|
|
146
|
+
disconnect: "Disconnect",
|
|
147
|
+
detach: "Detach domain",
|
|
104
148
|
cancel: "Cancel",
|
|
105
|
-
|
|
106
|
-
|
|
149
|
+
close: "Close",
|
|
150
|
+
retry: "Try again",
|
|
151
|
+
approve: "Approve",
|
|
152
|
+
decline: "Decline",
|
|
153
|
+
reviewChanges: "Review changes",
|
|
154
|
+
cleanUp: "Remove records",
|
|
107
155
|
checkDns: "Check DNS",
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
156
|
+
checkAgain: "Check again",
|
|
157
|
+
moreActions: "More actions",
|
|
158
|
+
copy: "Copy",
|
|
159
|
+
copied: "Copied",
|
|
160
|
+
copyZone: "Copy zone file",
|
|
161
|
+
download: "Download",
|
|
162
|
+
useConnection: (label) => `Use ${label}`,
|
|
163
|
+
chooseZone: "Choose the zone that serves this domain",
|
|
164
|
+
getToken: "Where do I find this?",
|
|
165
|
+
loading: "Loading…",
|
|
114
166
|
connecting: "Connecting…",
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
disconnectDomain: "Disconnect",
|
|
118
|
-
disconnectConsent: "This domain will be detached from the provider. Existing DNS records will be preserved.",
|
|
167
|
+
redirecting: "Opening the provider…",
|
|
168
|
+
detaching: "Detaching…",
|
|
119
169
|
disconnecting: "Disconnecting…",
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
dialogTitle: (provider) => `Connect ${provider}`,
|
|
125
|
-
openingAuthorization: "Opening provider authorization…",
|
|
126
|
-
moreActions: "More connection actions",
|
|
127
|
-
noChanges: "No changes needed",
|
|
128
|
-
planConsent: "Review the exact DNS operations before approving this plan.",
|
|
170
|
+
planning: "Preparing DNS changes…",
|
|
171
|
+
approving: "Approving…",
|
|
172
|
+
applying: "Adding records…",
|
|
173
|
+
rejecting: "Declining…",
|
|
129
174
|
planningCleanup: "Preparing cleanup…",
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
175
|
+
cleaning: "Removing records…",
|
|
176
|
+
observing: "Checking DNS…",
|
|
177
|
+
connectTitle: (provider) => `Connect ${provider}`,
|
|
178
|
+
connectAnyTitle: "Connect your DNS provider",
|
|
179
|
+
connectDescription: (domain) => `Authorize DNS changes for ${domain}.`,
|
|
180
|
+
connectedTo: (provider) => `${provider} connected`,
|
|
181
|
+
notConnected: "No DNS provider is connected.",
|
|
182
|
+
reconnectRequired: (provider) => `${provider} needs to be reconnected`,
|
|
183
|
+
disconnectTitle: (provider) => `Disconnect ${provider}?`,
|
|
184
|
+
disconnectConsent: "The provider connection is removed. Existing DNS records are preserved.",
|
|
185
|
+
detachConsent: "This domain is detached from the provider. Existing DNS records are preserved.",
|
|
186
|
+
detached: "Domain detached. DNS records were preserved.",
|
|
187
|
+
reusableConnections: "Connections you already have",
|
|
188
|
+
authenticationAlternative: "or",
|
|
189
|
+
discoveredConnection: (label) => `${label} already serves this domain`,
|
|
190
|
+
discoveryAmbiguous: "More than one connection can serve this domain. Pick one.",
|
|
191
|
+
discoveryNotFound: (nameservers) => nameservers.length === 0 ? "No connected provider serves this domain yet." : `No connected provider serves this domain. Its nameservers are ${nameservers.join(", ")}.`,
|
|
192
|
+
noProviders: "No DNS providers are available.",
|
|
193
|
+
fieldLabel: humanize,
|
|
194
|
+
optionalField: "optional",
|
|
195
|
+
planTitle: "Review DNS changes",
|
|
196
|
+
planConsent: "Review the exact DNS operations before approving this plan.",
|
|
197
|
+
cleanupTitle: "Review the records to remove",
|
|
198
|
+
cleanupConsent: "Only records the apply receipt proves DomainKit created will be deleted.",
|
|
199
|
+
noChanges: "No changes needed",
|
|
200
|
+
planExpires: (at) => `This plan expires at ${at}.`,
|
|
201
|
+
declinedBy: (actor) => `Declined by ${actor}. Build a new plan to continue.`,
|
|
202
|
+
declineReason: (reason) => `Reason: ${reason}`,
|
|
203
|
+
operation: (operation) => {
|
|
204
|
+
switch (operation._tag) {
|
|
205
|
+
case "Create": return "Add";
|
|
206
|
+
case "Noop": return "Already in place";
|
|
207
|
+
case "Delete": return "Remove";
|
|
208
|
+
case "Conflict": return "Blocked";
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
conflictReason: (reason) => {
|
|
212
|
+
switch (reason) {
|
|
213
|
+
case "exclusive-name": return "Another record already owns this name.";
|
|
214
|
+
case "cname-collision": return "A CNAME cannot share a name with other records.";
|
|
215
|
+
case "value-mismatch": return "A record with this name holds a different value.";
|
|
216
|
+
case "opaque": return "A record here uses a form DomainKit will not overwrite.";
|
|
217
|
+
case "missing": return "The record this plan expected is gone.";
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
attemptStatus: (status) => {
|
|
221
|
+
switch (status) {
|
|
222
|
+
case "planned": return "Awaiting review";
|
|
223
|
+
case "approved": return "Approved";
|
|
224
|
+
case "applying": return "Applying";
|
|
225
|
+
case "complete": return "Applied";
|
|
226
|
+
case "partial": return "Partly applied";
|
|
227
|
+
case "failed": return "Failed";
|
|
228
|
+
case "expired": return "Expired";
|
|
229
|
+
case "rejected": return "Declined";
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
recordsCaption: (domain) => `DNS records for ${domain}`,
|
|
233
|
+
headingType: "Type",
|
|
234
|
+
headingName: "Name",
|
|
235
|
+
headingValue: "Value",
|
|
236
|
+
headingStatus: "Status",
|
|
237
|
+
headingPurpose: "Purpose",
|
|
238
|
+
priority: (priority) => `Priority ${priority}`,
|
|
239
|
+
ttl: (seconds) => `TTL ${seconds}s`,
|
|
240
|
+
recordType: (record) => record._tag === "Opaque" ? record.type : recordTypes[record._tag],
|
|
241
|
+
applied: (receipt) => receipt.status === "complete" ? "DNS records added." : "Some DNS records were not added.",
|
|
242
|
+
cleaned: (receipt) => receipt.status === "complete" ? "DNS records removed." : "Some DNS records were not removed.",
|
|
243
|
+
partiallyApplied: "Some DNS changes failed. Review and retry safely.",
|
|
244
|
+
partiallyCleaned: "Some DNS records could not be deleted. Review and retry safely.",
|
|
245
|
+
outcome: (outcome) => {
|
|
246
|
+
switch (outcome._tag) {
|
|
247
|
+
case "Applied": return "Done";
|
|
248
|
+
case "Skipped": return "Skipped";
|
|
249
|
+
case "Failed": return outcome.message;
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
skippedReason: (reason) => {
|
|
253
|
+
switch (reason) {
|
|
254
|
+
case "noop": return "The record was already in place.";
|
|
255
|
+
case "not-approved": return "The approval left this operation out.";
|
|
256
|
+
case "not-attempted": return "An earlier operation failed before this one ran.";
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
requirementStatus: (status) => {
|
|
260
|
+
switch (status) {
|
|
261
|
+
case "satisfied": return "Found";
|
|
262
|
+
case "missing": return "Missing";
|
|
263
|
+
case "mismatch": return "Different value";
|
|
264
|
+
case "unknown": return "Not checked";
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
overall: (overall) => {
|
|
268
|
+
switch (overall) {
|
|
269
|
+
case "ready": return "Ready";
|
|
270
|
+
case "pending": return "Pending";
|
|
271
|
+
case "failed": return "Failed";
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
evidenceSource: (evidence) => {
|
|
275
|
+
switch (evidence._tag) {
|
|
276
|
+
case "Host": return evidence.label;
|
|
277
|
+
case "Provider": return `${evidence.provider} records`;
|
|
278
|
+
case "PublicDns": return `Public DNS via ${evidence.resolver}`;
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
hostEvidenceStatus: (status) => {
|
|
282
|
+
switch (status) {
|
|
283
|
+
case "ok": return "Ready";
|
|
284
|
+
case "pending": return "Pending";
|
|
285
|
+
case "failed": return "Failed";
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
expectedValue: (value) => `Expected ${value}`,
|
|
289
|
+
observedValues: (values) => `Found ${values.join(", ")}`,
|
|
290
|
+
observedNothing: "Found nothing",
|
|
291
|
+
checkedAt: (at) => `Checked ${at}`,
|
|
292
|
+
nextCheckAt: (at) => `Next check ${at}`,
|
|
293
|
+
hostEvidence: "Other checks",
|
|
294
|
+
noEvidence: "Nothing has been checked yet.",
|
|
295
|
+
invalidInput: (reason) => reason.field === void 0 ? reason.message : `${humanize(reason.field)}: ${reason.message}`,
|
|
296
|
+
unauthenticated: () => "The provider rejected these credentials.",
|
|
297
|
+
forbidden: () => "You do not have access to this domain.",
|
|
298
|
+
notFound: (reason) => `That ${entity[reason.entity]} no longer exists.`,
|
|
299
|
+
conflict: (reason) => reason.operations.length === 1 ? "One DNS record conflicts with what is already in the zone." : `${reason.operations.length} DNS records conflict with what is already in the zone.`,
|
|
300
|
+
stale: () => "The zone changed while you were reviewing. Build a new plan.",
|
|
301
|
+
expired: (reason) => `That ${expiredEntity[reason.entity]} expired. Start again.`,
|
|
302
|
+
busy: () => "Another change is running. Try again in a moment.",
|
|
303
|
+
providerRejected: (reason) => `${reason.provider} refused the change: ${reason.message}`,
|
|
304
|
+
providerUnavailable: (reason) => `${reason.provider} is unreachable right now.`,
|
|
305
|
+
providerConflict: (reason) => `${reason.provider} already holds a conflicting record.`,
|
|
306
|
+
unsupported: (reason) => `${reason.provider} cannot ${reason.operation}.`,
|
|
307
|
+
reconnect: (reason) => `Reconnect ${reason.provider} to continue.`,
|
|
308
|
+
storageFailed: () => "The change could not be saved. Try again.",
|
|
309
|
+
cryptoFailed: () => "A stored credential could not be read.",
|
|
310
|
+
resolverFailed: (reason) => `DNS lookups through ${reason.resolver} failed.`
|
|
139
311
|
};
|
|
140
312
|
const merge = (overrides = {}) => ({
|
|
141
313
|
...english,
|
|
142
314
|
...overrides
|
|
143
315
|
});
|
|
316
|
+
/** The user-facing sentence for a failure, chosen by the error's reason. */
|
|
317
|
+
const failure = (error, catalog) => {
|
|
318
|
+
const reason = error.reason;
|
|
319
|
+
switch (reason._tag) {
|
|
320
|
+
case "InvalidInput": return catalog.invalidInput(reason);
|
|
321
|
+
case "Unauthenticated": return catalog.unauthenticated(reason);
|
|
322
|
+
case "Forbidden": return catalog.forbidden(reason);
|
|
323
|
+
case "NotFound": return catalog.notFound(reason);
|
|
324
|
+
case "Conflict": return catalog.conflict(reason);
|
|
325
|
+
case "Stale": return catalog.stale(reason);
|
|
326
|
+
case "Expired": return catalog.expired(reason);
|
|
327
|
+
case "Busy": return catalog.busy(reason);
|
|
328
|
+
case "ProviderRejected": return catalog.providerRejected(reason);
|
|
329
|
+
case "ProviderUnavailable": return catalog.providerUnavailable(reason);
|
|
330
|
+
case "ProviderConflict": return catalog.providerConflict(reason);
|
|
331
|
+
case "Unsupported": return catalog.unsupported(reason);
|
|
332
|
+
case "Reconnect": return catalog.reconnect(reason);
|
|
333
|
+
case "StorageFailed": return catalog.storageFailed(reason);
|
|
334
|
+
case "CryptoFailed": return catalog.cryptoFailed(reason);
|
|
335
|
+
case "ResolverFailed": return catalog.resolverFailed(reason);
|
|
336
|
+
}
|
|
337
|
+
};
|
|
144
338
|
//#endregion
|
|
145
339
|
//#region src/theme.ts
|
|
146
340
|
var theme_exports = /* @__PURE__ */ __exportAll({ toStyle: () => toStyle });
|
|
@@ -166,14 +360,45 @@ function toStyle(theme = {}) {
|
|
|
166
360
|
//#endregion
|
|
167
361
|
//#region src/domain-kit.tsx
|
|
168
362
|
var domain_kit_exports = /* @__PURE__ */ __exportAll({
|
|
363
|
+
ReadOnly: () => ReadOnly,
|
|
169
364
|
Root: () => Root$6,
|
|
170
|
-
|
|
365
|
+
useCapabilities: () => useCapabilities,
|
|
366
|
+
useDomainKit: () => useDomainKit,
|
|
367
|
+
useReadOnly: () => useReadOnly,
|
|
368
|
+
useTransport: () => useTransport
|
|
171
369
|
});
|
|
172
370
|
const Context = createContext(null);
|
|
173
371
|
const navigateInBrowser = (url) => {
|
|
174
|
-
if (typeof window === "undefined") throw new Error("DomainKit
|
|
372
|
+
if (typeof window === "undefined") throw new Error("DomainKit provider authorization requires a browser or a `navigate` prop");
|
|
175
373
|
window.location.assign(url);
|
|
176
374
|
};
|
|
375
|
+
/**
|
|
376
|
+
* A transport whose identity survives re-renders. Each method reads the newest transport when it
|
|
377
|
+
* runs, so a host may write `<DomainKit.Root transport={Transport.fromFetch("/api/domainkit")}>`
|
|
378
|
+
* inline and controllers still see one transport for the whole mount. Swapping in a transport
|
|
379
|
+
* that declares different capability groups rebuilds it, and every controller re-runs.
|
|
380
|
+
*/
|
|
381
|
+
const useStableTransport = (transport) => {
|
|
382
|
+
const latest = useRef(transport);
|
|
383
|
+
useLayoutEffect(() => {
|
|
384
|
+
latest.current = transport;
|
|
385
|
+
});
|
|
386
|
+
const signature = Transport.capabilities(transport).join(",");
|
|
387
|
+
return useMemo(() => {
|
|
388
|
+
const capabilities = Transport.capabilities(latest.current);
|
|
389
|
+
return {
|
|
390
|
+
capabilities,
|
|
391
|
+
transport: Object.fromEntries(capabilities.map((capability) => {
|
|
392
|
+
const group = latest.current[capability];
|
|
393
|
+
return [capability, Object.fromEntries(Object.keys(group).map((name) => [name, (...args) => Effect.suspend(() => {
|
|
394
|
+
const method = latest.current[capability][name];
|
|
395
|
+
if (method === void 0) throw new Error(`The transport no longer declares ${capability}.${name}`);
|
|
396
|
+
return method(...args);
|
|
397
|
+
})]))];
|
|
398
|
+
}))
|
|
399
|
+
};
|
|
400
|
+
}, [signature]);
|
|
401
|
+
};
|
|
177
402
|
const resolvePortalContainer = (container, ownerDocument) => {
|
|
178
403
|
if (container === null || ownerDocument === null) return null;
|
|
179
404
|
return container.ownerDocument === ownerDocument && container.getRootNode() === ownerDocument ? container : null;
|
|
@@ -192,8 +417,8 @@ const usePortalContainer = (container) => {
|
|
|
192
417
|
const getSnapshot = useCallback(() => resolvePortalContainer(container, ownerDocument), [container, ownerDocument]);
|
|
193
418
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
194
419
|
};
|
|
195
|
-
function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages, navigate = navigateInBrowser, onEvent, portalContainer = null, theme, transport, ...props }) {
|
|
196
|
-
const
|
|
420
|
+
function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages, navigate = navigateInBrowser, onEvent, portalContainer = null, readOnly = false, revision = 0, theme, transport, ...props }) {
|
|
421
|
+
const { capabilities, transport: stable } = useStableTransport(transport);
|
|
197
422
|
const onEventRef = useRef(onEvent);
|
|
198
423
|
useLayoutEffect(() => {
|
|
199
424
|
onEventRef.current = onEvent;
|
|
@@ -206,844 +431,340 @@ function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages
|
|
|
206
431
|
const themeStyle = toStyle(theme);
|
|
207
432
|
const resolvedPortalContainer = usePortalContainer(portalContainer);
|
|
208
433
|
const portalContainerRef = useMemo(() => ({ current: resolvedPortalContainer }), [resolvedPortalContainer]);
|
|
434
|
+
const value = {
|
|
435
|
+
capabilities,
|
|
436
|
+
colorScheme,
|
|
437
|
+
emit,
|
|
438
|
+
marks,
|
|
439
|
+
messages: merge(messages),
|
|
440
|
+
navigate,
|
|
441
|
+
portalContainer: portalContainerRef,
|
|
442
|
+
readOnly,
|
|
443
|
+
revision,
|
|
444
|
+
themeStyle,
|
|
445
|
+
transport: stable
|
|
446
|
+
};
|
|
209
447
|
const content = usePart("div", props, { colorScheme }, {
|
|
210
448
|
children,
|
|
211
449
|
"data-color-scheme": colorScheme,
|
|
212
450
|
"data-domainkit-root": "",
|
|
213
451
|
style: themeStyle
|
|
214
452
|
});
|
|
215
|
-
return /* @__PURE__ */ jsx(
|
|
216
|
-
value
|
|
217
|
-
colorScheme,
|
|
218
|
-
emit,
|
|
219
|
-
marks,
|
|
220
|
-
messages: merge(messages),
|
|
221
|
-
navigate,
|
|
222
|
-
portalContainer: portalContainerRef,
|
|
223
|
-
runtime,
|
|
224
|
-
themeStyle
|
|
225
|
-
},
|
|
453
|
+
return /* @__PURE__ */ jsx(Context.Provider, {
|
|
454
|
+
value,
|
|
226
455
|
children: /* @__PURE__ */ jsx(IconsProvider, {
|
|
227
456
|
...icons === void 0 ? {} : { icons },
|
|
228
457
|
children: content
|
|
229
458
|
})
|
|
230
|
-
})
|
|
459
|
+
});
|
|
231
460
|
}
|
|
232
461
|
function useDomainKit() {
|
|
233
462
|
const value = useContext(Context);
|
|
234
463
|
if (value === null) throw new Error("DomainKit components must be rendered inside DomainKit.Root");
|
|
235
464
|
return value;
|
|
236
465
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const Event = Data.taggedEnum();
|
|
241
|
-
//#endregion
|
|
242
|
-
//#region src/operations.tsx
|
|
243
|
-
var operations_exports = /* @__PURE__ */ __exportAll({
|
|
244
|
-
Item: () => Item,
|
|
245
|
-
Kind: () => Kind,
|
|
246
|
-
List: () => List,
|
|
247
|
-
Name: () => Name,
|
|
248
|
-
Priority: () => Priority$1,
|
|
249
|
-
Reason: () => Reason,
|
|
250
|
-
Record: () => Record,
|
|
251
|
-
Root: () => Root$5,
|
|
252
|
-
Type: () => Type,
|
|
253
|
-
Value: () => Value$1
|
|
254
|
-
});
|
|
255
|
-
function leafPart$1(defaultTagName, part) {
|
|
256
|
-
return function Leaf(props) {
|
|
257
|
-
return usePart(defaultTagName, props, {}, { "data-domainkit-part": part });
|
|
258
|
-
};
|
|
466
|
+
/** The transport `DomainKit.Root` holds, with the identity it keeps for the whole mount. */
|
|
467
|
+
function useTransport() {
|
|
468
|
+
return useDomainKit().transport;
|
|
259
469
|
}
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const Reason = leafPart$1("span", "operation-reason");
|
|
267
|
-
function Item({ operation, ...props }) {
|
|
268
|
-
return usePart("li", props, { operation: operation._tag }, {
|
|
269
|
-
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
270
|
-
/* @__PURE__ */ jsx(Kind, { children: operation._tag }),
|
|
271
|
-
" ",
|
|
272
|
-
/* @__PURE__ */ jsx(Type, { children: operation.record.type }),
|
|
273
|
-
" ",
|
|
274
|
-
/* @__PURE__ */ jsxs(Record, { children: [
|
|
275
|
-
/* @__PURE__ */ jsx(Name, { children: operation.record.name }),
|
|
276
|
-
/* @__PURE__ */ jsx(Value$1, { children: operation.record.value }),
|
|
277
|
-
operation.record.priority === void 0 ? null : /* @__PURE__ */ jsxs(Priority$1, { children: ["Priority ", operation.record.priority] }),
|
|
278
|
-
"reason" in operation ? /* @__PURE__ */ jsx(Reason, { children: operation.reason }) : null
|
|
279
|
-
] })
|
|
280
|
-
] }),
|
|
281
|
-
"data-domainkit-part": "operation-item",
|
|
282
|
-
"data-operation": operation._tag
|
|
470
|
+
const ReadOnlyContext = createContext(null);
|
|
471
|
+
/** Narrow one subtree to read-only without touching the rest of the page. */
|
|
472
|
+
function ReadOnly({ children, value }) {
|
|
473
|
+
return /* @__PURE__ */ jsx(ReadOnlyContext.Provider, {
|
|
474
|
+
value,
|
|
475
|
+
children
|
|
283
476
|
});
|
|
284
477
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
"data-domainkit-part": lifecycle === "provisioning" ? "plan-operations" : "cleanup-operations",
|
|
291
|
-
"data-lifecycle": lifecycle
|
|
292
|
-
});
|
|
478
|
+
/** Whether this part may offer controls that change the domain. */
|
|
479
|
+
function useReadOnly() {
|
|
480
|
+
const scoped = useContext(ReadOnlyContext);
|
|
481
|
+
const root = useDomainKit().readOnly;
|
|
482
|
+
return scoped ?? root;
|
|
293
483
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
lifecycle,
|
|
298
|
-
...props,
|
|
299
|
-
children: operations.map((operation) => /* @__PURE__ */ jsx(Item, { operation }, operation.id))
|
|
300
|
-
});
|
|
484
|
+
/** Which capability groups the host's transport declares, for gating a custom part. */
|
|
485
|
+
function useCapabilities() {
|
|
486
|
+
return useDomainKit().capabilities;
|
|
301
487
|
}
|
|
302
488
|
//#endregion
|
|
303
|
-
//#region src/
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const
|
|
319
|
-
|
|
489
|
+
//#region src/events.ts
|
|
490
|
+
const Event = Data.taggedEnum();
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region src/task.ts
|
|
493
|
+
/**
|
|
494
|
+
* The one place the package leaves Effect. Every controller runs its transport calls through
|
|
495
|
+
* `useRunner`, which interrupts the call in flight when a newer one starts or the component
|
|
496
|
+
* unmounts, and drops results that arrive after either.
|
|
497
|
+
*/
|
|
498
|
+
/** A defect is not a lifecycle failure; report it in the shape the UI already renders. */
|
|
499
|
+
const defect = (cause) => new DomainKit.Error({ reason: new Reason.ProviderUnavailable({
|
|
500
|
+
provider: "domainkit",
|
|
501
|
+
message: `The transport failed: ${String(cause)}`
|
|
502
|
+
}) });
|
|
503
|
+
function useRunner() {
|
|
504
|
+
const state = useRef({
|
|
505
|
+
live: null,
|
|
506
|
+
mounted: true,
|
|
507
|
+
next: 0
|
|
508
|
+
});
|
|
509
|
+
useEffect(() => {
|
|
510
|
+
const current = state.current;
|
|
511
|
+
current.mounted = true;
|
|
512
|
+
return () => {
|
|
513
|
+
current.mounted = false;
|
|
514
|
+
current.live?.interrupt?.();
|
|
515
|
+
current.live = null;
|
|
516
|
+
};
|
|
517
|
+
}, []);
|
|
320
518
|
return useMemo(() => {
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const current = get(state);
|
|
325
|
-
if (command._tag === "Dismiss") {
|
|
326
|
-
if (current._tag === "Planning" || current._tag === "Cleaning") return Effect.void;
|
|
327
|
-
get.set(state, State$3.Idle());
|
|
328
|
-
return Effect.void;
|
|
329
|
-
}
|
|
330
|
-
if (command._tag === "Plan") {
|
|
331
|
-
if (current._tag === "Planning" || current._tag === "Cleaning") return Effect.void;
|
|
332
|
-
get.set(state, State$3.Planning());
|
|
333
|
-
return Effect.flatMap(Transport.Service, (transport) => transport.cleanup.plan({
|
|
334
|
-
attachmentId: connection.attachment.id,
|
|
335
|
-
domain: connection.attachment.domain,
|
|
336
|
-
receiptId
|
|
337
|
-
})).pipe(Effect.tap((plan) => Effect.sync(() => get.set(state, State$3.Review({ plan })))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
|
|
338
|
-
}
|
|
339
|
-
if (current._tag !== "Review" || current.plan.operations.some((operation) => operation._tag === "Blocked")) return Effect.void;
|
|
340
|
-
const plan = current.plan;
|
|
341
|
-
get.set(state, State$3.Cleaning({ plan }));
|
|
342
|
-
return Effect.flatMap(Transport.Service, (transport) => transport.cleanup.apply({
|
|
343
|
-
attachmentId: connection.attachment.id,
|
|
344
|
-
domain: connection.attachment.domain,
|
|
345
|
-
planDigest: plan.digest,
|
|
346
|
-
receiptId
|
|
347
|
-
})).pipe(Effect.tap((result) => Effect.sync(() => {
|
|
348
|
-
if (result._tag === "Cleaned") {
|
|
349
|
-
get.set(state, State$3.Cleaned({ result }));
|
|
350
|
-
onCleanedRef.current?.(result);
|
|
351
|
-
emit(Event.RecordsCleaned({
|
|
352
|
-
connection,
|
|
353
|
-
result
|
|
354
|
-
}));
|
|
355
|
-
} else if (result._tag === "Partial") {
|
|
356
|
-
get.set(state, State$3.Partial({ result }));
|
|
357
|
-
onCleanedRef.current?.(result);
|
|
358
|
-
emit(Event.RecordsPartiallyCleaned({
|
|
359
|
-
connection,
|
|
360
|
-
result
|
|
361
|
-
}));
|
|
362
|
-
} else get.set(state, result);
|
|
363
|
-
})), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
|
|
364
|
-
}),
|
|
365
|
-
state
|
|
519
|
+
const stop = () => {
|
|
520
|
+
state.current.live?.interrupt?.();
|
|
521
|
+
state.current.live = null;
|
|
366
522
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"data-domainkit-part": "cleanup-flow",
|
|
390
|
-
"data-state": status
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
function Outcome$2({ state }) {
|
|
394
|
-
const { messages } = useDomainKit();
|
|
395
|
-
if (state._tag === "Partial" || state._tag === "Failure" || state._tag === "Stale") return /* @__PURE__ */ jsx("p", {
|
|
396
|
-
"data-domainkit-part": "flow-outcome",
|
|
397
|
-
"data-tone": "danger",
|
|
398
|
-
role: "alert",
|
|
399
|
-
children: state._tag === "Partial" ? messages.cleanupPartial : state.message
|
|
400
|
-
});
|
|
401
|
-
return null;
|
|
402
|
-
}
|
|
403
|
-
function Dialog$3({ controller, onOpenChange, onOpenChangeComplete, trigger }) {
|
|
404
|
-
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
405
|
-
const state = controller.state;
|
|
406
|
-
const planRef = useRef(void 0);
|
|
407
|
-
if (state._tag === "Idle") planRef.current = void 0;
|
|
408
|
-
if (state._tag === "Review" || state._tag === "Cleaning") planRef.current = state.plan;
|
|
409
|
-
const plan = planRef.current;
|
|
410
|
-
const busy = state._tag === "Planning" || state._tag === "Cleaning";
|
|
411
|
-
const open = state._tag !== "Idle" && state._tag !== "Cleaned";
|
|
412
|
-
return /* @__PURE__ */ jsxs(AlertDialog.Root, {
|
|
413
|
-
onOpenChange: (nextOpen, eventDetails) => {
|
|
414
|
-
if (!nextOpen && busy) {
|
|
415
|
-
eventDetails.cancel();
|
|
416
|
-
return;
|
|
523
|
+
return {
|
|
524
|
+
cancel: stop,
|
|
525
|
+
run: (effect, handlers) => {
|
|
526
|
+
stop();
|
|
527
|
+
const live = {
|
|
528
|
+
id: state.current.next += 1,
|
|
529
|
+
interrupt: null
|
|
530
|
+
};
|
|
531
|
+
state.current.live = live;
|
|
532
|
+
const interrupt = Effect.runCallback(effect, { onExit: (exit) => {
|
|
533
|
+
if (state.current.live?.id !== live.id || !state.current.mounted) return;
|
|
534
|
+
state.current.live = null;
|
|
535
|
+
if (Exit.isSuccess(exit)) {
|
|
536
|
+
handlers.onSuccess(exit.value);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const cause = exit.cause;
|
|
540
|
+
const error = Exit.findErrorOption(exit);
|
|
541
|
+
if (Exit.hasInterrupts(exit)) return;
|
|
542
|
+
handlers.onFailure(Option.isSome(error) ? error.value : defect(cause));
|
|
543
|
+
} });
|
|
544
|
+
if (state.current.live?.id === live.id) live.interrupt = () => interrupt();
|
|
417
545
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
},
|
|
421
|
-
onOpenChangeComplete,
|
|
422
|
-
open,
|
|
423
|
-
children: [trigger === null ? null : /* @__PURE__ */ jsx(AlertDialog.Trigger, {
|
|
424
|
-
"data-domainkit-part": "cleanup-trigger",
|
|
425
|
-
disabled: state._tag !== "Idle",
|
|
426
|
-
onClick: () => controller.plan(),
|
|
427
|
-
...trigger === void 0 ? {} : { render: trigger },
|
|
428
|
-
children: messages.reviewCleanup
|
|
429
|
-
}), /* @__PURE__ */ jsxs(AlertDialog.Portal, {
|
|
430
|
-
container: portalContainer,
|
|
431
|
-
children: [/* @__PURE__ */ jsx(AlertDialog.Backdrop, {
|
|
432
|
-
"data-color-scheme": colorScheme,
|
|
433
|
-
"data-domainkit-part": "dialog-backdrop",
|
|
434
|
-
"data-domainkit-root": "",
|
|
435
|
-
style: themeStyle
|
|
436
|
-
}), /* @__PURE__ */ jsxs(AlertDialog.Popup, {
|
|
437
|
-
"data-color-scheme": colorScheme,
|
|
438
|
-
"data-domainkit-part": "cleanup-dialog",
|
|
439
|
-
"data-domainkit-root": "",
|
|
440
|
-
style: themeStyle,
|
|
441
|
-
children: [
|
|
442
|
-
/* @__PURE__ */ jsxs("div", {
|
|
443
|
-
"data-domainkit-part": "dialog-header",
|
|
444
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
445
|
-
"data-domainkit-part": "dialog-heading",
|
|
446
|
-
children: [/* @__PURE__ */ jsx(AlertDialog.Title, {
|
|
447
|
-
"data-domainkit-part": "dialog-title",
|
|
448
|
-
children: messages.reviewCleanup
|
|
449
|
-
}), /* @__PURE__ */ jsx(AlertDialog.Description, {
|
|
450
|
-
"data-domainkit-part": "dialog-description",
|
|
451
|
-
children: messages.cleanupConsent
|
|
452
|
-
})]
|
|
453
|
-
}), busy ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
|
|
454
|
-
"aria-label": messages.close,
|
|
455
|
-
"data-domainkit-part": "dialog-close",
|
|
456
|
-
children: "×"
|
|
457
|
-
})]
|
|
458
|
-
}),
|
|
459
|
-
/* @__PURE__ */ jsxs("div", {
|
|
460
|
-
"data-domainkit-part": "dialog-body",
|
|
461
|
-
children: [plan === void 0 ? /* @__PURE__ */ jsx("p", {
|
|
462
|
-
"data-domainkit-part": "dialog-progress",
|
|
463
|
-
role: "status",
|
|
464
|
-
children: messages.planningCleanup
|
|
465
|
-
}) : /* @__PURE__ */ jsx(List, {
|
|
466
|
-
lifecycle: "cleanup",
|
|
467
|
-
operations: plan.operations
|
|
468
|
-
}), /* @__PURE__ */ jsx(Outcome$2, { state })]
|
|
469
|
-
}),
|
|
470
|
-
/* @__PURE__ */ jsx("div", {
|
|
471
|
-
"data-domainkit-part": "dialog-footer",
|
|
472
|
-
children: busy ? /* @__PURE__ */ jsx("button", {
|
|
473
|
-
"data-domainkit-part": "cleanup-apply",
|
|
474
|
-
disabled: true,
|
|
475
|
-
type: "button",
|
|
476
|
-
children: state._tag === "Cleaning" ? messages.cleaningDns : messages.planningCleanup
|
|
477
|
-
}) : state._tag === "Review" && plan !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertDialog.Close, {
|
|
478
|
-
"data-domainkit-part": "dialog-cancel",
|
|
479
|
-
children: messages.cancel
|
|
480
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
481
|
-
"data-domainkit-part": "cleanup-apply",
|
|
482
|
-
disabled: plan.operations.some((operation) => operation._tag === "Blocked"),
|
|
483
|
-
onClick: () => controller.apply(),
|
|
484
|
-
type: "button",
|
|
485
|
-
children: messages.applyCleanup
|
|
486
|
-
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertDialog.Close, {
|
|
487
|
-
"data-domainkit-part": "dialog-cancel",
|
|
488
|
-
children: messages.close
|
|
489
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
490
|
-
"data-domainkit-part": "cleanup-retry",
|
|
491
|
-
onClick: () => controller.retry(),
|
|
492
|
-
type: "button",
|
|
493
|
-
children: messages.retry
|
|
494
|
-
})] })
|
|
495
|
-
})
|
|
496
|
-
]
|
|
497
|
-
})]
|
|
498
|
-
})]
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
function Flow$3({ connection, onCleaned, receiptId, trigger, ...props }) {
|
|
502
|
-
const controller = useController$3(connection, receiptId, onCleaned);
|
|
503
|
-
const state = controller.state;
|
|
504
|
-
return /* @__PURE__ */ jsx(Root$4, {
|
|
505
|
-
status: state._tag,
|
|
506
|
-
...props,
|
|
507
|
-
children: /* @__PURE__ */ jsx(Dialog$3, {
|
|
508
|
-
controller,
|
|
509
|
-
...trigger === void 0 ? {} : { trigger }
|
|
510
|
-
})
|
|
511
|
-
});
|
|
546
|
+
};
|
|
547
|
+
}, []);
|
|
512
548
|
}
|
|
513
549
|
//#endregion
|
|
514
|
-
//#region src/
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
googlecloud: "cloud.google.com",
|
|
529
|
-
googleclouddns: "cloud.google.com",
|
|
530
|
-
hostgator: "hostgator.com",
|
|
531
|
-
hostinger: "hostinger.com",
|
|
532
|
-
hover: "hover.com",
|
|
533
|
-
ionos: "ionos.com",
|
|
534
|
-
namecheap: "namecheap.com",
|
|
535
|
-
namecom: "name.com",
|
|
536
|
-
netlify: "netlify.com",
|
|
537
|
-
ns1: "ns1.com",
|
|
538
|
-
ovh: "ovh.com",
|
|
539
|
-
porkbun: "porkbun.com",
|
|
540
|
-
route53: "route53.com",
|
|
541
|
-
spaceship: "spaceship.com",
|
|
542
|
-
squarespace: "squarespace.com",
|
|
543
|
-
vercel: "vercel.com"
|
|
544
|
-
};
|
|
545
|
-
const logoKey = (providerId) => providerId.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
546
|
-
const logoHost = (providerId) => logoHosts[logoKey(providerId)];
|
|
547
|
-
const letterMark = (provider) => provider.name.trim().charAt(0).toUpperCase() || "?";
|
|
548
|
-
function DefaultMark({ provider }) {
|
|
549
|
-
const host = logoHost(provider.id);
|
|
550
|
-
const [failed, setFailed] = useState(false);
|
|
551
|
-
if (host === void 0 || failed) return letterMark(provider);
|
|
552
|
-
return /* @__PURE__ */ jsx("img", {
|
|
553
|
-
alt: "",
|
|
554
|
-
height: 32,
|
|
555
|
-
onError: () => setFailed(true),
|
|
556
|
-
referrerPolicy: "no-referrer",
|
|
557
|
-
src: `https://integrations.sh/logo/${host}?sz=64`,
|
|
558
|
-
width: 32
|
|
550
|
+
//#region src/attempt.ts
|
|
551
|
+
const State$2 = Data.taggedEnum();
|
|
552
|
+
/** Reasons that mean the plan itself is gone: retrying the same step would fail the same way. */
|
|
553
|
+
const needsNewPlan = (error) => error.reason._tag === "Stale" || error.reason._tag === "Expired" || error.reason._tag === "Conflict";
|
|
554
|
+
function useAttempt(options) {
|
|
555
|
+
const { domain, done, group, key, onDone } = options;
|
|
556
|
+
const { emit } = useDomainKit();
|
|
557
|
+
const readOnly = useReadOnly();
|
|
558
|
+
const runner = useRunner();
|
|
559
|
+
const [state, setState] = useState(State$2.Idle());
|
|
560
|
+
const held = useRef({
|
|
561
|
+
approval: null,
|
|
562
|
+
key,
|
|
563
|
+
plan: null
|
|
559
564
|
});
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
const content = typeof replacement === "function" ? replacement(provider) : replacement ?? /* @__PURE__ */ jsx(DefaultMark, { provider }, provider.id);
|
|
565
|
-
return usePart("span", props, { providerId: provider.id }, {
|
|
566
|
-
"aria-label": provider.name,
|
|
567
|
-
children: content,
|
|
568
|
-
"data-domainkit-part": "provider-mark",
|
|
569
|
-
"data-domainkit-provider": logoKey(provider.id),
|
|
570
|
-
role: "img"
|
|
565
|
+
const lastCommand = useRef(null);
|
|
566
|
+
const build = useRef(options.plan);
|
|
567
|
+
useEffect(() => {
|
|
568
|
+
build.current = options.plan;
|
|
571
569
|
});
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
const inspection = get(inspect);
|
|
609
|
-
return AsyncResult.matchWithError(inspection, {
|
|
610
|
-
onDefect: () => failureFromDefect("connection.inspect", "Provider detection failed"),
|
|
611
|
-
onError: failureFromError,
|
|
612
|
-
onInitial: () => State$2.Loading(),
|
|
613
|
-
onSuccess: ({ value }) => value
|
|
570
|
+
const [current, setCurrent] = useState(key);
|
|
571
|
+
if (current !== key) {
|
|
572
|
+
setCurrent(key);
|
|
573
|
+
runner.cancel();
|
|
574
|
+
held.current = {
|
|
575
|
+
approval: null,
|
|
576
|
+
key,
|
|
577
|
+
plan: null
|
|
578
|
+
};
|
|
579
|
+
lastCommand.current = null;
|
|
580
|
+
setState(State$2.Idle());
|
|
581
|
+
}
|
|
582
|
+
const onFailure = useCallback((error) => {
|
|
583
|
+
setState(State$2.Failure({ error }));
|
|
584
|
+
emit(Event.Failed({
|
|
585
|
+
domain,
|
|
586
|
+
error
|
|
587
|
+
}));
|
|
588
|
+
}, [domain, emit]);
|
|
589
|
+
const applyWith = useCallback((plan, approval) => {
|
|
590
|
+
if (group === void 0 || held.current.key !== key) return;
|
|
591
|
+
const command = () => {
|
|
592
|
+
setState(State$2.Applying({
|
|
593
|
+
approval,
|
|
594
|
+
plan
|
|
595
|
+
}));
|
|
596
|
+
runner.run(group.apply(approval.id), {
|
|
597
|
+
onFailure,
|
|
598
|
+
onSuccess: (receipt) => {
|
|
599
|
+
setState(State$2.Applied({
|
|
600
|
+
plan,
|
|
601
|
+
receipt
|
|
602
|
+
}));
|
|
603
|
+
emit(done(receipt));
|
|
604
|
+
onDone?.(receipt);
|
|
605
|
+
}
|
|
614
606
|
});
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
607
|
+
};
|
|
608
|
+
lastCommand.current = {
|
|
609
|
+
key,
|
|
610
|
+
run: command
|
|
611
|
+
};
|
|
612
|
+
command();
|
|
613
|
+
}, [
|
|
614
|
+
done,
|
|
615
|
+
emit,
|
|
616
|
+
group,
|
|
617
|
+
key,
|
|
618
|
+
onDone,
|
|
619
|
+
onFailure,
|
|
620
|
+
runner
|
|
621
|
+
]);
|
|
622
|
+
const buildPlan = useCallback(() => {
|
|
623
|
+
const effect = build.current();
|
|
624
|
+
if (effect === null) return;
|
|
625
|
+
const command = () => {
|
|
626
|
+
setState(State$2.Planning());
|
|
627
|
+
runner.run(effect, {
|
|
628
|
+
onFailure,
|
|
629
|
+
onSuccess: (plan) => {
|
|
630
|
+
if (held.current.key !== key) return;
|
|
631
|
+
held.current = {
|
|
632
|
+
approval: null,
|
|
633
|
+
key,
|
|
634
|
+
plan
|
|
635
|
+
};
|
|
636
|
+
setState(State$2.Planned({ plan }));
|
|
622
637
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
lastCommand.current = {
|
|
641
|
+
key,
|
|
642
|
+
run: command
|
|
643
|
+
};
|
|
644
|
+
command();
|
|
645
|
+
}, [
|
|
646
|
+
key,
|
|
647
|
+
onFailure,
|
|
648
|
+
runner
|
|
649
|
+
]);
|
|
650
|
+
const approve = useCallback((operationIds) => {
|
|
651
|
+
const plan = held.current.plan;
|
|
652
|
+
if (group === void 0 || plan === null || held.current.key !== key) return;
|
|
653
|
+
const command = () => {
|
|
654
|
+
setState(State$2.Approving({ plan }));
|
|
655
|
+
runner.run(group.approve({
|
|
656
|
+
planId: plan.id,
|
|
657
|
+
...operationIds === void 0 ? {} : { operationIds }
|
|
658
|
+
}), {
|
|
659
|
+
onFailure,
|
|
660
|
+
onSuccess: (approval) => {
|
|
661
|
+
if (held.current.key !== key) return;
|
|
662
|
+
held.current = {
|
|
663
|
+
approval,
|
|
664
|
+
key,
|
|
665
|
+
plan
|
|
666
|
+
};
|
|
667
|
+
applyWith(plan, approval);
|
|
644
668
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
lastCommand.current = {
|
|
672
|
+
key,
|
|
673
|
+
run: command
|
|
674
|
+
};
|
|
675
|
+
command();
|
|
676
|
+
}, [
|
|
677
|
+
applyWith,
|
|
678
|
+
group,
|
|
679
|
+
key,
|
|
680
|
+
onFailure,
|
|
681
|
+
runner
|
|
682
|
+
]);
|
|
683
|
+
const reject = useCallback((reason) => {
|
|
684
|
+
const plan = held.current.plan;
|
|
685
|
+
if (group === void 0 || plan === null || held.current.key !== key) return;
|
|
686
|
+
const command = () => {
|
|
687
|
+
setState(State$2.Rejecting({ plan }));
|
|
688
|
+
runner.run(group.reject({
|
|
689
|
+
planId: plan.id,
|
|
690
|
+
...reason === void 0 ? {} : { reason }
|
|
691
|
+
}), {
|
|
692
|
+
onFailure,
|
|
693
|
+
onSuccess: (attempt) => {
|
|
694
|
+
setState(State$2.Rejected({
|
|
695
|
+
attempt,
|
|
696
|
+
plan
|
|
697
|
+
}));
|
|
698
|
+
emit(Event.Declined({
|
|
699
|
+
attempt,
|
|
700
|
+
domain
|
|
701
|
+
}));
|
|
669
702
|
}
|
|
670
|
-
|
|
671
|
-
if (input._tag === "Connect") return complete(Effect.flatMap(Transport.Service, (transport) => transport.connection.connect({
|
|
672
|
-
domain,
|
|
673
|
-
method: input.method,
|
|
674
|
-
providerId: snapshot.provider.id
|
|
675
|
-
})), "connect");
|
|
676
|
-
return Effect.void;
|
|
677
|
-
}),
|
|
678
|
-
state
|
|
703
|
+
});
|
|
679
704
|
};
|
|
705
|
+
lastCommand.current = {
|
|
706
|
+
key,
|
|
707
|
+
run: command
|
|
708
|
+
};
|
|
709
|
+
command();
|
|
680
710
|
}, [
|
|
681
711
|
domain,
|
|
682
712
|
emit,
|
|
683
|
-
|
|
684
|
-
|
|
713
|
+
group,
|
|
714
|
+
key,
|
|
715
|
+
onFailure,
|
|
716
|
+
runner
|
|
717
|
+
]);
|
|
718
|
+
const apply = useCallback(() => {
|
|
719
|
+
const { approval, plan } = held.current;
|
|
720
|
+
if (approval === null || plan === null) return;
|
|
721
|
+
applyWith(plan, approval);
|
|
722
|
+
}, [applyWith]);
|
|
723
|
+
const retry = useCallback(() => {
|
|
724
|
+
if (readOnly) return;
|
|
725
|
+
if (state._tag === "Failure" && needsNewPlan(state.error)) {
|
|
726
|
+
held.current = {
|
|
727
|
+
approval: null,
|
|
728
|
+
key,
|
|
729
|
+
plan: null
|
|
730
|
+
};
|
|
731
|
+
buildPlan();
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
const command = lastCommand.current;
|
|
735
|
+
if (command === null || command.key !== key) buildPlan();
|
|
736
|
+
else command.run();
|
|
737
|
+
}, [
|
|
738
|
+
buildPlan,
|
|
739
|
+
key,
|
|
740
|
+
readOnly,
|
|
741
|
+
state
|
|
685
742
|
]);
|
|
686
|
-
}
|
|
687
|
-
function useController$2(domain) {
|
|
688
|
-
const model = useModel$2(domain);
|
|
689
|
-
const state = useAtomValue(model.state);
|
|
690
|
-
const execute = useAtomSet(model.command);
|
|
691
743
|
return {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
744
|
+
apply,
|
|
745
|
+
approve,
|
|
746
|
+
plan: buildPlan,
|
|
747
|
+
reject,
|
|
748
|
+
reset: useCallback(() => {
|
|
749
|
+
runner.cancel();
|
|
750
|
+
held.current = {
|
|
751
|
+
approval: null,
|
|
752
|
+
key,
|
|
753
|
+
plan: null
|
|
754
|
+
};
|
|
755
|
+
lastCommand.current = null;
|
|
756
|
+
setState(State$2.Idle());
|
|
757
|
+
}, [key, runner]),
|
|
758
|
+
retry,
|
|
699
759
|
state
|
|
700
760
|
};
|
|
701
761
|
}
|
|
702
|
-
function Root$3({ children, status = "Loading", ...props }) {
|
|
703
|
-
return usePart("div", props, { status }, {
|
|
704
|
-
children,
|
|
705
|
-
"data-domainkit-part": "connection-root"
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
function Status$2({ children, state, ...props }) {
|
|
709
|
-
const { messages } = useDomainKit();
|
|
710
|
-
const text = state._tag === "Loading" ? messages.detectingProvider : state._tag === "Connected" ? messages.connected(state.provider.name) : state._tag === "Detaching" ? messages.detaching : state._tag === "Unsupported" ? messages.automaticUnavailable : state._tag === "Failure" ? state.message : state._tag === "Redirecting" ? messages.openingAuthorization : state._tag === "Submitting" ? messages.connecting : messages.providerAvailable(state.provider.name);
|
|
711
|
-
return usePart("div", props, { status: state._tag }, {
|
|
712
|
-
children: children ?? text,
|
|
713
|
-
"data-domainkit-part": "connection-status",
|
|
714
|
-
"data-state": state._tag
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
|
-
function Trigger({ children, ...props }) {
|
|
718
|
-
return /* @__PURE__ */ jsx(Dialog.Trigger, {
|
|
719
|
-
"data-domainkit-part": "connection-trigger",
|
|
720
|
-
...props,
|
|
721
|
-
children
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
function ConnectTrigger({ children, provider, ...props }) {
|
|
725
|
-
const { messages } = useDomainKit();
|
|
726
|
-
return /* @__PURE__ */ jsx(Trigger, {
|
|
727
|
-
...props,
|
|
728
|
-
"data-domainkit-recipe": "connect",
|
|
729
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Mark, {
|
|
730
|
-
"aria-hidden": "true",
|
|
731
|
-
provider
|
|
732
|
-
}), messages.connectProvider(provider.name)] })
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
function OAuthAction({ controller, label, ...props }) {
|
|
736
|
-
return usePart("button", props, { authentication: "oauth" }, {
|
|
737
|
-
children: label,
|
|
738
|
-
"data-domainkit-part": "oauth-connect",
|
|
739
|
-
disabled: controller.state._tag === "Submitting" || controller.state._tag === "Redirecting",
|
|
740
|
-
onClick: () => controller.connect(Transport.Method.OAuth()),
|
|
741
|
-
type: "button"
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
function IntegrationAction({ controller, label, ...props }) {
|
|
745
|
-
return usePart("button", props, { authentication: "integration" }, {
|
|
746
|
-
children: label,
|
|
747
|
-
"data-domainkit-part": "integration-connect",
|
|
748
|
-
disabled: controller.state._tag === "Submitting" || controller.state._tag === "Redirecting",
|
|
749
|
-
onClick: () => controller.connect(Transport.Method.Integration()),
|
|
750
|
-
type: "button"
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
function AttachAction({ connection, controller, label, target, ...props }) {
|
|
754
|
-
return usePart("button", props, { authentication: "attach" }, {
|
|
755
|
-
children: label,
|
|
756
|
-
"data-domainkit-part": "attach-target",
|
|
757
|
-
disabled: controller.state._tag === "Submitting" || controller.state._tag === "Redirecting",
|
|
758
|
-
onClick: () => controller.attach(connection, target),
|
|
759
|
-
type: "button"
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
function TokenAction({ controller, method, ...props }) {
|
|
763
|
-
const { messages } = useDomainKit();
|
|
764
|
-
const pending = controller.state._tag === "Submitting" || controller.state._tag === "Redirecting";
|
|
765
|
-
const [token, setToken] = useState("");
|
|
766
|
-
const [parameters, setParameters] = useState({});
|
|
767
|
-
const submit = (event) => {
|
|
768
|
-
event.preventDefault();
|
|
769
|
-
if (token.length > 0) {
|
|
770
|
-
const populated = Object.fromEntries(Object.entries(parameters).filter(([, value]) => value.length > 0));
|
|
771
|
-
controller.connect(Transport.Method.Token({
|
|
772
|
-
token,
|
|
773
|
-
...Object.keys(populated).length === 0 ? {} : { parameters: populated }
|
|
774
|
-
}));
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
const missingRequiredParameter = method.parameters?.some((parameter) => parameter.required === true && !parameters[parameter.key]);
|
|
778
|
-
return usePart("form", props, { authentication: "token" }, {
|
|
779
|
-
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
780
|
-
method.parameters?.map((parameter) => /* @__PURE__ */ jsxs("label", { children: [
|
|
781
|
-
parameter.label,
|
|
782
|
-
/* @__PURE__ */ jsx("input", {
|
|
783
|
-
name: parameter.key,
|
|
784
|
-
disabled: pending,
|
|
785
|
-
onChange: (event) => {
|
|
786
|
-
const value = event.currentTarget.value;
|
|
787
|
-
setParameters((current) => ({
|
|
788
|
-
...current,
|
|
789
|
-
[parameter.key]: value
|
|
790
|
-
}));
|
|
791
|
-
},
|
|
792
|
-
placeholder: parameter.placeholder,
|
|
793
|
-
required: parameter.required,
|
|
794
|
-
type: "text",
|
|
795
|
-
value: parameters[parameter.key] ?? ""
|
|
796
|
-
}),
|
|
797
|
-
parameter.description === void 0 ? null : /* @__PURE__ */ jsx("small", { children: parameter.description })
|
|
798
|
-
] }, parameter.key)),
|
|
799
|
-
/* @__PURE__ */ jsxs("label", { children: [messages.tokenLabel, /* @__PURE__ */ jsx("input", {
|
|
800
|
-
autoComplete: "off",
|
|
801
|
-
disabled: pending,
|
|
802
|
-
name: "token",
|
|
803
|
-
onChange: (event) => setToken(event.currentTarget.value),
|
|
804
|
-
placeholder: method.placeholder,
|
|
805
|
-
type: "password",
|
|
806
|
-
value: token
|
|
807
|
-
})] }),
|
|
808
|
-
/* @__PURE__ */ jsx("button", {
|
|
809
|
-
disabled: pending || token.length === 0 || missingRequiredParameter === true,
|
|
810
|
-
type: "submit",
|
|
811
|
-
children: method.label
|
|
812
|
-
})
|
|
813
|
-
] }),
|
|
814
|
-
"data-domainkit-part": "token-connect",
|
|
815
|
-
onSubmit: submit
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
const targetLabel = (target) => `${target.evidence?.accountName ?? target.accountId} · ${target.zoneName}`;
|
|
819
|
-
function Dialog$2({ controller, snapshot }) {
|
|
820
|
-
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
821
|
-
const pending = controller.state._tag === "Submitting" || controller.state._tag === "Redirecting";
|
|
822
|
-
const integrationMethods = snapshot.provider.authentication.filter((method) => method._tag === "Integration");
|
|
823
|
-
const oauthMethods = snapshot.provider.authentication.filter((method) => method._tag === "OAuth");
|
|
824
|
-
const tokenMethods = snapshot.provider.authentication.filter((method) => method._tag === "Token");
|
|
825
|
-
const hasProviderAccountPath = integrationMethods.length > 0 || oauthMethods.length > 0 || snapshot.reusableConnections.length > 0;
|
|
826
|
-
return /* @__PURE__ */ jsxs(Dialog.Portal, {
|
|
827
|
-
container: portalContainer,
|
|
828
|
-
children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
829
|
-
"data-color-scheme": colorScheme,
|
|
830
|
-
"data-domainkit-part": "dialog-backdrop",
|
|
831
|
-
"data-domainkit-root": "",
|
|
832
|
-
style: themeStyle
|
|
833
|
-
}), /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
834
|
-
"data-domainkit-part": "connection-dialog",
|
|
835
|
-
"data-domainkit-root": "",
|
|
836
|
-
"data-color-scheme": colorScheme,
|
|
837
|
-
style: themeStyle,
|
|
838
|
-
children: [
|
|
839
|
-
/* @__PURE__ */ jsxs("div", {
|
|
840
|
-
"data-domainkit-part": "dialog-header",
|
|
841
|
-
children: [
|
|
842
|
-
/* @__PURE__ */ jsx(Mark, { provider: snapshot.provider }),
|
|
843
|
-
/* @__PURE__ */ jsxs("div", {
|
|
844
|
-
"data-domainkit-part": "dialog-heading",
|
|
845
|
-
children: [/* @__PURE__ */ jsx(Dialog.Title, {
|
|
846
|
-
"data-domainkit-part": "dialog-title",
|
|
847
|
-
children: messages.dialogTitle(snapshot.provider.name)
|
|
848
|
-
}), /* @__PURE__ */ jsx(Dialog.Description, {
|
|
849
|
-
"data-domainkit-part": "dialog-description",
|
|
850
|
-
children: messages.dialogDescription(snapshot.domain)
|
|
851
|
-
})]
|
|
852
|
-
}),
|
|
853
|
-
pending ? null : /* @__PURE__ */ jsx(Dialog.Close, {
|
|
854
|
-
"aria-label": messages.close,
|
|
855
|
-
"data-domainkit-part": "dialog-close",
|
|
856
|
-
children: "×"
|
|
857
|
-
})
|
|
858
|
-
]
|
|
859
|
-
}),
|
|
860
|
-
/* @__PURE__ */ jsxs("div", {
|
|
861
|
-
"data-domainkit-part": "dialog-body",
|
|
862
|
-
children: [
|
|
863
|
-
hasProviderAccountPath ? /* @__PURE__ */ jsxs("div", {
|
|
864
|
-
"data-domainkit-part": "provider-authentication",
|
|
865
|
-
children: [
|
|
866
|
-
integrationMethods.map((method) => /* @__PURE__ */ jsx(IntegrationAction, {
|
|
867
|
-
controller,
|
|
868
|
-
label: method.label
|
|
869
|
-
}, method._tag)),
|
|
870
|
-
oauthMethods.map((method) => /* @__PURE__ */ jsx(OAuthAction, {
|
|
871
|
-
controller,
|
|
872
|
-
label: method.label
|
|
873
|
-
}, method._tag)),
|
|
874
|
-
snapshot.reusableConnections.map((connection) => /* @__PURE__ */ jsxs("section", {
|
|
875
|
-
"data-connection-id": connection.connection.id,
|
|
876
|
-
"data-domainkit-part": "reusable-connection",
|
|
877
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
878
|
-
"data-domainkit-part": "reusable-connection-heading",
|
|
879
|
-
children: [/* @__PURE__ */ jsx("strong", { children: messages.existingConnection }), /* @__PURE__ */ jsx("span", { children: connection.connection.providerId })]
|
|
880
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
881
|
-
"data-domainkit-part": "target-list",
|
|
882
|
-
"data-state": connection.targets.length === 0 ? "unavailable" : connection.targets.length === 1 ? "unique" : "ambiguous",
|
|
883
|
-
children: connection.targets.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
884
|
-
"data-domainkit-part": "target-unavailable",
|
|
885
|
-
children: messages.targetUnavailable
|
|
886
|
-
}) : connection.targets.map((target) => /* @__PURE__ */ jsx(AttachAction, {
|
|
887
|
-
connection,
|
|
888
|
-
controller,
|
|
889
|
-
label: messages.attachTarget(targetLabel(target)),
|
|
890
|
-
target
|
|
891
|
-
}, `${target.accountId}:${target.zoneId}`))
|
|
892
|
-
})]
|
|
893
|
-
}, connection.connection.id))
|
|
894
|
-
]
|
|
895
|
-
}) : null,
|
|
896
|
-
hasProviderAccountPath && tokenMethods.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
897
|
-
"aria-label": messages.authenticationAlternative,
|
|
898
|
-
"data-domainkit-part": "authentication-separator",
|
|
899
|
-
role: "separator",
|
|
900
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
901
|
-
"aria-hidden": "true",
|
|
902
|
-
children: messages.authenticationAlternative
|
|
903
|
-
})
|
|
904
|
-
}) : null,
|
|
905
|
-
tokenMethods.map((method) => /* @__PURE__ */ jsx(TokenAction, {
|
|
906
|
-
controller,
|
|
907
|
-
method
|
|
908
|
-
}, method._tag))
|
|
909
|
-
]
|
|
910
|
-
}),
|
|
911
|
-
pending ? null : /* @__PURE__ */ jsx("div", {
|
|
912
|
-
"data-domainkit-part": "dialog-footer",
|
|
913
|
-
children: /* @__PURE__ */ jsx(Dialog.Close, {
|
|
914
|
-
"data-domainkit-part": "dialog-cancel",
|
|
915
|
-
children: messages.cancel
|
|
916
|
-
})
|
|
917
|
-
})
|
|
918
|
-
]
|
|
919
|
-
})]
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
function Flow$2({ domain, ...props }) {
|
|
923
|
-
const controller = useController$2(domain);
|
|
924
|
-
const state = controller.state;
|
|
925
|
-
const snapshot = state._tag === "Disconnected" ? state : state._tag === "Submitting" || state._tag === "Redirecting" ? state.snapshot : void 0;
|
|
926
|
-
return /* @__PURE__ */ jsxs(Root$3, {
|
|
927
|
-
...props,
|
|
928
|
-
status: state._tag,
|
|
929
|
-
children: [
|
|
930
|
-
/* @__PURE__ */ jsx(Status$2, { state }),
|
|
931
|
-
state._tag === "Failure" && state.retry !== "never" ? /* @__PURE__ */ jsx(RetryAction$1, {
|
|
932
|
-
controller,
|
|
933
|
-
kind: state.retry === "after-user-action" ? "after-user-action" : "retry"
|
|
934
|
-
}) : null,
|
|
935
|
-
snapshot === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
936
|
-
onOpenChange: (open, eventDetails) => {
|
|
937
|
-
if (!open && (state._tag === "Submitting" || state._tag === "Redirecting")) eventDetails.cancel();
|
|
938
|
-
},
|
|
939
|
-
children: [/* @__PURE__ */ jsx(ConnectTrigger, { provider: snapshot.provider }), /* @__PURE__ */ jsx(Dialog$2, {
|
|
940
|
-
controller,
|
|
941
|
-
snapshot
|
|
942
|
-
})]
|
|
943
|
-
})
|
|
944
|
-
]
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
function RetryAction$1({ controller, kind = "retry", ...props }) {
|
|
948
|
-
const { messages } = useDomainKit();
|
|
949
|
-
return usePart("button", props, { status: "Failure" }, {
|
|
950
|
-
children: kind === "after-user-action" ? messages.checkAgain : messages.retry,
|
|
951
|
-
"data-domainkit-part": "connection-retry",
|
|
952
|
-
onClick: controller.retry,
|
|
953
|
-
type: "button"
|
|
954
|
-
});
|
|
955
|
-
}
|
|
956
|
-
function Card$1({ status, ...props }) {
|
|
957
|
-
return usePart("div", props, { status }, {
|
|
958
|
-
"data-domainkit-part": "connected-card",
|
|
959
|
-
"data-state": status
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
function CardIdentity({ status, ...props }) {
|
|
963
|
-
return usePart("div", props, { status }, {
|
|
964
|
-
"data-domainkit-part": "connected-identity",
|
|
965
|
-
"data-state": status
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
function CardActions({ status, ...props }) {
|
|
969
|
-
return usePart("div", props, { status }, {
|
|
970
|
-
"data-domainkit-part": "connected-actions",
|
|
971
|
-
"data-state": status
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
function DisconnectDialog({ connection, controller, onOpenChange, open: openProp, trigger }) {
|
|
975
|
-
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
976
|
-
const [internalOpen, setInternalOpen] = useState(false);
|
|
977
|
-
const open = openProp ?? internalOpen;
|
|
978
|
-
const setOpen = (nextOpen) => {
|
|
979
|
-
if (openProp === void 0) setInternalOpen(nextOpen);
|
|
980
|
-
onOpenChange?.(nextOpen);
|
|
981
|
-
};
|
|
982
|
-
const detaching = controller.state._tag === "Detaching";
|
|
983
|
-
return /* @__PURE__ */ jsxs(AlertDialog.Root, {
|
|
984
|
-
onOpenChange: (nextOpen, eventDetails) => {
|
|
985
|
-
if (!nextOpen && detaching) {
|
|
986
|
-
eventDetails.cancel();
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
setOpen(nextOpen);
|
|
990
|
-
},
|
|
991
|
-
open,
|
|
992
|
-
children: [trigger === null ? null : /* @__PURE__ */ jsx(AlertDialog.Trigger, {
|
|
993
|
-
"data-domainkit-part": "disconnect-trigger",
|
|
994
|
-
...trigger === void 0 ? {} : { render: trigger },
|
|
995
|
-
children: messages.disconnectDomain
|
|
996
|
-
}), /* @__PURE__ */ jsxs(AlertDialog.Portal, {
|
|
997
|
-
container: portalContainer,
|
|
998
|
-
children: [/* @__PURE__ */ jsx(AlertDialog.Backdrop, {
|
|
999
|
-
"data-color-scheme": colorScheme,
|
|
1000
|
-
"data-domainkit-part": "dialog-backdrop",
|
|
1001
|
-
"data-domainkit-root": "",
|
|
1002
|
-
style: themeStyle
|
|
1003
|
-
}), /* @__PURE__ */ jsxs(AlertDialog.Popup, {
|
|
1004
|
-
"data-color-scheme": colorScheme,
|
|
1005
|
-
"data-domainkit-part": "disconnect-dialog",
|
|
1006
|
-
"data-domainkit-root": "",
|
|
1007
|
-
style: themeStyle,
|
|
1008
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
1009
|
-
"data-domainkit-part": "dialog-header",
|
|
1010
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
1011
|
-
"data-domainkit-part": "dialog-heading",
|
|
1012
|
-
children: [/* @__PURE__ */ jsx(AlertDialog.Title, {
|
|
1013
|
-
"data-domainkit-part": "dialog-title",
|
|
1014
|
-
children: messages.disconnectTitle(connection.provider.name)
|
|
1015
|
-
}), /* @__PURE__ */ jsx(AlertDialog.Description, {
|
|
1016
|
-
"data-domainkit-part": "dialog-description",
|
|
1017
|
-
children: messages.disconnectConsent
|
|
1018
|
-
})]
|
|
1019
|
-
}), detaching ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
|
|
1020
|
-
"aria-label": messages.close,
|
|
1021
|
-
"data-domainkit-part": "dialog-close",
|
|
1022
|
-
children: "×"
|
|
1023
|
-
})]
|
|
1024
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
1025
|
-
"data-domainkit-part": "dialog-footer",
|
|
1026
|
-
children: [detaching ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
|
|
1027
|
-
"data-domainkit-part": "dialog-cancel",
|
|
1028
|
-
children: messages.cancel
|
|
1029
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
1030
|
-
"data-domainkit-part": "disconnect-action",
|
|
1031
|
-
disabled: detaching,
|
|
1032
|
-
onClick: () => controller.detach(),
|
|
1033
|
-
type: "button",
|
|
1034
|
-
children: detaching ? messages.detaching : messages.disconnectDomain
|
|
1035
|
-
})]
|
|
1036
|
-
})]
|
|
1037
|
-
})]
|
|
1038
|
-
})]
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
762
|
//#endregion
|
|
1042
763
|
//#region src/records.tsx
|
|
1043
764
|
var records_exports = /* @__PURE__ */ __exportAll({
|
|
1044
|
-
Body: () => Body,
|
|
765
|
+
Body: () => Body$1,
|
|
1045
766
|
Caption: () => Caption,
|
|
1046
|
-
Card: () => Card,
|
|
767
|
+
Card: () => Card$1,
|
|
1047
768
|
CardContent: () => CardContent,
|
|
1048
769
|
CardHeader: () => CardHeader,
|
|
1049
770
|
CardTitle: () => CardTitle,
|
|
@@ -1052,35 +773,22 @@ var records_exports = /* @__PURE__ */ __exportAll({
|
|
|
1052
773
|
Footer: () => Footer,
|
|
1053
774
|
Head: () => Head,
|
|
1054
775
|
Header: () => Header,
|
|
1055
|
-
|
|
1056
|
-
Root: () => Root$
|
|
776
|
+
Purpose: () => Purpose,
|
|
777
|
+
Root: () => Root$5,
|
|
1057
778
|
Row: () => Row,
|
|
1058
|
-
Status: () => Status$
|
|
779
|
+
Status: () => Status$5,
|
|
1059
780
|
Table: () => Table,
|
|
1060
781
|
Value: () => Value,
|
|
1061
782
|
ZoneFile: () => ZoneFile,
|
|
1062
783
|
copyText: () => copyText,
|
|
1063
784
|
downloadZoneFile: () => downloadZoneFile,
|
|
785
|
+
identity: () => identity,
|
|
786
|
+
requirementsKey: () => requirementsKey,
|
|
787
|
+
statusOf: () => statusOf,
|
|
1064
788
|
toZoneFile: () => toZoneFile,
|
|
1065
789
|
useCopy: () => useCopy
|
|
1066
790
|
});
|
|
1067
|
-
const
|
|
1068
|
-
if (typeof navigator === "undefined" || navigator.clipboard === void 0) return Promise.resolve(false);
|
|
1069
|
-
return navigator.clipboard.writeText(value).then(() => true, () => false);
|
|
1070
|
-
};
|
|
1071
|
-
const downloadText = (filename, contents) => {
|
|
1072
|
-
if (typeof document === "undefined") return;
|
|
1073
|
-
const blob = new Blob([contents], { type: "text/plain;charset=utf-8" });
|
|
1074
|
-
const url = URL.createObjectURL(blob);
|
|
1075
|
-
const anchor = document.createElement("a");
|
|
1076
|
-
anchor.download = filename;
|
|
1077
|
-
anchor.href = url;
|
|
1078
|
-
document.body.append(anchor);
|
|
1079
|
-
anchor.click();
|
|
1080
|
-
anchor.remove();
|
|
1081
|
-
URL.revokeObjectURL(url);
|
|
1082
|
-
};
|
|
1083
|
-
const absoluteDomainName = (value) => value.endsWith(".") ? value : `${value}.`;
|
|
791
|
+
const absolute = (value) => value.endsWith(".") ? value : `${value}.`;
|
|
1084
792
|
const textEncoder = new TextEncoder();
|
|
1085
793
|
const escapeTxtCharacter = (character) => {
|
|
1086
794
|
if (character === "\"" || character === "\\") return `\\${character}`;
|
|
@@ -1088,6 +796,7 @@ const escapeTxtCharacter = (character) => {
|
|
|
1088
796
|
if (codePoint !== void 0 && (codePoint < 32 || codePoint === 127)) return `\\${codePoint.toString().padStart(3, "0")}`;
|
|
1089
797
|
return character;
|
|
1090
798
|
};
|
|
799
|
+
/** TXT strings are capped at 255 bytes each, so long values are split and quoted per chunk. */
|
|
1091
800
|
const txtValue = (value) => {
|
|
1092
801
|
const chunks = [];
|
|
1093
802
|
let chunk = "";
|
|
@@ -1105,29 +814,38 @@ const txtValue = (value) => {
|
|
|
1105
814
|
chunks.push(chunk);
|
|
1106
815
|
return chunks.map((part) => `"${part}"`).join(" ");
|
|
1107
816
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
switch (record.type.toUpperCase()) {
|
|
1117
|
-
case "CNAME":
|
|
1118
|
-
case "MX":
|
|
1119
|
-
case "NS":
|
|
1120
|
-
case "PTR": return absoluteDomainName(record.value);
|
|
1121
|
-
case "SRV": return srvValue(record.value);
|
|
817
|
+
/** The RR type as a zone file spells it. The tag and the type name are the same string. */
|
|
818
|
+
const rrType = (record) => record._tag;
|
|
819
|
+
const zoneData = (record) => {
|
|
820
|
+
switch (record._tag) {
|
|
821
|
+
case "A":
|
|
822
|
+
case "AAAA": return record.address;
|
|
823
|
+
case "CNAME": return absolute(record.target);
|
|
824
|
+
case "NS": return absolute(record.nameserver);
|
|
1122
825
|
case "TXT": return txtValue(record.value);
|
|
1123
|
-
|
|
826
|
+
case "MX": return `${record.priority} ${absolute(record.exchange)}`;
|
|
827
|
+
case "CAA": return `${record.flags} ${record.tag} "${record.value}"`;
|
|
828
|
+
case "SRV": return `${record.priority} ${record.weight} ${record.port} ${absolute(record.target)}`;
|
|
1124
829
|
}
|
|
1125
830
|
};
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
};
|
|
1130
|
-
|
|
831
|
+
const toZoneFile = (records) => `${records.map((record) => `${absolute(record.name)}${record.ttl === null ? "" : ` ${record.ttl}`} IN ${rrType(record)} ${zoneData(record)}`).join("\n")}\n`;
|
|
832
|
+
const downloadText = (filename, contents) => {
|
|
833
|
+
if (typeof document === "undefined") return;
|
|
834
|
+
const blob = new Blob([contents], { type: "text/plain;charset=utf-8" });
|
|
835
|
+
const url = URL.createObjectURL(blob);
|
|
836
|
+
const anchor = document.createElement("a");
|
|
837
|
+
anchor.download = filename;
|
|
838
|
+
anchor.href = url;
|
|
839
|
+
document.body.append(anchor);
|
|
840
|
+
anchor.click();
|
|
841
|
+
anchor.remove();
|
|
842
|
+
URL.revokeObjectURL(url);
|
|
843
|
+
};
|
|
844
|
+
const downloadZoneFile = (domain, records) => downloadText(`${domain}.txt`, toZoneFile(records));
|
|
845
|
+
const copyText = (value) => {
|
|
846
|
+
if (typeof navigator === "undefined" || navigator.clipboard === void 0) return Promise.resolve(false);
|
|
847
|
+
return navigator.clipboard.writeText(value).then(() => true, () => false);
|
|
848
|
+
};
|
|
1131
849
|
function useCopy(value, resetAfter = 2e3) {
|
|
1132
850
|
const [copied, setCopied] = useState(false);
|
|
1133
851
|
const reset = useRef(void 0);
|
|
@@ -1144,279 +862,365 @@ function useCopy(value, resetAfter = 2e3) {
|
|
|
1144
862
|
}
|
|
1145
863
|
};
|
|
1146
864
|
}
|
|
1147
|
-
function CopyValue({
|
|
865
|
+
function CopyValue({ value, ...props }) {
|
|
866
|
+
const { messages } = useDomainKit();
|
|
1148
867
|
const icons = useIcons();
|
|
1149
|
-
const
|
|
1150
|
-
const copied = controller.copied;
|
|
868
|
+
const { copied, copy } = useCopy(value);
|
|
1151
869
|
return usePart("span", props, { copied }, {
|
|
1152
870
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("code", { children: value }), /* @__PURE__ */ jsxs("button", {
|
|
1153
|
-
"aria-label": `${copied ?
|
|
871
|
+
"aria-label": `${copied ? messages.copied : messages.copy} ${value}`,
|
|
1154
872
|
"data-domainkit-part": "copy-action",
|
|
1155
|
-
onClick:
|
|
873
|
+
onClick: copy,
|
|
1156
874
|
type: "button",
|
|
1157
875
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1158
876
|
"aria-hidden": "true",
|
|
1159
877
|
"data-domainkit-part": "copy-glyph",
|
|
1160
878
|
"data-icon": "",
|
|
1161
879
|
"data-state": "idle",
|
|
1162
|
-
children:
|
|
880
|
+
children: icons.copy
|
|
1163
881
|
}), /* @__PURE__ */ jsx("span", {
|
|
1164
882
|
"aria-hidden": "true",
|
|
1165
883
|
"data-domainkit-part": "copy-glyph",
|
|
1166
884
|
"data-icon": "",
|
|
1167
885
|
"data-state": "done",
|
|
1168
|
-
children:
|
|
886
|
+
children: icons.copied
|
|
1169
887
|
})]
|
|
1170
888
|
})] }),
|
|
1171
889
|
"data-copied": copied ? "" : void 0,
|
|
1172
890
|
"data-domainkit-part": "copy-value"
|
|
1173
891
|
});
|
|
1174
892
|
}
|
|
1175
|
-
function ZoneFile({
|
|
893
|
+
function ZoneFile({ domain, records, ...props }) {
|
|
894
|
+
const { messages } = useDomainKit();
|
|
1176
895
|
const icons = useIcons();
|
|
1177
|
-
const
|
|
1178
|
-
const copied = controller.copied;
|
|
896
|
+
const { copied, copy } = useCopy(toZoneFile(records));
|
|
1179
897
|
return usePart("div", props, { count: records.length }, {
|
|
1180
898
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
|
|
1181
|
-
"aria-label": copied ?
|
|
899
|
+
"aria-label": copied ? messages.copied : messages.copyZone,
|
|
1182
900
|
"data-domainkit-part": "zone-copy",
|
|
1183
|
-
onClick:
|
|
901
|
+
onClick: copy,
|
|
1184
902
|
type: "button",
|
|
1185
903
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1186
904
|
"aria-hidden": "true",
|
|
1187
905
|
"data-icon": "inline-start",
|
|
1188
|
-
children: copied ?
|
|
1189
|
-
}), copied ?
|
|
906
|
+
children: copied ? icons.copied : icons.copy
|
|
907
|
+
}), copied ? messages.copied : messages.copyZone]
|
|
1190
908
|
}), /* @__PURE__ */ jsxs("button", {
|
|
1191
|
-
"aria-label":
|
|
909
|
+
"aria-label": messages.download,
|
|
1192
910
|
"data-domainkit-part": "zone-download",
|
|
1193
911
|
onClick: () => downloadZoneFile(domain, records),
|
|
1194
912
|
type: "button",
|
|
1195
913
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1196
914
|
"aria-hidden": "true",
|
|
1197
915
|
"data-icon": "inline-start",
|
|
1198
|
-
children:
|
|
1199
|
-
}),
|
|
916
|
+
children: icons.download
|
|
917
|
+
}), messages.download]
|
|
1200
918
|
})] }),
|
|
1201
919
|
"data-domainkit-part": "zone-file"
|
|
1202
920
|
});
|
|
1203
921
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
922
|
+
/** The readiness this record reached, or `null` when nothing has observed it. */
|
|
923
|
+
const statusOf = (record, readiness) => readiness?.requirements.find((requirement) => DnsRecord.equals(requirement.record, record))?.status ?? null;
|
|
924
|
+
function Status$5({ status, ...props }) {
|
|
925
|
+
const { messages } = useDomainKit();
|
|
926
|
+
const icons = useIcons();
|
|
927
|
+
const glyph = status === "satisfied" ? icons.success : status === "unknown" ? icons.pending : icons.failure;
|
|
928
|
+
return usePart("span", props, { status }, {
|
|
929
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
930
|
+
"aria-hidden": "true",
|
|
931
|
+
"data-icon": "inline-start",
|
|
932
|
+
children: glyph
|
|
933
|
+
}), messages.requirementStatus(status)] }),
|
|
1207
934
|
"data-domainkit-part": "record-status",
|
|
1208
|
-
"data-status":
|
|
1209
|
-
});
|
|
1210
|
-
}
|
|
1211
|
-
function Priority({ children, priority = 0, ...props }) {
|
|
1212
|
-
return usePart("span", props, { priority }, {
|
|
1213
|
-
children: children ?? `Priority ${priority}`,
|
|
1214
|
-
"data-domainkit-part": "record-priority"
|
|
935
|
+
"data-status": status
|
|
1215
936
|
});
|
|
1216
937
|
}
|
|
1217
938
|
const Header = leafPart("thead", "records-header");
|
|
1218
|
-
const Body = leafPart("tbody", "records-body");
|
|
939
|
+
const Body$1 = leafPart("tbody", "records-body");
|
|
1219
940
|
const Footer = leafPart("tfoot", "records-footer");
|
|
1220
941
|
const Row = leafPart("tr", "records-row");
|
|
1221
942
|
const Head = leafPart("th", "records-head");
|
|
1222
943
|
const Cell = leafPart("td", "records-cell");
|
|
1223
944
|
const Caption = leafPart("caption", "records-caption");
|
|
1224
945
|
const Value = leafPart("span", "record-value");
|
|
946
|
+
const Purpose = leafPart("span", "record-purpose");
|
|
1225
947
|
const CardHeader = leafPart("div", "record-card-head");
|
|
1226
948
|
const CardTitle = leafPart("strong", "record-card-title");
|
|
1227
949
|
const CardContent = leafPart("dl", "record-card-content");
|
|
1228
|
-
function Root$
|
|
950
|
+
function Root$5({ count = 0, ...props }) {
|
|
1229
951
|
return /* @__PURE__ */ jsx("div", {
|
|
1230
952
|
"data-domainkit-part": "records-panel",
|
|
1231
953
|
children: usePart("table", props, { count }, { "data-domainkit-part": "records-table" })
|
|
1232
954
|
});
|
|
1233
955
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
956
|
+
/** A stable React key for a requirement: type, name, and data identify a record. */
|
|
957
|
+
const identity = (record) => [
|
|
958
|
+
rrType(record),
|
|
959
|
+
record.name,
|
|
960
|
+
DnsRecord.data(record)
|
|
961
|
+
].join(":");
|
|
962
|
+
/**
|
|
963
|
+
* A requirement set keyed by everything it carries, for memos that decide whether to re-send it.
|
|
964
|
+
* `identity` is deliberately narrower: it answers "is this the same record" for a React key, while
|
|
965
|
+
* a plan and an observation are built from `ttl`, `policy`, and `purpose` as well. `policy` in
|
|
966
|
+
* particular decides whether a name may hold anything else, so readiness turns on it.
|
|
967
|
+
*/
|
|
968
|
+
const requirementsKey = (records) => JSON.stringify(records);
|
|
969
|
+
function Card$1({ readiness, record, ...props }) {
|
|
970
|
+
const { messages } = useDomainKit();
|
|
971
|
+
const status = statusOf(record, readiness);
|
|
972
|
+
return usePart("section", props, { record: identity(record) }, {
|
|
973
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(CardTitle, { children: messages.recordType(record) }), status === null ? null : /* @__PURE__ */ jsx(Status$5, { status })] }), /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
974
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: messages.headingName }), /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(CopyValue, { value: record.name }) })] }),
|
|
975
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: messages.headingValue }), /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(CopyValue, { value: DnsRecord.data(record) }) })] }),
|
|
976
|
+
record.purpose === void 0 ? null : /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: messages.headingPurpose }), /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Purpose, { children: record.purpose }) })] })
|
|
977
|
+
] })] }),
|
|
1246
978
|
"data-domainkit-part": "record-card"
|
|
1247
979
|
});
|
|
1248
980
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
981
|
+
/** The default records presentation: one row per requirement, with readiness when there is any. */
|
|
982
|
+
function Table({ caption, readiness, records, ...props }) {
|
|
983
|
+
const { messages } = useDomainKit();
|
|
984
|
+
const withStatus = readiness !== null && readiness !== void 0;
|
|
985
|
+
return /* @__PURE__ */ jsxs(Root$5, {
|
|
1252
986
|
count: records.length,
|
|
1253
987
|
...props,
|
|
1254
|
-
children: [
|
|
1255
|
-
/* @__PURE__ */ jsx(
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
] }, record.id)) })]
|
|
988
|
+
children: [
|
|
989
|
+
caption === void 0 ? null : /* @__PURE__ */ jsx(Caption, { children: caption }),
|
|
990
|
+
/* @__PURE__ */ jsx(Header, { children: /* @__PURE__ */ jsxs(Row, { children: [
|
|
991
|
+
/* @__PURE__ */ jsx(Head, {
|
|
992
|
+
scope: "col",
|
|
993
|
+
children: messages.headingType
|
|
994
|
+
}),
|
|
995
|
+
/* @__PURE__ */ jsx(Head, {
|
|
996
|
+
scope: "col",
|
|
997
|
+
children: messages.headingName
|
|
998
|
+
}),
|
|
999
|
+
/* @__PURE__ */ jsx(Head, {
|
|
1000
|
+
scope: "col",
|
|
1001
|
+
children: messages.headingValue
|
|
1002
|
+
}),
|
|
1003
|
+
withStatus ? /* @__PURE__ */ jsx(Head, {
|
|
1004
|
+
"data-column": "status",
|
|
1005
|
+
scope: "col",
|
|
1006
|
+
children: messages.headingStatus
|
|
1007
|
+
}) : null
|
|
1008
|
+
] }) }),
|
|
1009
|
+
/* @__PURE__ */ jsx(Body$1, { children: records.map((record) => {
|
|
1010
|
+
const status = statusOf(record, readiness);
|
|
1011
|
+
return /* @__PURE__ */ jsxs(Row, { children: [
|
|
1012
|
+
/* @__PURE__ */ jsx(Cell, { children: messages.recordType(record) }),
|
|
1013
|
+
/* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(CopyValue, { value: record.name }) }),
|
|
1014
|
+
/* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsxs(Value, { children: [/* @__PURE__ */ jsx(CopyValue, { value: DnsRecord.data(record) }), record.purpose === void 0 ? null : /* @__PURE__ */ jsx(Purpose, { children: record.purpose })] }) }),
|
|
1015
|
+
withStatus ? /* @__PURE__ */ jsx(Cell, {
|
|
1016
|
+
"data-column": "status",
|
|
1017
|
+
children: status === null ? null : /* @__PURE__ */ jsx(Status$5, { status })
|
|
1018
|
+
}) : null
|
|
1019
|
+
] }, identity(record));
|
|
1020
|
+
}) })
|
|
1021
|
+
]
|
|
1289
1022
|
});
|
|
1290
1023
|
}
|
|
1291
|
-
const toZoneFile = (records) => `${records.map((record) => `${absoluteDomainName(record.name)} IN ${record.type} ${record.priority === void 0 ? "" : `${record.priority} `}${zoneValue(record)}`).join("\n")}\n`;
|
|
1292
|
-
const downloadZoneFile = (domain, records) => downloadText(`${domain}.txt`, toZoneFile(records));
|
|
1293
1024
|
//#endregion
|
|
1294
|
-
//#region src/
|
|
1295
|
-
var
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
useModel: () => useModel$1
|
|
1025
|
+
//#region src/operations.tsx
|
|
1026
|
+
var operations_exports = /* @__PURE__ */ __exportAll({
|
|
1027
|
+
Item: () => Item,
|
|
1028
|
+
Kind: () => Kind,
|
|
1029
|
+
List: () => List,
|
|
1030
|
+
Name: () => Name,
|
|
1031
|
+
Reason: () => Reason$1,
|
|
1032
|
+
Record: () => Record,
|
|
1033
|
+
Root: () => Root$4,
|
|
1034
|
+
Type: () => Type
|
|
1305
1035
|
});
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
return
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
get.set(state, State$1.Planning());
|
|
1326
|
-
return Effect.flatMap(Transport.Service, (transport) => transport.provisioning.plan({
|
|
1327
|
-
attachmentId: connection.attachment.id,
|
|
1328
|
-
domain: connection.attachment.domain,
|
|
1329
|
-
records
|
|
1330
|
-
})).pipe(Effect.tap((plan) => Effect.sync(() => get.set(state, State$1.Review({ plan })))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
|
|
1331
|
-
}
|
|
1332
|
-
if (current._tag !== "Review" || current.plan.operations.some((operation) => operation._tag === "Conflict")) return Effect.void;
|
|
1333
|
-
const plan = current.plan;
|
|
1334
|
-
get.set(state, State$1.Applying({ plan }));
|
|
1335
|
-
return Effect.flatMap(Transport.Service, (transport) => transport.provisioning.apply({
|
|
1336
|
-
attachmentId: connection.attachment.id,
|
|
1337
|
-
domain: connection.attachment.domain,
|
|
1338
|
-
planDigest: plan.digest
|
|
1339
|
-
})).pipe(Effect.tap((result) => Effect.sync(() => {
|
|
1340
|
-
if (result._tag === "Applied") {
|
|
1341
|
-
get.set(state, State$1.Complete({ result }));
|
|
1342
|
-
emit(Event.RecordsApplied({
|
|
1343
|
-
connection,
|
|
1344
|
-
result
|
|
1345
|
-
}));
|
|
1346
|
-
onAppliedRef.current?.(result);
|
|
1347
|
-
} else if (result._tag === "Partial") {
|
|
1348
|
-
get.set(state, State$1.Partial({ result }));
|
|
1349
|
-
emit(Event.RecordsPartiallyApplied({
|
|
1350
|
-
connection,
|
|
1351
|
-
result
|
|
1352
|
-
}));
|
|
1353
|
-
onAppliedRef.current?.(result);
|
|
1354
|
-
} else get.set(state, result);
|
|
1355
|
-
})), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
|
|
1356
|
-
}),
|
|
1357
|
-
state
|
|
1358
|
-
};
|
|
1359
|
-
}, [
|
|
1360
|
-
connection.attachment.domain,
|
|
1361
|
-
connection.attachment.id,
|
|
1362
|
-
emit,
|
|
1363
|
-
recordKey,
|
|
1364
|
-
runtime
|
|
1365
|
-
]);
|
|
1036
|
+
const Kind = leafPart("span", "operation-kind");
|
|
1037
|
+
const Type = leafPart("strong", "operation-type");
|
|
1038
|
+
const Record = leafPart("span", "operation-record");
|
|
1039
|
+
const Name = leafPart("span", "operation-name");
|
|
1040
|
+
const Reason$1 = leafPart("span", "operation-reason");
|
|
1041
|
+
function Item({ operation, ...props }) {
|
|
1042
|
+
const { messages } = useDomainKit();
|
|
1043
|
+
return usePart("li", props, { operation: operation._tag }, {
|
|
1044
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1045
|
+
/* @__PURE__ */ jsx(Kind, { children: messages.operation(operation) }),
|
|
1046
|
+
" ",
|
|
1047
|
+
/* @__PURE__ */ jsx(Type, { children: messages.recordType(operation.record) }),
|
|
1048
|
+
" ",
|
|
1049
|
+
/* @__PURE__ */ jsxs(Record, { children: [/* @__PURE__ */ jsx(Name, { children: operation.record.name }), /* @__PURE__ */ jsx(CopyValue, { value: DnsRecord.data(operation.record) })] }),
|
|
1050
|
+
operation._tag === "Conflict" ? /* @__PURE__ */ jsx(Reason$1, { children: messages.conflictReason(operation.reason) }) : null
|
|
1051
|
+
] }),
|
|
1052
|
+
"data-domainkit-part": "operation-item",
|
|
1053
|
+
"data-operation": operation._tag
|
|
1054
|
+
});
|
|
1366
1055
|
}
|
|
1367
|
-
function
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
retry: () => execute(Command$1.Plan()),
|
|
1376
|
-
state
|
|
1377
|
-
};
|
|
1056
|
+
function Root$4({ count = 0, kind, ...props }) {
|
|
1057
|
+
return usePart("ul", props, {
|
|
1058
|
+
count,
|
|
1059
|
+
kind
|
|
1060
|
+
}, {
|
|
1061
|
+
"data-domainkit-part": kind === "provisioning" ? "plan-operations" : "cleanup-operations",
|
|
1062
|
+
"data-kind": kind
|
|
1063
|
+
});
|
|
1378
1064
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1065
|
+
/** Every operation the plan holds, in plan order, so a customer reviews exactly what will run. */
|
|
1066
|
+
function List({ plan, ...props }) {
|
|
1067
|
+
return /* @__PURE__ */ jsx(Root$4, {
|
|
1068
|
+
count: plan.operations.length,
|
|
1069
|
+
kind: plan.kind,
|
|
1070
|
+
...props,
|
|
1071
|
+
children: plan.operations.map((operation) => /* @__PURE__ */ jsx(Item, { operation }, operation.id))
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
//#endregion
|
|
1075
|
+
//#region src/review.tsx
|
|
1076
|
+
/**
|
|
1077
|
+
* The review surface both `Provision` and `Cleanup` render: what the plan will do, the Approve
|
|
1078
|
+
* and Decline actions D35 defines, and the outcome. `kind` picks the wording; nothing else about
|
|
1079
|
+
* the two flows differs on screen.
|
|
1080
|
+
*/
|
|
1081
|
+
const busy = (status) => status === "Planning" || status === "Approving" || status === "Applying" || status === "Rejecting";
|
|
1082
|
+
/** What the flow is doing right now, or what it finished doing. */
|
|
1083
|
+
function Status$4({ controller, kind, ...props }) {
|
|
1084
|
+
const { messages } = useDomainKit();
|
|
1085
|
+
const state = controller.state;
|
|
1086
|
+
const text = () => {
|
|
1087
|
+
switch (state._tag) {
|
|
1088
|
+
case "Idle": return "";
|
|
1089
|
+
case "Planning": return kind === "provisioning" ? messages.planning : messages.planningCleanup;
|
|
1090
|
+
case "Planned": return kind === "provisioning" ? messages.planConsent : messages.cleanupConsent;
|
|
1091
|
+
case "Approving": return messages.approving;
|
|
1092
|
+
case "Applying": return kind === "provisioning" ? messages.applying : messages.cleaning;
|
|
1093
|
+
case "Rejecting": return messages.rejecting;
|
|
1094
|
+
case "Rejected": return messages.declinedBy(state.attempt.rejection?.actorId ?? "");
|
|
1095
|
+
case "Applied": return kind === "provisioning" ? messages.applied(state.receipt) : messages.cleaned(state.receipt);
|
|
1096
|
+
case "Failure": return "";
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
return usePart("p", props, { status: state._tag }, {
|
|
1100
|
+
children: text(),
|
|
1101
|
+
"data-domainkit-part": kind === "provisioning" ? "provisioning-status" : "cleanup-status",
|
|
1102
|
+
"data-state": state._tag,
|
|
1103
|
+
role: busy(state._tag) ? "status" : void 0
|
|
1383
1104
|
});
|
|
1384
1105
|
}
|
|
1385
|
-
|
|
1106
|
+
/** The failure sentence from the error's reason, with the retry the flow allows. */
|
|
1107
|
+
function Outcome$4({ controller, kind, ...props }) {
|
|
1386
1108
|
const { messages } = useDomainKit();
|
|
1387
|
-
|
|
1109
|
+
const readOnly = useReadOnly();
|
|
1110
|
+
const state = controller.state;
|
|
1111
|
+
const partial = state._tag === "Applied" && state.receipt.status === "partial";
|
|
1112
|
+
const element = usePart("p", props, { status: state._tag }, {
|
|
1113
|
+
children: state._tag === "Failure" ? /* @__PURE__ */ jsxs(Fragment, { children: [failure(state.error, messages), readOnly ? null : /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx("button", {
|
|
1114
|
+
"data-domainkit-part": kind === "provisioning" ? "provisioning-retry" : "cleanup-retry",
|
|
1115
|
+
onClick: controller.retry,
|
|
1116
|
+
type: "button",
|
|
1117
|
+
children: messages.retry
|
|
1118
|
+
})] })] }) : partial ? kind === "provisioning" ? messages.partiallyApplied : messages.partiallyCleaned : null,
|
|
1388
1119
|
"data-domainkit-part": "flow-outcome",
|
|
1389
1120
|
"data-tone": "danger",
|
|
1390
|
-
role: "alert"
|
|
1391
|
-
children: state._tag === "Partial" ? messages.recordsPartiallyApplied : state.message
|
|
1121
|
+
role: "alert"
|
|
1392
1122
|
});
|
|
1393
|
-
return null;
|
|
1123
|
+
return state._tag === "Failure" || partial ? element : null;
|
|
1394
1124
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1125
|
+
/**
|
|
1126
|
+
* Approve and Decline. Approve authorizes the digest and applies it; Decline records the refusal
|
|
1127
|
+
* and ends the attempt. Neither renders until there is a plan to act on.
|
|
1128
|
+
*/
|
|
1129
|
+
function Actions$2({ controller, kind, ...props }) {
|
|
1130
|
+
const { messages } = useDomainKit();
|
|
1131
|
+
const readOnly = useReadOnly();
|
|
1397
1132
|
const state = controller.state;
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1133
|
+
const plan = state._tag === "Planned" ? state.plan : null;
|
|
1134
|
+
const running = busy(state._tag);
|
|
1135
|
+
const element = usePart("div", props, { status: state._tag }, {
|
|
1136
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
|
|
1137
|
+
"data-domainkit-part": kind === "provisioning" ? "plan-apply" : "cleanup-apply",
|
|
1138
|
+
disabled: running || plan === null || plan.operations.length === 0,
|
|
1139
|
+
onClick: () => controller.approve(),
|
|
1140
|
+
type: "button",
|
|
1141
|
+
children: messages.approve
|
|
1142
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
1143
|
+
"data-domainkit-part": "plan-decline",
|
|
1144
|
+
disabled: running || plan === null,
|
|
1145
|
+
onClick: () => controller.reject(),
|
|
1146
|
+
type: "button",
|
|
1147
|
+
children: messages.decline
|
|
1148
|
+
})] }),
|
|
1149
|
+
"data-domainkit-part": "review-actions"
|
|
1150
|
+
});
|
|
1151
|
+
if (readOnly) return null;
|
|
1152
|
+
return plan === null && !running ? null : element;
|
|
1153
|
+
}
|
|
1154
|
+
/** The operations under review, or the reason there is nothing to review. */
|
|
1155
|
+
function Body({ controller, kind }) {
|
|
1156
|
+
const { messages } = useDomainKit();
|
|
1157
|
+
const state = controller.state;
|
|
1158
|
+
const plan = state._tag === "Planned" || state._tag === "Approving" || state._tag === "Applying" || state._tag === "Rejecting" || state._tag === "Rejected" ? state.plan : state._tag === "Applied" ? state.plan : null;
|
|
1159
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1160
|
+
"data-domainkit-part": "dialog-body",
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ jsx(Status$4, {
|
|
1163
|
+
controller,
|
|
1164
|
+
kind
|
|
1165
|
+
}),
|
|
1166
|
+
plan === null ? null : plan.operations.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
1167
|
+
"data-domainkit-part": "plan-empty",
|
|
1168
|
+
children: messages.noChanges
|
|
1169
|
+
}) : /* @__PURE__ */ jsx(List, { plan }),
|
|
1170
|
+
state._tag === "Rejected" && state.attempt.rejection?.reason != null ? /* @__PURE__ */ jsx("p", {
|
|
1171
|
+
"data-domainkit-part": "plan-decline-reason",
|
|
1172
|
+
children: messages.declineReason(state.attempt.rejection.reason)
|
|
1173
|
+
}) : null,
|
|
1174
|
+
/* @__PURE__ */ jsx(Outcome$4, {
|
|
1175
|
+
controller,
|
|
1176
|
+
kind
|
|
1177
|
+
})
|
|
1178
|
+
]
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
/** The review dialog. `render` swaps the surface; the contents stay the flow's. */
|
|
1182
|
+
function Dialog$4({ children, controller, kind, onOpenChange, open, render, trigger }) {
|
|
1183
|
+
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
1184
|
+
const readOnly = useReadOnly();
|
|
1185
|
+
const [uncontrolled, setUncontrolled] = useState(false);
|
|
1186
|
+
const isOpen = open ?? uncontrolled;
|
|
1187
|
+
const setOpen = (next) => {
|
|
1188
|
+
if (open === void 0) setUncontrolled(next);
|
|
1189
|
+
onOpenChange?.(next);
|
|
1190
|
+
};
|
|
1191
|
+
const running = busy(controller.state._tag);
|
|
1192
|
+
const body = children ?? /* @__PURE__ */ jsx(Body, {
|
|
1193
|
+
controller,
|
|
1194
|
+
kind
|
|
1195
|
+
});
|
|
1196
|
+
const title = kind === "provisioning" ? messages.planTitle : messages.cleanupTitle;
|
|
1197
|
+
const label = trigger ?? (kind === "provisioning" ? messages.reviewChanges : messages.cleanUp);
|
|
1198
|
+
if (readOnly) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1199
|
+
if (render !== void 0) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
|
|
1200
|
+
"data-domainkit-part": kind === "provisioning" ? "plan-trigger" : "cleanup-trigger",
|
|
1201
|
+
onClick: () => {
|
|
1202
|
+
setOpen(true);
|
|
1203
|
+
controller.plan();
|
|
1204
|
+
},
|
|
1205
|
+
type: "button",
|
|
1206
|
+
children: label
|
|
1207
|
+
}), render({
|
|
1208
|
+
children: body,
|
|
1209
|
+
open: isOpen
|
|
1210
|
+
})] });
|
|
1405
1211
|
return /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
1406
|
-
onOpenChange: (
|
|
1407
|
-
if (!
|
|
1408
|
-
|
|
1212
|
+
onOpenChange: (next, details) => {
|
|
1213
|
+
if (!next && running) {
|
|
1214
|
+
details.cancel();
|
|
1409
1215
|
return;
|
|
1410
1216
|
}
|
|
1411
|
-
|
|
1217
|
+
setOpen(next);
|
|
1412
1218
|
},
|
|
1413
|
-
open,
|
|
1219
|
+
open: isOpen,
|
|
1414
1220
|
children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
|
|
1415
|
-
"data-domainkit-part": "plan-trigger",
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
...trigger === void 0 ? {} : { render: trigger },
|
|
1419
|
-
children: messages.reviewDns
|
|
1221
|
+
"data-domainkit-part": kind === "provisioning" ? "plan-trigger" : "cleanup-trigger",
|
|
1222
|
+
onClick: controller.plan,
|
|
1223
|
+
children: label
|
|
1420
1224
|
}), /* @__PURE__ */ jsxs(Dialog.Portal, {
|
|
1421
1225
|
container: portalContainer,
|
|
1422
1226
|
children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
@@ -1426,7 +1230,7 @@ function Dialog$1({ controller, trigger }) {
|
|
|
1426
1230
|
style: themeStyle
|
|
1427
1231
|
}), /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
1428
1232
|
"data-color-scheme": colorScheme,
|
|
1429
|
-
"data-domainkit-part": "plan-dialog",
|
|
1233
|
+
"data-domainkit-part": kind === "provisioning" ? "plan-dialog" : "cleanup-dialog",
|
|
1430
1234
|
"data-domainkit-root": "",
|
|
1431
1235
|
style: themeStyle,
|
|
1432
1236
|
children: [
|
|
@@ -1436,203 +1240,911 @@ function Dialog$1({ controller, trigger }) {
|
|
|
1436
1240
|
"data-domainkit-part": "dialog-heading",
|
|
1437
1241
|
children: [/* @__PURE__ */ jsx(Dialog.Title, {
|
|
1438
1242
|
"data-domainkit-part": "dialog-title",
|
|
1439
|
-
children:
|
|
1243
|
+
children: title
|
|
1440
1244
|
}), /* @__PURE__ */ jsx(Dialog.Description, {
|
|
1441
1245
|
"data-domainkit-part": "dialog-description",
|
|
1442
|
-
children: messages.planConsent
|
|
1246
|
+
children: kind === "provisioning" ? messages.planConsent : messages.cleanupConsent
|
|
1443
1247
|
})]
|
|
1444
|
-
}),
|
|
1248
|
+
}), running ? null : /* @__PURE__ */ jsx(Dialog.Close, {
|
|
1445
1249
|
"aria-label": messages.close,
|
|
1446
1250
|
"data-domainkit-part": "dialog-close",
|
|
1447
1251
|
children: "×"
|
|
1448
1252
|
})]
|
|
1449
1253
|
}),
|
|
1254
|
+
body,
|
|
1450
1255
|
/* @__PURE__ */ jsxs("div", {
|
|
1451
|
-
"data-domainkit-part": "dialog-body",
|
|
1452
|
-
children: [plan === void 0 ? /* @__PURE__ */ jsx("p", {
|
|
1453
|
-
"data-domainkit-part": "dialog-progress",
|
|
1454
|
-
role: "status",
|
|
1455
|
-
children: messages.planningDns
|
|
1456
|
-
}) : /* @__PURE__ */ jsx(List, {
|
|
1457
|
-
lifecycle: "provisioning",
|
|
1458
|
-
operations: plan.operations
|
|
1459
|
-
}), /* @__PURE__ */ jsx(Outcome$1, { state })]
|
|
1460
|
-
}),
|
|
1461
|
-
/* @__PURE__ */ jsx("div", {
|
|
1462
1256
|
"data-domainkit-part": "dialog-footer",
|
|
1463
|
-
children:
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
children: state._tag === "Applying" ? messages.applyingDns : messages.planningDns
|
|
1468
|
-
}) : state._tag === "Review" && plan !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Dialog.Close, {
|
|
1257
|
+
children: [/* @__PURE__ */ jsx(Actions$2, {
|
|
1258
|
+
controller,
|
|
1259
|
+
kind
|
|
1260
|
+
}), running ? null : /* @__PURE__ */ jsx(Dialog.Close, {
|
|
1469
1261
|
"data-domainkit-part": "dialog-cancel",
|
|
1470
1262
|
children: messages.cancel
|
|
1471
|
-
})
|
|
1472
|
-
"data-domainkit-part": "plan-apply",
|
|
1473
|
-
disabled: isNoopOnly || plan.operations.some((operation) => operation._tag === "Conflict"),
|
|
1474
|
-
onClick: () => controller.apply(),
|
|
1475
|
-
type: "button",
|
|
1476
|
-
children: isNoopOnly ? messages.noChanges : messages.applyDns
|
|
1477
|
-
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Dialog.Close, {
|
|
1478
|
-
"data-domainkit-part": "dialog-cancel",
|
|
1479
|
-
children: messages.close
|
|
1480
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
1481
|
-
"data-domainkit-part": "provisioning-retry",
|
|
1482
|
-
onClick: () => controller.retry(),
|
|
1483
|
-
type: "button",
|
|
1484
|
-
children: messages.retry
|
|
1485
|
-
})] })
|
|
1263
|
+
})]
|
|
1486
1264
|
})
|
|
1487
1265
|
]
|
|
1488
1266
|
})]
|
|
1489
1267
|
})]
|
|
1490
1268
|
});
|
|
1491
1269
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1270
|
+
//#endregion
|
|
1271
|
+
//#region src/cleanup.tsx
|
|
1272
|
+
var cleanup_exports = /* @__PURE__ */ __exportAll({
|
|
1273
|
+
Actions: () => Actions$1,
|
|
1274
|
+
Dialog: () => Dialog$3,
|
|
1275
|
+
Flow: () => Flow$3,
|
|
1276
|
+
Outcome: () => Outcome$3,
|
|
1277
|
+
Root: () => Root$3,
|
|
1278
|
+
State: () => State$2,
|
|
1279
|
+
Status: () => Status$3,
|
|
1280
|
+
useController: () => useController$3
|
|
1281
|
+
});
|
|
1282
|
+
/**
|
|
1283
|
+
* Cleanup is bound to a receipt: it removes only what an apply proved DomainKit created. When the
|
|
1284
|
+
* host does not name one, the controller reads the domain's latest from the snapshot.
|
|
1285
|
+
*/
|
|
1286
|
+
function useController$3({ domain, onCleaned, receiptId }) {
|
|
1287
|
+
const { transport } = useDomainKit();
|
|
1288
|
+
const group = transport.cleanup;
|
|
1289
|
+
const connection = transport.connection;
|
|
1290
|
+
return useAttempt({
|
|
1291
|
+
domain,
|
|
1292
|
+
key: [domain, receiptId ?? ""].join("|"),
|
|
1293
|
+
done: (receipt) => Event.Cleaned({
|
|
1294
|
+
domain,
|
|
1295
|
+
receipt
|
|
1296
|
+
}),
|
|
1297
|
+
group,
|
|
1298
|
+
onDone: onCleaned,
|
|
1299
|
+
plan: useCallback(() => {
|
|
1300
|
+
if (group === void 0) return null;
|
|
1301
|
+
if (receiptId !== void 0) return group.plan(receiptId);
|
|
1302
|
+
if (connection === void 0) return null;
|
|
1303
|
+
return Effect.flatMap(connection.inspect(domain), (snapshot) => snapshot.lastReceiptId === null ? Effect.fail(new DomainKit.Error({ reason: new Reason.NotFound({
|
|
1304
|
+
entity: "receipt",
|
|
1305
|
+
id: snapshot.domain
|
|
1306
|
+
}) })) : group.plan(Receipt.ReceiptId.make(snapshot.lastReceiptId)));
|
|
1307
|
+
}, [
|
|
1308
|
+
connection,
|
|
1309
|
+
domain,
|
|
1310
|
+
group,
|
|
1311
|
+
receiptId
|
|
1312
|
+
])
|
|
1501
1313
|
});
|
|
1502
1314
|
}
|
|
1503
|
-
function
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1315
|
+
function Root$3({ controller, ...props }) {
|
|
1316
|
+
return usePart("div", props, { status: controller.state._tag }, {
|
|
1317
|
+
"data-domainkit-part": "cleanup-flow",
|
|
1318
|
+
"data-state": controller.state._tag
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
function Dialog$3(props) {
|
|
1322
|
+
return /* @__PURE__ */ jsx(Dialog$4, {
|
|
1508
1323
|
...props,
|
|
1509
|
-
|
|
1510
|
-
controller,
|
|
1511
|
-
...trigger === void 0 ? {} : { trigger }
|
|
1512
|
-
})]
|
|
1324
|
+
kind: "cleanup"
|
|
1513
1325
|
});
|
|
1514
1326
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1327
|
+
function Actions$1(props) {
|
|
1328
|
+
return /* @__PURE__ */ jsx(Actions$2, {
|
|
1329
|
+
...props,
|
|
1330
|
+
kind: "cleanup"
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
function Outcome$3(props) {
|
|
1334
|
+
return /* @__PURE__ */ jsx(Outcome$4, {
|
|
1335
|
+
...props,
|
|
1336
|
+
kind: "cleanup"
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
function Status$3(props) {
|
|
1340
|
+
return /* @__PURE__ */ jsx(Status$4, {
|
|
1341
|
+
...props,
|
|
1342
|
+
kind: "cleanup"
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
/** Cleanup on its own: a trigger that plans the removal, then the same review dialog. */
|
|
1346
|
+
function Flow$3({ domain, onCleaned, receiptId, trigger, ...props }) {
|
|
1347
|
+
const controller = useController$3({
|
|
1348
|
+
domain,
|
|
1349
|
+
...onCleaned === void 0 ? {} : { onCleaned },
|
|
1350
|
+
...receiptId === void 0 ? {} : { receiptId }
|
|
1351
|
+
});
|
|
1352
|
+
return /* @__PURE__ */ jsxs(Root$3, {
|
|
1353
|
+
controller,
|
|
1354
|
+
...props,
|
|
1355
|
+
children: [/* @__PURE__ */ jsx(Dialog$3, {
|
|
1356
|
+
controller,
|
|
1357
|
+
...trigger === void 0 ? {} : { trigger }
|
|
1358
|
+
}), /* @__PURE__ */ jsx(Outcome$3, { controller })]
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
//#endregion
|
|
1362
|
+
//#region src/provider.tsx
|
|
1363
|
+
var provider_exports = /* @__PURE__ */ __exportAll({ Mark: () => Mark });
|
|
1364
|
+
const key = (providerId) => providerId.trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "");
|
|
1365
|
+
/** No network call: the fallback is the provider's own initial, drawn with the theme's tokens. */
|
|
1366
|
+
const monogram = (provider) => provider.name.trim().charAt(0).toUpperCase() || "?";
|
|
1367
|
+
/**
|
|
1368
|
+
* A provider's artwork. `DomainKit.Root`'s `marks` decides what a provider looks like; without an
|
|
1369
|
+
* entry the mark is the provider's initial. Nothing is fetched at render time.
|
|
1370
|
+
*/
|
|
1371
|
+
function Mark({ provider, ...props }) {
|
|
1372
|
+
const { marks } = useDomainKit();
|
|
1373
|
+
const replacement = marks[provider.id];
|
|
1374
|
+
const content = typeof replacement === "function" ? replacement(provider) : replacement ?? monogram(provider);
|
|
1375
|
+
return usePart("span", props, { providerId: provider.id }, {
|
|
1376
|
+
"aria-label": provider.name,
|
|
1377
|
+
children: content,
|
|
1378
|
+
"data-domainkit-part": "provider-mark",
|
|
1379
|
+
"data-domainkit-provider": key(provider.id),
|
|
1380
|
+
role: "img"
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
//#endregion
|
|
1384
|
+
//#region src/connect.tsx
|
|
1385
|
+
var connect_exports = /* @__PURE__ */ __exportAll({
|
|
1386
|
+
Card: () => Card,
|
|
1387
|
+
Dialog: () => Dialog$2,
|
|
1388
|
+
Flow: () => Flow$2,
|
|
1389
|
+
Form: () => Form,
|
|
1390
|
+
Outcome: () => Outcome$2,
|
|
1391
|
+
Root: () => Root$2,
|
|
1392
|
+
State: () => State$1,
|
|
1393
|
+
Status: () => Status$2,
|
|
1394
|
+
useController: () => useController$2
|
|
1395
|
+
});
|
|
1396
|
+
const State$1 = Data.taggedEnum();
|
|
1397
|
+
/** Read at connect time, not at render, so it is the page the customer is actually on. */
|
|
1398
|
+
const currentUrl = () => typeof window === "undefined" ? null : window.location.href;
|
|
1399
|
+
const snapshotOf = (state) => {
|
|
1400
|
+
switch (state._tag) {
|
|
1401
|
+
case "Connected":
|
|
1402
|
+
case "Reconnect":
|
|
1403
|
+
case "Disconnected": return state.snapshot;
|
|
1404
|
+
case "Loading":
|
|
1405
|
+
case "Submitting":
|
|
1406
|
+
case "SelectionRequired": return state.snapshot;
|
|
1407
|
+
case "Redirecting":
|
|
1408
|
+
case "Failure": return null;
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
const settled = (snapshot, discovery) => {
|
|
1412
|
+
switch (snapshot.status) {
|
|
1413
|
+
case "connected": return State$1.Connected({ snapshot });
|
|
1414
|
+
case "reconnect": return State$1.Reconnect({ snapshot });
|
|
1415
|
+
case "disconnected": return State$1.Disconnected({
|
|
1416
|
+
discovery,
|
|
1417
|
+
snapshot
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
/**
|
|
1422
|
+
* The domain's connection, and the four ways to change it. Discovery runs on mount whenever the
|
|
1423
|
+
* transport declares it and the domain has no connection yet; a discovery failure is not the
|
|
1424
|
+
* customer's problem, so the provider list still renders.
|
|
1425
|
+
*/
|
|
1426
|
+
function useController$2({ domain, returnTo }) {
|
|
1427
|
+
const { emit, navigate, revision, transport } = useDomainKit();
|
|
1428
|
+
const readOnly = useReadOnly();
|
|
1429
|
+
const connection = transport.connection;
|
|
1430
|
+
const runner = useRunner();
|
|
1431
|
+
const [state, setState] = useState(State$1.Loading({ snapshot: null }));
|
|
1432
|
+
const held = useRef({
|
|
1433
|
+
discovery: null,
|
|
1434
|
+
domain,
|
|
1435
|
+
snapshot: null
|
|
1436
|
+
});
|
|
1437
|
+
const lastCommand = useRef(null);
|
|
1438
|
+
const [inspected, setInspected] = useState(domain);
|
|
1439
|
+
if (inspected !== domain) {
|
|
1440
|
+
setInspected(domain);
|
|
1441
|
+
runner.cancel();
|
|
1442
|
+
held.current = {
|
|
1443
|
+
discovery: null,
|
|
1444
|
+
domain,
|
|
1445
|
+
snapshot: null
|
|
1446
|
+
};
|
|
1447
|
+
lastCommand.current = null;
|
|
1448
|
+
setState(State$1.Loading({ snapshot: null }));
|
|
1449
|
+
}
|
|
1450
|
+
const onFailure = useCallback((error) => {
|
|
1451
|
+
setState(State$1.Failure({ error }));
|
|
1452
|
+
emit(Event.Failed({
|
|
1453
|
+
domain,
|
|
1454
|
+
error
|
|
1455
|
+
}));
|
|
1456
|
+
}, [domain, emit]);
|
|
1457
|
+
const load = useCallback(() => {
|
|
1458
|
+
if (connection === void 0) return;
|
|
1459
|
+
lastCommand.current = null;
|
|
1460
|
+
held.current = {
|
|
1461
|
+
discovery: null,
|
|
1462
|
+
domain,
|
|
1463
|
+
snapshot: null
|
|
1561
1464
|
};
|
|
1465
|
+
setState((previous) => State$1.Loading({ snapshot: snapshotOf(previous) }));
|
|
1466
|
+
runner.run(Effect.flatMap(connection.inspect(domain), (snapshot) => snapshot.status === "disconnected" ? Effect.map(connection.discover(domain).pipe(Effect.catch(() => Effect.succeed(null))), (discovery) => ({
|
|
1467
|
+
discovery,
|
|
1468
|
+
snapshot
|
|
1469
|
+
})) : Effect.succeed({
|
|
1470
|
+
discovery: null,
|
|
1471
|
+
snapshot
|
|
1472
|
+
})), {
|
|
1473
|
+
onFailure,
|
|
1474
|
+
onSuccess: ({ discovery, snapshot }) => {
|
|
1475
|
+
if (held.current.domain !== domain) return;
|
|
1476
|
+
held.current = {
|
|
1477
|
+
discovery,
|
|
1478
|
+
domain,
|
|
1479
|
+
snapshot
|
|
1480
|
+
};
|
|
1481
|
+
setState(settled(snapshot, discovery));
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1562
1484
|
}, [
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1485
|
+
connection,
|
|
1486
|
+
domain,
|
|
1487
|
+
onFailure,
|
|
1488
|
+
runner
|
|
1489
|
+
]);
|
|
1490
|
+
useEffect(load, [load, revision]);
|
|
1491
|
+
const started = useCallback((result) => {
|
|
1492
|
+
if (held.current.domain !== domain) return;
|
|
1493
|
+
switch (result._tag) {
|
|
1494
|
+
case "Connected":
|
|
1495
|
+
held.current = {
|
|
1496
|
+
discovery: null,
|
|
1497
|
+
domain,
|
|
1498
|
+
snapshot: result.snapshot
|
|
1499
|
+
};
|
|
1500
|
+
setState(settled(result.snapshot, null));
|
|
1501
|
+
if (result.snapshot.connectionId !== null) emit(Event.Connected({
|
|
1502
|
+
connectionId: result.snapshot.connectionId,
|
|
1503
|
+
domain,
|
|
1504
|
+
snapshot: result.snapshot
|
|
1505
|
+
}));
|
|
1506
|
+
return;
|
|
1507
|
+
case "Redirect":
|
|
1508
|
+
setState(State$1.Redirecting({ url: result.authorizationUrl }));
|
|
1509
|
+
navigate(result.authorizationUrl);
|
|
1510
|
+
return;
|
|
1511
|
+
case "SelectionRequired":
|
|
1512
|
+
setState(State$1.SelectionRequired({
|
|
1513
|
+
candidates: result.candidates,
|
|
1514
|
+
connectionId: result.connectionId,
|
|
1515
|
+
snapshot: held.current.snapshot
|
|
1516
|
+
}));
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
}, [
|
|
1520
|
+
domain,
|
|
1521
|
+
emit,
|
|
1522
|
+
navigate
|
|
1523
|
+
]);
|
|
1524
|
+
const submit = useCallback((effect) => {
|
|
1525
|
+
if (held.current.domain !== domain) return;
|
|
1526
|
+
const command = () => {
|
|
1527
|
+
setState(State$1.Submitting({ snapshot: held.current.snapshot }));
|
|
1528
|
+
runner.run(effect, {
|
|
1529
|
+
onFailure,
|
|
1530
|
+
onSuccess: started
|
|
1531
|
+
});
|
|
1532
|
+
};
|
|
1533
|
+
lastCommand.current = {
|
|
1534
|
+
domain,
|
|
1535
|
+
run: command
|
|
1536
|
+
};
|
|
1537
|
+
command();
|
|
1538
|
+
}, [
|
|
1539
|
+
domain,
|
|
1540
|
+
onFailure,
|
|
1541
|
+
runner,
|
|
1542
|
+
started
|
|
1543
|
+
]);
|
|
1544
|
+
const connect = useCallback((input) => {
|
|
1545
|
+
if (connection === void 0) return;
|
|
1546
|
+
const destination = input.returnTo ?? (returnTo === void 0 ? currentUrl() : returnTo);
|
|
1547
|
+
const interactive = destination === null ? {} : { returnTo: destination };
|
|
1548
|
+
const method = input.method === "token" ? Transport.Method.token(input.values ?? {}) : input.method === "oauth" ? Transport.Method.oauth(interactive) : Transport.Method.integration(interactive);
|
|
1549
|
+
submit(connection.start({
|
|
1550
|
+
domain,
|
|
1551
|
+
method,
|
|
1552
|
+
provider: input.provider
|
|
1553
|
+
}));
|
|
1554
|
+
}, [
|
|
1555
|
+
connection,
|
|
1556
|
+
domain,
|
|
1557
|
+
returnTo,
|
|
1558
|
+
submit
|
|
1559
|
+
]);
|
|
1560
|
+
const reuse = useCallback((input) => {
|
|
1561
|
+
if (connection === void 0) return;
|
|
1562
|
+
submit(connection.attach({
|
|
1563
|
+
connectionId: input.connectionId,
|
|
1564
|
+
domain,
|
|
1565
|
+
...input.zone === void 0 ? {} : { zone: input.zone }
|
|
1566
|
+
}));
|
|
1567
|
+
}, [
|
|
1568
|
+
connection,
|
|
1569
|
+
domain,
|
|
1570
|
+
submit
|
|
1571
|
+
]);
|
|
1572
|
+
const select = useCallback((zone) => {
|
|
1573
|
+
if (state._tag !== "SelectionRequired") return;
|
|
1574
|
+
reuse({
|
|
1575
|
+
connectionId: state.connectionId,
|
|
1576
|
+
zone
|
|
1577
|
+
});
|
|
1578
|
+
}, [reuse, state]);
|
|
1579
|
+
const release = useCallback((effect, event) => {
|
|
1580
|
+
if (held.current.domain !== domain) return;
|
|
1581
|
+
const command = () => {
|
|
1582
|
+
setState(State$1.Submitting({ snapshot: held.current.snapshot }));
|
|
1583
|
+
runner.run(effect, {
|
|
1584
|
+
onFailure,
|
|
1585
|
+
onSuccess: () => {
|
|
1586
|
+
emit(event);
|
|
1587
|
+
load();
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
};
|
|
1591
|
+
lastCommand.current = {
|
|
1592
|
+
domain,
|
|
1593
|
+
run: command
|
|
1594
|
+
};
|
|
1595
|
+
command();
|
|
1596
|
+
}, [
|
|
1597
|
+
domain,
|
|
1598
|
+
emit,
|
|
1599
|
+
load,
|
|
1600
|
+
onFailure,
|
|
1601
|
+
runner
|
|
1602
|
+
]);
|
|
1603
|
+
const detach = useCallback(() => {
|
|
1604
|
+
const attachmentId = held.current.snapshot?.attachmentId;
|
|
1605
|
+
if (connection === void 0 || attachmentId == null || held.current.domain !== domain) return;
|
|
1606
|
+
release(connection.detach(attachmentId), Event.Detached({ domain }));
|
|
1607
|
+
}, [
|
|
1608
|
+
connection,
|
|
1609
|
+
domain,
|
|
1610
|
+
release
|
|
1611
|
+
]);
|
|
1612
|
+
const disconnect = useCallback(() => {
|
|
1613
|
+
const connectionId = held.current.snapshot?.connectionId;
|
|
1614
|
+
if (connection === void 0 || connectionId == null || held.current.domain !== domain) return;
|
|
1615
|
+
release(connection.disconnect(connectionId), Event.Disconnected({
|
|
1616
|
+
connectionId,
|
|
1617
|
+
domain
|
|
1618
|
+
}));
|
|
1619
|
+
}, [
|
|
1620
|
+
connection,
|
|
1621
|
+
domain,
|
|
1622
|
+
release
|
|
1623
|
+
]);
|
|
1624
|
+
const retry = useCallback(() => {
|
|
1625
|
+
const command = lastCommand.current;
|
|
1626
|
+
if (readOnly || command === null || command.domain !== domain) load();
|
|
1627
|
+
else command.run();
|
|
1628
|
+
}, [
|
|
1629
|
+
domain,
|
|
1630
|
+
load,
|
|
1631
|
+
readOnly
|
|
1569
1632
|
]);
|
|
1570
|
-
}
|
|
1571
|
-
function useController(config) {
|
|
1572
|
-
const model = useModel(config);
|
|
1573
|
-
const state = useAtomValue(model.state);
|
|
1574
|
-
const dispatch = useAtomSet(model.command);
|
|
1575
|
-
const observe = () => dispatch(Command.Observe());
|
|
1576
|
-
const reset = () => dispatch(Command.Reset());
|
|
1577
1633
|
return {
|
|
1578
|
-
|
|
1579
|
-
|
|
1634
|
+
connect,
|
|
1635
|
+
detach,
|
|
1636
|
+
disconnect,
|
|
1637
|
+
discovery: state._tag === "Disconnected" ? state.discovery : null,
|
|
1638
|
+
providers: snapshotOf(state)?.providers ?? [],
|
|
1639
|
+
refresh: load,
|
|
1640
|
+
retry,
|
|
1641
|
+
reuse,
|
|
1642
|
+
select,
|
|
1643
|
+
snapshot: snapshotOf(state),
|
|
1580
1644
|
state
|
|
1581
1645
|
};
|
|
1582
1646
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
case "Found":
|
|
1588
|
-
case "Missing": return;
|
|
1589
|
-
default: return evidence;
|
|
1590
|
-
}
|
|
1591
|
-
};
|
|
1592
|
-
const observationGroups = (observation) => [{
|
|
1593
|
-
evidence: observation.provider,
|
|
1594
|
-
label: "Provider"
|
|
1595
|
-
}, {
|
|
1596
|
-
evidence: observation.publicDns,
|
|
1597
|
-
label: "Public DNS"
|
|
1598
|
-
}].filter((group) => group.evidence.length > 0);
|
|
1599
|
-
function Root({ status, ...props }) {
|
|
1600
|
-
return usePart("div", props, { status }, {
|
|
1601
|
-
"data-domainkit-part": "verification-status",
|
|
1602
|
-
"data-state": status
|
|
1647
|
+
function Root$2({ controller, ...props }) {
|
|
1648
|
+
return usePart("div", props, { status: controller.state._tag }, {
|
|
1649
|
+
"data-domainkit-part": "connection-root",
|
|
1650
|
+
"data-state": controller.state._tag
|
|
1603
1651
|
});
|
|
1604
1652
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
1618
|
-
"data-domainkit-part": "observation-record",
|
|
1619
|
-
children: evidence.recordId
|
|
1620
|
-
}), /* @__PURE__ */ jsx(Status$1, { evidence })]
|
|
1621
|
-
}), note === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
1622
|
-
"data-domainkit-part": "observation-note",
|
|
1623
|
-
children: note
|
|
1624
|
-
})] }, `${evidence._tag}-${evidence.recordId}-${index}`);
|
|
1625
|
-
}) })]
|
|
1626
|
-
}, group.label))
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
function Outcome({ state }) {
|
|
1630
|
-
if (state._tag !== "Failed") return null;
|
|
1631
|
-
return /* @__PURE__ */ jsx("p", {
|
|
1653
|
+
/** The failure sentence, chosen by the error's reason, plus the retry that reason allows. */
|
|
1654
|
+
function Outcome$2({ controller, ...props }) {
|
|
1655
|
+
const { messages } = useDomainKit();
|
|
1656
|
+
const readOnly = useReadOnly();
|
|
1657
|
+
const state = controller.state;
|
|
1658
|
+
const element = usePart("p", props, { status: state._tag }, {
|
|
1659
|
+
children: state._tag === "Failure" ? /* @__PURE__ */ jsxs(Fragment, { children: [failure(state.error, messages), readOnly ? null : /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx("button", {
|
|
1660
|
+
"data-domainkit-part": "connection-retry",
|
|
1661
|
+
onClick: controller.retry,
|
|
1662
|
+
type: "button",
|
|
1663
|
+
children: messages.retry
|
|
1664
|
+
})] })] }) : null,
|
|
1632
1665
|
"data-domainkit-part": "flow-outcome",
|
|
1633
1666
|
"data-tone": "danger",
|
|
1634
|
-
role: "alert"
|
|
1635
|
-
|
|
1667
|
+
role: "alert"
|
|
1668
|
+
});
|
|
1669
|
+
return state._tag === "Failure" ? element : null;
|
|
1670
|
+
}
|
|
1671
|
+
function Status$2({ controller, ...props }) {
|
|
1672
|
+
const { messages } = useDomainKit();
|
|
1673
|
+
const state = controller.state;
|
|
1674
|
+
const provider = controller.snapshot?.provider ?? "";
|
|
1675
|
+
const text = () => {
|
|
1676
|
+
switch (state._tag) {
|
|
1677
|
+
case "Loading": return messages.loading;
|
|
1678
|
+
case "Submitting": return messages.connecting;
|
|
1679
|
+
case "Redirecting": return messages.redirecting;
|
|
1680
|
+
case "Connected": return messages.connectedTo(provider);
|
|
1681
|
+
case "Reconnect": return messages.reconnectRequired(provider);
|
|
1682
|
+
case "SelectionRequired": return messages.chooseZone;
|
|
1683
|
+
case "Disconnected": return messages.notConnected;
|
|
1684
|
+
case "Failure": return "";
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
return usePart("p", props, { status: state._tag }, {
|
|
1688
|
+
children: text(),
|
|
1689
|
+
"data-domainkit-part": "connection-status",
|
|
1690
|
+
"data-state": state._tag,
|
|
1691
|
+
role: state._tag === "Submitting" || state._tag === "Loading" ? "status" : void 0
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* One auth method, rendered from its descriptor. A token method draws an input per declared
|
|
1696
|
+
* field, so a provider that needs an account id alongside a token needs no code here.
|
|
1697
|
+
*/
|
|
1698
|
+
function Method({ controller, method, provider }) {
|
|
1699
|
+
const { messages } = useDomainKit();
|
|
1700
|
+
const icons = useIcons();
|
|
1701
|
+
const busy = controller.state._tag === "Submitting";
|
|
1702
|
+
if (method.fields === null) return /* @__PURE__ */ jsx("button", {
|
|
1703
|
+
"data-domainkit-part": method.kind === "oauth" ? "oauth-connect" : "integration-connect",
|
|
1704
|
+
"data-provider": provider.id,
|
|
1705
|
+
disabled: busy,
|
|
1706
|
+
onClick: () => controller.connect({
|
|
1707
|
+
method: method.kind,
|
|
1708
|
+
provider: provider.id
|
|
1709
|
+
}),
|
|
1710
|
+
type: "button",
|
|
1711
|
+
children: messages.connectWith(method.label)
|
|
1712
|
+
});
|
|
1713
|
+
const fields = method.fields;
|
|
1714
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
1715
|
+
"data-domainkit-part": "token-connect",
|
|
1716
|
+
"data-provider": provider.id,
|
|
1717
|
+
onSubmit: (event) => {
|
|
1718
|
+
event.preventDefault();
|
|
1719
|
+
const data = new FormData(event.currentTarget);
|
|
1720
|
+
const values = {};
|
|
1721
|
+
for (const field of fields) {
|
|
1722
|
+
const value = data.get(field.name);
|
|
1723
|
+
if (typeof value === "string" && (value !== "" || field.required)) values[field.name] = value;
|
|
1724
|
+
}
|
|
1725
|
+
controller.connect({
|
|
1726
|
+
method: method.kind,
|
|
1727
|
+
provider: provider.id,
|
|
1728
|
+
values
|
|
1729
|
+
});
|
|
1730
|
+
},
|
|
1731
|
+
children: [
|
|
1732
|
+
fields.map((field) => /* @__PURE__ */ jsxs("label", {
|
|
1733
|
+
"data-domainkit-part": "token-field",
|
|
1734
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1735
|
+
"data-domainkit-part": "token-field-label",
|
|
1736
|
+
children: [messages.fieldLabel(field.name), field.required ? null : /* @__PURE__ */ jsx("span", {
|
|
1737
|
+
"data-domainkit-part": "token-field-optional",
|
|
1738
|
+
children: messages.optionalField
|
|
1739
|
+
})]
|
|
1740
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
1741
|
+
autoComplete: "off",
|
|
1742
|
+
"data-domainkit-part": "token-field-input",
|
|
1743
|
+
name: field.name,
|
|
1744
|
+
required: field.required,
|
|
1745
|
+
type: field.secret ? "password" : "text"
|
|
1746
|
+
})]
|
|
1747
|
+
}, field.name)),
|
|
1748
|
+
method.docsUrl === null ? null : /* @__PURE__ */ jsxs("a", {
|
|
1749
|
+
"data-domainkit-part": "token-docs",
|
|
1750
|
+
href: method.docsUrl,
|
|
1751
|
+
rel: "noreferrer",
|
|
1752
|
+
target: "_blank",
|
|
1753
|
+
children: [messages.getToken, /* @__PURE__ */ jsx("span", {
|
|
1754
|
+
"aria-hidden": "true",
|
|
1755
|
+
"data-icon": "inline-end",
|
|
1756
|
+
children: icons.external
|
|
1757
|
+
})]
|
|
1758
|
+
}),
|
|
1759
|
+
/* @__PURE__ */ jsx("button", {
|
|
1760
|
+
"data-domainkit-part": "token-submit",
|
|
1761
|
+
disabled: busy,
|
|
1762
|
+
type: "submit",
|
|
1763
|
+
children: messages.connectWith(method.label)
|
|
1764
|
+
})
|
|
1765
|
+
]
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Everything a disconnected domain can do: a connection discovery already found, the connections
|
|
1770
|
+
* this owner already has, then each provider's declared methods.
|
|
1771
|
+
*/
|
|
1772
|
+
function Form({ controller, ...props }) {
|
|
1773
|
+
const { messages } = useDomainKit();
|
|
1774
|
+
const state = controller.state;
|
|
1775
|
+
const snapshot = controller.snapshot;
|
|
1776
|
+
const discovery = controller.discovery;
|
|
1777
|
+
const candidates = state._tag === "SelectionRequired" ? state.candidates.map((candidate) => ({
|
|
1778
|
+
...candidate,
|
|
1779
|
+
connectionId: state.connectionId
|
|
1780
|
+
})) : discovery !== null && discovery._tag === "SelectionRequired" ? discovery.candidates : [];
|
|
1781
|
+
const resolved = discovery !== null && discovery._tag === "Resolved" ? discovery : null;
|
|
1782
|
+
const reusable = snapshot?.reusable ?? [];
|
|
1783
|
+
const providers = controller.providers;
|
|
1784
|
+
return usePart("div", props, { status: state._tag }, {
|
|
1785
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1786
|
+
resolved === null ? null : /* @__PURE__ */ jsxs("section", {
|
|
1787
|
+
"data-domainkit-part": "discovery-resolved",
|
|
1788
|
+
children: [/* @__PURE__ */ jsx("p", { children: messages.discoveredConnection(resolved.label) }), /* @__PURE__ */ jsx("button", {
|
|
1789
|
+
"data-domainkit-part": "attach-target",
|
|
1790
|
+
onClick: () => controller.reuse({
|
|
1791
|
+
connectionId: resolved.connectionId,
|
|
1792
|
+
zone: resolved.zone
|
|
1793
|
+
}),
|
|
1794
|
+
type: "button",
|
|
1795
|
+
children: messages.useConnection(resolved.label)
|
|
1796
|
+
})]
|
|
1797
|
+
}),
|
|
1798
|
+
candidates.length === 0 ? null : /* @__PURE__ */ jsxs("section", {
|
|
1799
|
+
"data-domainkit-part": "discovery-candidates",
|
|
1800
|
+
children: [/* @__PURE__ */ jsx("p", { children: state._tag === "SelectionRequired" ? messages.chooseZone : messages.discoveryAmbiguous }), /* @__PURE__ */ jsx("div", {
|
|
1801
|
+
"data-domainkit-part": "target-list",
|
|
1802
|
+
"data-state": "ambiguous",
|
|
1803
|
+
children: candidates.map((candidate) => /* @__PURE__ */ jsx("button", {
|
|
1804
|
+
"data-domainkit-part": "attach-target",
|
|
1805
|
+
onClick: () => controller.reuse({
|
|
1806
|
+
connectionId: candidate.connectionId,
|
|
1807
|
+
zone: candidate.zone
|
|
1808
|
+
}),
|
|
1809
|
+
type: "button",
|
|
1810
|
+
children: messages.useConnection(candidate.label)
|
|
1811
|
+
}, `${candidate.connectionId}:${candidate.zone}`))
|
|
1812
|
+
})]
|
|
1813
|
+
}),
|
|
1814
|
+
reusable.length === 0 ? null : /* @__PURE__ */ jsxs("section", {
|
|
1815
|
+
"data-domainkit-part": "reusable-connection",
|
|
1816
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1817
|
+
"data-domainkit-part": "reusable-connection-heading",
|
|
1818
|
+
children: /* @__PURE__ */ jsx("strong", { children: messages.reusableConnections })
|
|
1819
|
+
}), reusable.map((connection) => /* @__PURE__ */ jsx("button", {
|
|
1820
|
+
"data-connection-id": connection.connectionId,
|
|
1821
|
+
"data-domainkit-part": "attach-target",
|
|
1822
|
+
onClick: () => controller.reuse({ connectionId: connection.connectionId }),
|
|
1823
|
+
type: "button",
|
|
1824
|
+
children: messages.useConnection(connection.provider)
|
|
1825
|
+
}, connection.connectionId))]
|
|
1826
|
+
}),
|
|
1827
|
+
providers.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
1828
|
+
"data-domainkit-part": "target-unavailable",
|
|
1829
|
+
children: messages.noProviders
|
|
1830
|
+
}) : providers.map((provider) => /* @__PURE__ */ jsxs("section", {
|
|
1831
|
+
"data-domainkit-part": "provider-authentication",
|
|
1832
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1833
|
+
"data-domainkit-part": "provider-heading",
|
|
1834
|
+
children: [/* @__PURE__ */ jsx(Mark, { provider }), /* @__PURE__ */ jsx("strong", { children: provider.name })]
|
|
1835
|
+
}), provider.methods.map((method) => /* @__PURE__ */ jsx(Method, {
|
|
1836
|
+
controller,
|
|
1837
|
+
method,
|
|
1838
|
+
provider
|
|
1839
|
+
}, `${provider.id}:${method.kind}`))]
|
|
1840
|
+
}, provider.id))
|
|
1841
|
+
] }),
|
|
1842
|
+
"data-domainkit-part": "connection-form"
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
/** The connect surface. Without `render` it is a Base UI dialog behind `trigger`. */
|
|
1846
|
+
function Dialog$2({ children, controller, render, title, trigger }) {
|
|
1847
|
+
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
1848
|
+
const readOnly = useReadOnly();
|
|
1849
|
+
const [open, setOpen] = useState(false);
|
|
1850
|
+
const busy = controller.state._tag === "Submitting";
|
|
1851
|
+
const snapshot = controller.snapshot;
|
|
1852
|
+
const provider = snapshot?.provider;
|
|
1853
|
+
const heading = title ?? (provider === null || provider === void 0 ? messages.connectAnyTitle : messages.connectTitle(provider));
|
|
1854
|
+
const body = children ?? /* @__PURE__ */ jsx(Form, { controller });
|
|
1855
|
+
if (readOnly) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1856
|
+
if (render !== void 0) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
|
|
1857
|
+
"data-domainkit-part": "connection-trigger",
|
|
1858
|
+
onClick: () => setOpen(!open),
|
|
1859
|
+
type: "button",
|
|
1860
|
+
children: trigger ?? messages.connect
|
|
1861
|
+
}), render({
|
|
1862
|
+
children: body,
|
|
1863
|
+
open
|
|
1864
|
+
})] });
|
|
1865
|
+
return /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
1866
|
+
onOpenChange: (next, details) => {
|
|
1867
|
+
if (!next && busy) {
|
|
1868
|
+
details.cancel();
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
setOpen(next);
|
|
1872
|
+
},
|
|
1873
|
+
open,
|
|
1874
|
+
children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
|
|
1875
|
+
"data-domainkit-part": "connection-trigger",
|
|
1876
|
+
children: trigger ?? messages.connect
|
|
1877
|
+
}), /* @__PURE__ */ jsxs(Dialog.Portal, {
|
|
1878
|
+
container: portalContainer,
|
|
1879
|
+
children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
1880
|
+
"data-color-scheme": colorScheme,
|
|
1881
|
+
"data-domainkit-part": "dialog-backdrop",
|
|
1882
|
+
"data-domainkit-root": "",
|
|
1883
|
+
style: themeStyle
|
|
1884
|
+
}), /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
1885
|
+
"data-color-scheme": colorScheme,
|
|
1886
|
+
"data-domainkit-part": "connection-dialog",
|
|
1887
|
+
"data-domainkit-root": "",
|
|
1888
|
+
style: themeStyle,
|
|
1889
|
+
children: [
|
|
1890
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1891
|
+
"data-domainkit-part": "dialog-header",
|
|
1892
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1893
|
+
"data-domainkit-part": "dialog-heading",
|
|
1894
|
+
children: [/* @__PURE__ */ jsx(Dialog.Title, {
|
|
1895
|
+
"data-domainkit-part": "dialog-title",
|
|
1896
|
+
children: heading
|
|
1897
|
+
}), /* @__PURE__ */ jsx(Dialog.Description, {
|
|
1898
|
+
"data-domainkit-part": "dialog-description",
|
|
1899
|
+
children: messages.connectDescription(snapshot?.domain ?? "")
|
|
1900
|
+
})]
|
|
1901
|
+
}), busy ? null : /* @__PURE__ */ jsx(Dialog.Close, {
|
|
1902
|
+
"aria-label": messages.close,
|
|
1903
|
+
"data-domainkit-part": "dialog-close",
|
|
1904
|
+
children: "×"
|
|
1905
|
+
})]
|
|
1906
|
+
}),
|
|
1907
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1908
|
+
"data-domainkit-part": "dialog-body",
|
|
1909
|
+
children: [
|
|
1910
|
+
/* @__PURE__ */ jsx(Status$2, { controller }),
|
|
1911
|
+
body,
|
|
1912
|
+
/* @__PURE__ */ jsx(Outcome$2, { controller })
|
|
1913
|
+
]
|
|
1914
|
+
}),
|
|
1915
|
+
busy ? null : /* @__PURE__ */ jsx("div", {
|
|
1916
|
+
"data-domainkit-part": "dialog-footer",
|
|
1917
|
+
children: /* @__PURE__ */ jsx(Dialog.Close, {
|
|
1918
|
+
"data-domainkit-part": "dialog-cancel",
|
|
1919
|
+
children: messages.cancel
|
|
1920
|
+
})
|
|
1921
|
+
})
|
|
1922
|
+
]
|
|
1923
|
+
})]
|
|
1924
|
+
})]
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
/** A connected domain: which provider holds it, and how to let it go. */
|
|
1928
|
+
function Card({ controller, ...props }) {
|
|
1929
|
+
const { messages } = useDomainKit();
|
|
1930
|
+
const readOnly = useReadOnly();
|
|
1931
|
+
const state = controller.state;
|
|
1932
|
+
const snapshot = controller.snapshot;
|
|
1933
|
+
const provider = controller.providers.find((entry) => entry.id === snapshot?.provider);
|
|
1934
|
+
return usePart("div", props, { status: state._tag }, {
|
|
1935
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1936
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1937
|
+
"data-domainkit-part": "connected-identity",
|
|
1938
|
+
children: [provider === void 0 ? null : /* @__PURE__ */ jsx(Mark, { provider }), /* @__PURE__ */ jsx(Status$2, { controller })]
|
|
1939
|
+
}),
|
|
1940
|
+
readOnly ? null : /* @__PURE__ */ jsxs("div", {
|
|
1941
|
+
"data-domainkit-part": "connected-actions",
|
|
1942
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
1943
|
+
"data-domainkit-part": "disconnect-trigger",
|
|
1944
|
+
disabled: state._tag === "Submitting",
|
|
1945
|
+
onClick: controller.detach,
|
|
1946
|
+
type: "button",
|
|
1947
|
+
children: messages.detach
|
|
1948
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
1949
|
+
"data-domainkit-part": "disconnect-action",
|
|
1950
|
+
disabled: state._tag === "Submitting",
|
|
1951
|
+
onClick: controller.disconnect,
|
|
1952
|
+
type: "button",
|
|
1953
|
+
children: messages.disconnect
|
|
1954
|
+
})]
|
|
1955
|
+
}),
|
|
1956
|
+
/* @__PURE__ */ jsx(Outcome$2, { controller })
|
|
1957
|
+
] }),
|
|
1958
|
+
"data-domainkit-part": "connected-card"
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
/** Connection on its own: the card once connected, the dialog until then. */
|
|
1962
|
+
function Flow$2({ domain, returnTo, ...props }) {
|
|
1963
|
+
const controller = useController$2({
|
|
1964
|
+
domain,
|
|
1965
|
+
...returnTo === void 0 ? {} : { returnTo }
|
|
1966
|
+
});
|
|
1967
|
+
const state = controller.state;
|
|
1968
|
+
return /* @__PURE__ */ jsx(Root$2, {
|
|
1969
|
+
controller,
|
|
1970
|
+
...props,
|
|
1971
|
+
children: state._tag === "Connected" ? /* @__PURE__ */ jsx(Card, { controller }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Dialog$2, { controller }), /* @__PURE__ */ jsx(Outcome$2, { controller })] })
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
//#endregion
|
|
1975
|
+
//#region src/provision.tsx
|
|
1976
|
+
var provision_exports = /* @__PURE__ */ __exportAll({
|
|
1977
|
+
Actions: () => Actions,
|
|
1978
|
+
Dialog: () => Dialog$1,
|
|
1979
|
+
Flow: () => Flow$1,
|
|
1980
|
+
Outcome: () => Outcome$1,
|
|
1981
|
+
Root: () => Root$1,
|
|
1982
|
+
State: () => State$2,
|
|
1983
|
+
Status: () => Status$1,
|
|
1984
|
+
useController: () => useController$1
|
|
1985
|
+
});
|
|
1986
|
+
/** Plan, approve, apply. `approve` authorizes the digest and applies it in the same action. */
|
|
1987
|
+
/**
|
|
1988
|
+
* Requirements identify themselves by content, so an inline array does not abandon the attempt.
|
|
1989
|
+
* Every field counts: a plan turns on `policy`, and `ttl` and `purpose` ride the wire with it.
|
|
1990
|
+
*/
|
|
1991
|
+
const keyOf = (domain, requirements) => [domain, requirementsKey(requirements)].join("|");
|
|
1992
|
+
function useController$1({ domain, onApplied, requirements }) {
|
|
1993
|
+
const { transport } = useDomainKit();
|
|
1994
|
+
const group = transport.provisioning;
|
|
1995
|
+
return useAttempt({
|
|
1996
|
+
domain,
|
|
1997
|
+
key: keyOf(domain, requirements),
|
|
1998
|
+
done: (receipt) => Event.Applied({
|
|
1999
|
+
domain,
|
|
2000
|
+
receipt
|
|
2001
|
+
}),
|
|
2002
|
+
group,
|
|
2003
|
+
onDone: onApplied,
|
|
2004
|
+
plan: useCallback(() => group === void 0 ? null : group.plan({
|
|
2005
|
+
domain,
|
|
2006
|
+
requirements
|
|
2007
|
+
}), [
|
|
2008
|
+
domain,
|
|
2009
|
+
group,
|
|
2010
|
+
requirements
|
|
2011
|
+
])
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
function Root$1({ controller, ...props }) {
|
|
2015
|
+
return usePart("div", props, { status: controller.state._tag }, {
|
|
2016
|
+
"data-domainkit-part": "provisioning-flow",
|
|
2017
|
+
"data-state": controller.state._tag
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
function Dialog$1(props) {
|
|
2021
|
+
return /* @__PURE__ */ jsx(Dialog$4, {
|
|
2022
|
+
...props,
|
|
2023
|
+
kind: "provisioning"
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
/** Approve and Decline for a plan already under review. */
|
|
2027
|
+
function Actions(props) {
|
|
2028
|
+
return /* @__PURE__ */ jsx(Actions$2, {
|
|
2029
|
+
...props,
|
|
2030
|
+
kind: "provisioning"
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
function Outcome$1(props) {
|
|
2034
|
+
return /* @__PURE__ */ jsx(Outcome$4, {
|
|
2035
|
+
...props,
|
|
2036
|
+
kind: "provisioning"
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
function Status$1(props) {
|
|
2040
|
+
return /* @__PURE__ */ jsx(Status$4, {
|
|
2041
|
+
...props,
|
|
2042
|
+
kind: "provisioning"
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
/** Provisioning on its own: a trigger that plans, then the review dialog. */
|
|
2046
|
+
function Flow$1({ domain, onApplied, requirements, trigger, ...props }) {
|
|
2047
|
+
const controller = useController$1({
|
|
2048
|
+
domain,
|
|
2049
|
+
requirements,
|
|
2050
|
+
...onApplied === void 0 ? {} : { onApplied }
|
|
2051
|
+
});
|
|
2052
|
+
return /* @__PURE__ */ jsxs(Root$1, {
|
|
2053
|
+
controller,
|
|
2054
|
+
...props,
|
|
2055
|
+
children: [/* @__PURE__ */ jsx(Dialog$1, {
|
|
2056
|
+
controller,
|
|
2057
|
+
...trigger === void 0 ? {} : { trigger }
|
|
2058
|
+
}), /* @__PURE__ */ jsx(Outcome$1, { controller })]
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
//#endregion
|
|
2062
|
+
//#region src/verify.tsx
|
|
2063
|
+
var verify_exports = /* @__PURE__ */ __exportAll({
|
|
2064
|
+
Evidence: () => Evidence,
|
|
2065
|
+
ObserveAction: () => ObserveAction,
|
|
2066
|
+
Outcome: () => Outcome,
|
|
2067
|
+
Root: () => Root,
|
|
2068
|
+
State: () => State,
|
|
2069
|
+
Status: () => Status,
|
|
2070
|
+
useController: () => useController
|
|
2071
|
+
});
|
|
2072
|
+
/**
|
|
2073
|
+
* What the observer read back for the requirement's name, or `null` when it read nothing back at
|
|
2074
|
+
* all. Host evidence reports a status the host reached rather than values read off a name, and an
|
|
2075
|
+
* `unknown` observation is a lookup that never answered, which is not the same as finding nothing.
|
|
2076
|
+
*/
|
|
2077
|
+
const valuesOf = (evidence) => evidence._tag === "Host" || evidence.status === "unknown" ? null : evidence.values;
|
|
2078
|
+
const State = Data.taggedEnum();
|
|
2079
|
+
const readinessOf = (state) => state._tag === "Idle" ? null : state.readiness;
|
|
2080
|
+
/** Observe once on mount, then follow the readiness's own `nextCheckAt` while polling is on. */
|
|
2081
|
+
function useController({ domain, polling = true, requirements }) {
|
|
2082
|
+
const { emit, revision, transport } = useDomainKit();
|
|
2083
|
+
const verification = transport.verification;
|
|
2084
|
+
const runner = useRunner();
|
|
2085
|
+
const [state, setState] = useState(State.Idle());
|
|
2086
|
+
const timer = useRef(void 0);
|
|
2087
|
+
const signature = requirements === void 0 ? null : requirementsKey(requirements);
|
|
2088
|
+
const requested = useMemo(() => requirements === void 0 ? void 0 : { requirements }, [signature]);
|
|
2089
|
+
const [observed, setObserved] = useState(domain);
|
|
2090
|
+
if (observed !== domain) {
|
|
2091
|
+
setObserved(domain);
|
|
2092
|
+
setState(State.Idle());
|
|
2093
|
+
}
|
|
2094
|
+
const observe = useCallback(() => {
|
|
2095
|
+
if (verification === void 0) return;
|
|
2096
|
+
clearTimeout(timer.current);
|
|
2097
|
+
setState((previous) => State.Observing({ readiness: readinessOf(previous) }));
|
|
2098
|
+
runner.run(requested === void 0 ? verification.observe(domain) : verification.observe(domain, requested), {
|
|
2099
|
+
onFailure: (error) => {
|
|
2100
|
+
setState((previous) => State.Failure({
|
|
2101
|
+
error,
|
|
2102
|
+
readiness: readinessOf(previous)
|
|
2103
|
+
}));
|
|
2104
|
+
emit(Event.Failed({
|
|
2105
|
+
domain,
|
|
2106
|
+
error
|
|
2107
|
+
}));
|
|
2108
|
+
},
|
|
2109
|
+
onSuccess: (readiness) => setState(State.Observed({ readiness }))
|
|
2110
|
+
});
|
|
2111
|
+
}, [
|
|
2112
|
+
domain,
|
|
2113
|
+
emit,
|
|
2114
|
+
requested,
|
|
2115
|
+
runner,
|
|
2116
|
+
verification
|
|
2117
|
+
]);
|
|
2118
|
+
useEffect(() => {
|
|
2119
|
+
observe();
|
|
2120
|
+
}, [observe, revision]);
|
|
2121
|
+
useEffect(() => {
|
|
2122
|
+
if (!polling || state._tag !== "Observed") return;
|
|
2123
|
+
const next = state.readiness.nextCheckAt;
|
|
2124
|
+
if (next === null) return;
|
|
2125
|
+
const delay = Math.max(0, DateTime.toEpochMillis(next) - Date.now());
|
|
2126
|
+
timer.current = setTimeout(observe, delay);
|
|
2127
|
+
return () => clearTimeout(timer.current);
|
|
2128
|
+
}, [
|
|
2129
|
+
observe,
|
|
2130
|
+
polling,
|
|
2131
|
+
state
|
|
2132
|
+
]);
|
|
2133
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
2134
|
+
return {
|
|
2135
|
+
observe,
|
|
2136
|
+
polling,
|
|
2137
|
+
readiness: readinessOf(state),
|
|
2138
|
+
retry: observe,
|
|
2139
|
+
state
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
function Root({ controller, ...props }) {
|
|
2143
|
+
const overall = controller.readiness?.overall ?? null;
|
|
2144
|
+
return usePart("div", props, { status: controller.state._tag }, {
|
|
2145
|
+
"data-domainkit-part": "verification-status",
|
|
2146
|
+
"data-overall": overall ?? void 0,
|
|
2147
|
+
"data-state": controller.state._tag
|
|
1636
2148
|
});
|
|
1637
2149
|
}
|
|
1638
2150
|
function ObserveAction({ controller, ...props }) {
|
|
@@ -1640,402 +2152,292 @@ function ObserveAction({ controller, ...props }) {
|
|
|
1640
2152
|
const observing = controller.state._tag === "Observing";
|
|
1641
2153
|
return usePart("button", props, { status: controller.state._tag }, {
|
|
1642
2154
|
"aria-busy": observing,
|
|
1643
|
-
children: messages.checkDns,
|
|
2155
|
+
children: controller.readiness === null ? messages.checkDns : messages.checkAgain,
|
|
1644
2156
|
"data-domainkit-part": "observe-action",
|
|
1645
2157
|
"data-loading": observing ? "" : void 0,
|
|
1646
2158
|
disabled: observing,
|
|
1647
|
-
onClick:
|
|
2159
|
+
onClick: controller.observe,
|
|
1648
2160
|
type: "button"
|
|
1649
2161
|
});
|
|
1650
2162
|
}
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
2163
|
+
/** Evidence carries no id; its source and position identify it within one requirement. */
|
|
2164
|
+
const evidenceKey = (evidence, index) => [evidence._tag, index].join("-");
|
|
2165
|
+
/**
|
|
2166
|
+
* Per-requirement readiness and, below it, the host's own evidence: an SES identity, a certificate,
|
|
2167
|
+
* anything DomainKit cannot observe but the host feeds in.
|
|
2168
|
+
*/
|
|
2169
|
+
function Evidence({ readiness }) {
|
|
2170
|
+
const { messages } = useDomainKit();
|
|
2171
|
+
const icons = useIcons();
|
|
2172
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2173
|
+
"data-domainkit-part": "observation-list",
|
|
2174
|
+
children: [readiness.requirements.map((requirement) => {
|
|
2175
|
+
const settled = requirement.status === "satisfied";
|
|
2176
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
2177
|
+
"data-domainkit-part": "observation-group",
|
|
2178
|
+
children: [
|
|
2179
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2180
|
+
"data-domainkit-part": "observation-row",
|
|
2181
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
2182
|
+
"data-domainkit-part": "observation-record",
|
|
2183
|
+
children: [
|
|
2184
|
+
messages.recordType(requirement.record),
|
|
2185
|
+
" ",
|
|
2186
|
+
requirement.record.name
|
|
2187
|
+
]
|
|
2188
|
+
}), /* @__PURE__ */ jsx(Status$5, { status: requirement.status })]
|
|
2189
|
+
}),
|
|
2190
|
+
settled ? null : /* @__PURE__ */ jsx("p", {
|
|
2191
|
+
"data-domainkit-part": "observation-expected",
|
|
2192
|
+
children: messages.expectedValue(DnsRecord.data(requirement.record))
|
|
2193
|
+
}),
|
|
2194
|
+
/* @__PURE__ */ jsx("ul", { children: requirement.evidence.map((evidence, index) => {
|
|
2195
|
+
const values = settled ? null : valuesOf(evidence);
|
|
2196
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
2197
|
+
"data-domainkit-part": "observation-source",
|
|
2198
|
+
children: [
|
|
2199
|
+
messages.evidenceSource(evidence),
|
|
2200
|
+
values === null ? null : /* @__PURE__ */ jsx("span", {
|
|
2201
|
+
"data-domainkit-part": "observation-observed",
|
|
2202
|
+
children: values.length === 0 ? messages.observedNothing : messages.observedValues(values)
|
|
2203
|
+
}),
|
|
2204
|
+
evidence.detail === null ? null : /* @__PURE__ */ jsx("p", {
|
|
2205
|
+
"data-domainkit-part": "observation-note",
|
|
2206
|
+
children: evidence.detail
|
|
2207
|
+
})
|
|
2208
|
+
]
|
|
2209
|
+
}, evidenceKey(evidence, index));
|
|
2210
|
+
}) })
|
|
2211
|
+
]
|
|
2212
|
+
}, identity(requirement.record));
|
|
2213
|
+
}), readiness.host.length === 0 ? null : /* @__PURE__ */ jsxs("section", {
|
|
2214
|
+
"data-domainkit-part": "observation-group",
|
|
2215
|
+
"data-source": "host",
|
|
2216
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
2217
|
+
"data-domainkit-part": "observation-source",
|
|
2218
|
+
children: messages.hostEvidence
|
|
2219
|
+
}), /* @__PURE__ */ jsx("ul", { children: readiness.host.map((evidence, index) => /* @__PURE__ */ jsxs("li", {
|
|
2220
|
+
"data-domainkit-part": "host-evidence",
|
|
2221
|
+
children: [
|
|
2222
|
+
/* @__PURE__ */ jsx("span", {
|
|
2223
|
+
"aria-hidden": "true",
|
|
2224
|
+
"data-icon": "inline-start",
|
|
2225
|
+
children: evidence.status === "ok" ? icons.success : evidence.status === "pending" ? icons.pending : icons.failure
|
|
2226
|
+
}),
|
|
2227
|
+
/* @__PURE__ */ jsx("span", {
|
|
2228
|
+
"data-domainkit-part": "observation-record",
|
|
2229
|
+
children: evidence.label
|
|
2230
|
+
}),
|
|
2231
|
+
/* @__PURE__ */ jsx("span", {
|
|
2232
|
+
"data-domainkit-part": "record-status",
|
|
2233
|
+
"data-status": evidence.status,
|
|
2234
|
+
children: messages.hostEvidenceStatus(evidence.status)
|
|
2235
|
+
}),
|
|
2236
|
+
evidence.detail === null ? null : /* @__PURE__ */ jsx("p", {
|
|
2237
|
+
"data-domainkit-part": "observation-note",
|
|
2238
|
+
children: evidence.detail
|
|
2239
|
+
})
|
|
2240
|
+
]
|
|
2241
|
+
}, `${evidence.source}-${index}`)) })]
|
|
2242
|
+
})]
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
function Outcome({ controller, ...props }) {
|
|
2246
|
+
const { messages } = useDomainKit();
|
|
1654
2247
|
const state = controller.state;
|
|
1655
|
-
const
|
|
2248
|
+
const element = usePart("p", props, { status: state._tag }, {
|
|
2249
|
+
children: state._tag === "Failure" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2250
|
+
failure(state.error, messages),
|
|
2251
|
+
" ",
|
|
2252
|
+
/* @__PURE__ */ jsx("button", {
|
|
2253
|
+
"data-domainkit-part": "verification-retry",
|
|
2254
|
+
onClick: controller.retry,
|
|
2255
|
+
type: "button",
|
|
2256
|
+
children: messages.retry
|
|
2257
|
+
})
|
|
2258
|
+
] }) : null,
|
|
2259
|
+
"data-domainkit-part": "flow-outcome",
|
|
2260
|
+
"data-tone": "danger",
|
|
2261
|
+
role: "alert"
|
|
2262
|
+
});
|
|
2263
|
+
return state._tag === "Failure" ? element : null;
|
|
2264
|
+
}
|
|
2265
|
+
/** The default verification slot: a button that observes, with the evidence behind it. */
|
|
2266
|
+
function Status({ controller, render, ...props }) {
|
|
2267
|
+
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
2268
|
+
const readiness = controller.readiness;
|
|
2269
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2270
|
+
controller.state._tag === "Observing" ? /* @__PURE__ */ jsx("p", {
|
|
2271
|
+
"data-domainkit-part": "verification-progress",
|
|
2272
|
+
role: "status",
|
|
2273
|
+
children: messages.observing
|
|
2274
|
+
}) : null,
|
|
2275
|
+
readiness === null ? /* @__PURE__ */ jsx("p", {
|
|
2276
|
+
"data-domainkit-part": "verification-progress",
|
|
2277
|
+
children: messages.noEvidence
|
|
2278
|
+
}) : /* @__PURE__ */ jsx(Evidence, { readiness }),
|
|
2279
|
+
/* @__PURE__ */ jsx(Outcome, { controller })
|
|
2280
|
+
] });
|
|
1656
2281
|
return /* @__PURE__ */ jsx(Root, {
|
|
1657
|
-
|
|
2282
|
+
controller,
|
|
1658
2283
|
...props,
|
|
1659
|
-
children: /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, { render: /* @__PURE__ */ jsx(ObserveAction, { controller }) }), /* @__PURE__ */ jsx(Popover.Portal, {
|
|
2284
|
+
children: render === void 0 ? /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, { render: /* @__PURE__ */ jsx(ObserveAction, { controller }) }), /* @__PURE__ */ jsx(Popover.Portal, {
|
|
1660
2285
|
container: portalContainer,
|
|
1661
2286
|
children: /* @__PURE__ */ jsx(Popover.Positioner, {
|
|
1662
2287
|
align: "end",
|
|
1663
2288
|
"data-domainkit-part": "verification-positioner",
|
|
1664
2289
|
sideOffset: 6,
|
|
1665
2290
|
children: /* @__PURE__ */ jsxs(Popover.Popup, {
|
|
2291
|
+
"aria-busy": controller.state._tag === "Observing",
|
|
1666
2292
|
"aria-label": messages.checkDns,
|
|
1667
|
-
"aria-busy": state._tag === "Observing",
|
|
1668
2293
|
"data-color-scheme": colorScheme,
|
|
1669
2294
|
"data-domainkit-part": "verification-popover",
|
|
1670
2295
|
"data-domainkit-root": "",
|
|
1671
2296
|
style: themeStyle,
|
|
1672
|
-
children: [
|
|
1673
|
-
/* @__PURE__ */ jsx(Popover.Arrow, { "data-domainkit-part": "verification-arrow" }),
|
|
1674
|
-
state._tag === "Observing" ? /* @__PURE__ */ jsx("p", {
|
|
1675
|
-
"data-domainkit-part": "verification-progress",
|
|
1676
|
-
role: "status",
|
|
1677
|
-
children: messages.checkingDns
|
|
1678
|
-
}) : null,
|
|
1679
|
-
observation === void 0 ? null : /* @__PURE__ */ jsx(Evidence, { observation }),
|
|
1680
|
-
/* @__PURE__ */ jsx(Outcome, { state })
|
|
1681
|
-
]
|
|
2297
|
+
children: [/* @__PURE__ */ jsx(Popover.Arrow, { "data-domainkit-part": "verification-arrow" }), body]
|
|
1682
2298
|
})
|
|
1683
2299
|
})
|
|
2300
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ObserveAction, { controller }), render({
|
|
2301
|
+
children: body,
|
|
2302
|
+
open: controller.state._tag !== "Idle"
|
|
1684
2303
|
})] })
|
|
1685
2304
|
});
|
|
1686
2305
|
}
|
|
1687
2306
|
//#endregion
|
|
1688
2307
|
//#region src/domain.tsx
|
|
1689
2308
|
var domain_exports = /* @__PURE__ */ __exportAll({ Flow: () => Flow });
|
|
1690
|
-
function
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
children: [
|
|
1697
|
-
state._tag === "Connected" || state._tag === "Detaching" ? /* @__PURE__ */ jsx(ConnectedCard, {
|
|
1698
|
-
connection: state._tag === "Connected" ? state : state.snapshot,
|
|
1699
|
-
controller,
|
|
1700
|
-
...receiptId === void 0 ? {} : { initialReceiptId: receiptId },
|
|
1701
|
-
records,
|
|
1702
|
-
status: state._tag
|
|
1703
|
-
}) : /* @__PURE__ */ jsx(AvailableCard, {
|
|
1704
|
-
controller,
|
|
1705
|
-
state
|
|
1706
|
-
}),
|
|
1707
|
-
/* @__PURE__ */ jsx(Table, { records }),
|
|
1708
|
-
/* @__PURE__ */ jsx(Status, { config: {
|
|
1709
|
-
...connected === void 0 ? {} : { connection: connected },
|
|
1710
|
-
domain,
|
|
1711
|
-
records
|
|
1712
|
-
} })
|
|
1713
|
-
]
|
|
1714
|
-
});
|
|
2309
|
+
function DefaultConnection({ controller }) {
|
|
2310
|
+
return controller.state._tag === "Connected" ? /* @__PURE__ */ jsx(Card, { controller }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2311
|
+
/* @__PURE__ */ jsx(Status$2, { controller }),
|
|
2312
|
+
/* @__PURE__ */ jsx(Dialog$2, { controller }),
|
|
2313
|
+
/* @__PURE__ */ jsx(Outcome$2, { controller })
|
|
2314
|
+
] });
|
|
1715
2315
|
}
|
|
1716
|
-
function
|
|
1717
|
-
const { messages } = useDomainKit();
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
2316
|
+
function DefaultActions({ cleanup, connection, provisioning }) {
|
|
2317
|
+
const { capabilities, messages } = useDomainKit();
|
|
2318
|
+
const readOnly = useReadOnly();
|
|
2319
|
+
const icons = useIcons();
|
|
2320
|
+
const connected = connection.state._tag === "Connected";
|
|
2321
|
+
if (readOnly) return null;
|
|
2322
|
+
const hasReceipt = connection.snapshot?.lastReceiptId != null;
|
|
2323
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [capabilities.includes("provisioning") && connected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2324
|
+
/* @__PURE__ */ jsx("button", {
|
|
2325
|
+
"data-domainkit-part": "plan-trigger",
|
|
2326
|
+
disabled: provisioning.state._tag === "Planning",
|
|
2327
|
+
onClick: provisioning.plan,
|
|
2328
|
+
type: "button",
|
|
2329
|
+
children: messages.reviewChanges
|
|
2330
|
+
}),
|
|
2331
|
+
/* @__PURE__ */ jsx(Status$1, { controller: provisioning }),
|
|
2332
|
+
/* @__PURE__ */ jsx(Actions, { controller: provisioning }),
|
|
2333
|
+
/* @__PURE__ */ jsx(Outcome$1, { controller: provisioning })
|
|
2334
|
+
] }) : null, capabilities.includes("cleanup") && connected && hasReceipt ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2335
|
+
/* @__PURE__ */ jsxs("button", {
|
|
2336
|
+
"data-domainkit-part": "cleanup-trigger",
|
|
2337
|
+
disabled: cleanup.state._tag === "Planning",
|
|
2338
|
+
onClick: cleanup.plan,
|
|
2339
|
+
type: "button",
|
|
2340
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2341
|
+
"aria-hidden": "true",
|
|
2342
|
+
"data-icon": "inline-start",
|
|
2343
|
+
children: icons.close
|
|
2344
|
+
}), messages.cleanUp]
|
|
2345
|
+
}),
|
|
2346
|
+
/* @__PURE__ */ jsx(Status$3, { controller: cleanup }),
|
|
2347
|
+
/* @__PURE__ */ jsx(Actions$1, { controller: cleanup }),
|
|
2348
|
+
/* @__PURE__ */ jsx(Outcome$3, { controller: cleanup })
|
|
2349
|
+
] }) : null] });
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* The whole lifecycle for one domain: connect, review, apply, observe, clean up. The flow renders
|
|
2353
|
+
* only what the transport declares, and every part of it is a slot with a default. It adds no
|
|
2354
|
+
* layout containers of its own, so a host's grid can place the slot output directly.
|
|
2355
|
+
*/
|
|
2356
|
+
function Flow({ domain, onApplied, onCleaned, readOnly, requirements, returnTo, slots = {}, ...props }) {
|
|
2357
|
+
const { capabilities } = useDomainKit();
|
|
2358
|
+
const inherited = useReadOnly();
|
|
2359
|
+
const connection = useController$2({
|
|
2360
|
+
domain,
|
|
2361
|
+
...returnTo === void 0 ? {} : { returnTo }
|
|
1743
2362
|
});
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
2363
|
+
const refresh = connection.refresh;
|
|
2364
|
+
const provisioning = useController$1({
|
|
2365
|
+
domain,
|
|
2366
|
+
onApplied: useCallback((receipt) => {
|
|
2367
|
+
refresh();
|
|
2368
|
+
onApplied?.(receipt);
|
|
2369
|
+
}, [onApplied, refresh]),
|
|
2370
|
+
requirements
|
|
2371
|
+
});
|
|
2372
|
+
const cleanup = useController$3({
|
|
2373
|
+
domain,
|
|
2374
|
+
onCleaned: useCallback((receipt) => {
|
|
2375
|
+
refresh();
|
|
2376
|
+
onCleaned?.(receipt);
|
|
2377
|
+
}, [onCleaned, refresh]),
|
|
2378
|
+
...connection.snapshot?.lastReceiptId == null ? {} : { receiptId: Receipt.ReceiptId.make(connection.snapshot.lastReceiptId) }
|
|
1749
2379
|
});
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
2380
|
+
const verification = useController({
|
|
2381
|
+
domain,
|
|
2382
|
+
requirements
|
|
1753
2383
|
});
|
|
1754
|
-
const
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
children:
|
|
1760
|
-
|
|
1761
|
-
children: [
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
connection
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
value: result.receiptId
|
|
2384
|
+
const readiness = verification.readiness;
|
|
2385
|
+
return usePart("div", props, {
|
|
2386
|
+
connection: connection.state._tag,
|
|
2387
|
+
provisioning: provisioning.state._tag
|
|
2388
|
+
}, {
|
|
2389
|
+
children: /* @__PURE__ */ jsxs(ReadOnly, {
|
|
2390
|
+
value: readOnly ?? inherited,
|
|
2391
|
+
children: [
|
|
2392
|
+
!capabilities.includes("connection") ? null : slots.connection === void 0 ? /* @__PURE__ */ jsx(DefaultConnection, {
|
|
2393
|
+
controller: connection,
|
|
2394
|
+
domain
|
|
2395
|
+
}) : slots.connection({
|
|
2396
|
+
controller: connection,
|
|
2397
|
+
domain
|
|
1769
2398
|
}),
|
|
1770
|
-
records,
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
actionsTriggerRef,
|
|
1779
|
-
connection,
|
|
1780
|
-
controller,
|
|
1781
|
-
disabled,
|
|
1782
|
-
onCleaned: () => setReceipt({
|
|
1783
|
-
host: initialReceiptId,
|
|
1784
|
-
value: void 0
|
|
2399
|
+
slots.records === void 0 ? /* @__PURE__ */ jsx(Table, {
|
|
2400
|
+
readiness,
|
|
2401
|
+
records: requirements
|
|
2402
|
+
}) : slots.records({
|
|
2403
|
+
controller: verification,
|
|
2404
|
+
domain,
|
|
2405
|
+
readiness,
|
|
2406
|
+
records: requirements
|
|
1785
2407
|
}),
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
controller,
|
|
1801
|
-
disabled,
|
|
1802
|
-
onCleanupCloseComplete: () => {
|
|
1803
|
-
if (cleaned) onCleaned();
|
|
1804
|
-
}
|
|
1805
|
-
});
|
|
1806
|
-
}
|
|
1807
|
-
function ProviderActions({ actionsTriggerRef: actionsTriggerRefProp, cleanup, connection, controller, disabled, onCleanupCloseComplete }) {
|
|
1808
|
-
const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
|
|
1809
|
-
const fallbackActionsTriggerRef = useRef(null);
|
|
1810
|
-
const actionsTriggerRef = actionsTriggerRefProp ?? fallbackActionsTriggerRef;
|
|
1811
|
-
const [menuOpen, setMenuOpen] = useState(false);
|
|
1812
|
-
const [disconnectOpen, setDisconnectOpen] = useState(false);
|
|
1813
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1814
|
-
/* @__PURE__ */ jsxs(Menu.Root, {
|
|
1815
|
-
disabled,
|
|
1816
|
-
modal: false,
|
|
1817
|
-
onOpenChange: setMenuOpen,
|
|
1818
|
-
open: menuOpen,
|
|
1819
|
-
children: [/* @__PURE__ */ jsx(Menu.Trigger, {
|
|
1820
|
-
"aria-label": messages.moreActions,
|
|
1821
|
-
"data-domainkit-part": "actions-trigger",
|
|
1822
|
-
ref: actionsTriggerRef,
|
|
1823
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
1824
|
-
"aria-hidden": "true",
|
|
1825
|
-
children: "⋯"
|
|
1826
|
-
})
|
|
1827
|
-
}), /* @__PURE__ */ jsx(Menu.Portal, {
|
|
1828
|
-
container: portalContainer,
|
|
1829
|
-
keepMounted: true,
|
|
1830
|
-
children: /* @__PURE__ */ jsx(Menu.Positioner, {
|
|
1831
|
-
align: "end",
|
|
1832
|
-
sideOffset: 6,
|
|
1833
|
-
children: /* @__PURE__ */ jsxs(Menu.Popup, {
|
|
1834
|
-
"data-color-scheme": colorScheme,
|
|
1835
|
-
"data-domainkit-part": "actions-menu",
|
|
1836
|
-
"data-domainkit-root": "",
|
|
1837
|
-
style: themeStyle,
|
|
1838
|
-
children: [cleanup === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu.Item, {
|
|
1839
|
-
closeOnClick: false,
|
|
1840
|
-
"data-domainkit-part": "actions-item",
|
|
1841
|
-
nativeButton: true,
|
|
1842
|
-
onClickCapture: () => {
|
|
1843
|
-
setMenuOpen(false);
|
|
1844
|
-
queueMicrotask(() => cleanup.plan());
|
|
1845
|
-
},
|
|
1846
|
-
render: /* @__PURE__ */ jsx("button", { type: "button" }),
|
|
1847
|
-
children: messages.reviewCleanup
|
|
1848
|
-
}), /* @__PURE__ */ jsx(Menu.Separator, { "data-domainkit-part": "actions-separator" })] }), /* @__PURE__ */ jsx(Menu.Item, {
|
|
1849
|
-
closeOnClick: false,
|
|
1850
|
-
"data-domainkit-part": "actions-item",
|
|
1851
|
-
"data-tone": "danger",
|
|
1852
|
-
nativeButton: true,
|
|
1853
|
-
onClickCapture: () => {
|
|
1854
|
-
setMenuOpen(false);
|
|
1855
|
-
queueMicrotask(() => setDisconnectOpen(true));
|
|
1856
|
-
},
|
|
1857
|
-
render: /* @__PURE__ */ jsx("button", { type: "button" }),
|
|
1858
|
-
children: messages.disconnectDomain
|
|
1859
|
-
})]
|
|
1860
|
-
})
|
|
2408
|
+
!capabilities.includes("verification") ? null : slots.verification === void 0 ? /* @__PURE__ */ jsx(Status, { controller: verification }) : slots.verification({
|
|
2409
|
+
controller: verification,
|
|
2410
|
+
domain
|
|
2411
|
+
}),
|
|
2412
|
+
slots.actions === void 0 ? /* @__PURE__ */ jsx(DefaultActions, {
|
|
2413
|
+
cleanup,
|
|
2414
|
+
connection,
|
|
2415
|
+
domain,
|
|
2416
|
+
provisioning
|
|
2417
|
+
}) : slots.actions({
|
|
2418
|
+
cleanup,
|
|
2419
|
+
connection,
|
|
2420
|
+
domain,
|
|
2421
|
+
provisioning
|
|
1861
2422
|
})
|
|
1862
|
-
|
|
1863
|
-
}),
|
|
1864
|
-
cleanup === void 0 ? null : /* @__PURE__ */ jsx(Dialog$3, {
|
|
1865
|
-
controller: cleanup,
|
|
1866
|
-
onOpenChangeComplete: (open) => {
|
|
1867
|
-
if (!open) {
|
|
1868
|
-
onCleanupCloseComplete?.();
|
|
1869
|
-
queueMicrotask(() => actionsTriggerRef.current?.focus());
|
|
1870
|
-
}
|
|
1871
|
-
},
|
|
1872
|
-
trigger: null
|
|
2423
|
+
]
|
|
1873
2424
|
}),
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
onOpenChange: (open) => {
|
|
1878
|
-
setDisconnectOpen(open);
|
|
1879
|
-
if (!open) queueMicrotask(() => actionsTriggerRef.current?.focus());
|
|
1880
|
-
},
|
|
1881
|
-
open: disconnectOpen,
|
|
1882
|
-
trigger: null
|
|
1883
|
-
})
|
|
1884
|
-
] });
|
|
2425
|
+
"data-domainkit-part": "domain-flow",
|
|
2426
|
+
"data-domain": domain
|
|
2427
|
+
});
|
|
1885
2428
|
}
|
|
1886
2429
|
//#endregion
|
|
1887
2430
|
//#region src/testing.ts
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
const
|
|
1897
|
-
authentication: [Transport.AuthenticationMethod.OAuth({ label: "Continue with OAuth" }), Transport.AuthenticationMethod.Token({
|
|
1898
|
-
label: "Connect with token",
|
|
1899
|
-
placeholder: "Paste API token"
|
|
1900
|
-
})],
|
|
1901
|
-
id: "cloudflare",
|
|
1902
|
-
name: "Cloudflare",
|
|
1903
|
-
...overrides
|
|
1904
|
-
});
|
|
1905
|
-
const target = (overrides = {}) => ({
|
|
1906
|
-
accountId: "account-1",
|
|
1907
|
-
accountKind: "account",
|
|
1908
|
-
zoneId: "zone-1",
|
|
1909
|
-
zoneName: DomainName.parse("example.com"),
|
|
1910
|
-
...overrides
|
|
1911
|
-
});
|
|
1912
|
-
const connection = (overrides = {}) => ({
|
|
1913
|
-
createdAt: /* @__PURE__ */ new Date("2026-08-30T00:00:00.000Z"),
|
|
1914
|
-
id: "connection-1",
|
|
1915
|
-
method: "oauth2",
|
|
1916
|
-
ownerId: "organization-1",
|
|
1917
|
-
providerId: "cloudflare",
|
|
1918
|
-
status: "active",
|
|
1919
|
-
...overrides
|
|
1920
|
-
});
|
|
1921
|
-
const attachment = (overrides = {}) => ({
|
|
1922
|
-
connectionId: "connection-1",
|
|
1923
|
-
createdAt: /* @__PURE__ */ new Date("2026-08-30T00:00:00.000Z"),
|
|
1924
|
-
domain: DomainName.parse("mail.example.com"),
|
|
1925
|
-
id: "attachment-1",
|
|
1926
|
-
target: target(),
|
|
1927
|
-
...overrides
|
|
1928
|
-
});
|
|
1929
|
-
const connected = (overrides = {}) => Transport.Connected({
|
|
1930
|
-
attachment: attachment(),
|
|
1931
|
-
connection: connection(),
|
|
1932
|
-
provider: provider(),
|
|
1933
|
-
...overrides
|
|
1934
|
-
});
|
|
1935
|
-
function makeFakeTransport(options) {
|
|
1936
|
-
const calls = {
|
|
1937
|
-
apply: [],
|
|
1938
|
-
attach: [],
|
|
1939
|
-
cleanupApply: [],
|
|
1940
|
-
cleanupPlan: [],
|
|
1941
|
-
connect: [],
|
|
1942
|
-
detach: [],
|
|
1943
|
-
inspect: [],
|
|
1944
|
-
observe: [],
|
|
1945
|
-
plan: []
|
|
1946
|
-
};
|
|
1947
|
-
const inspections = Array.isArray(options.inspect) ? [...options.inspect] : [options.inspect];
|
|
1948
|
-
const transport = {
|
|
1949
|
-
cleanup: {
|
|
1950
|
-
apply: async (input) => {
|
|
1951
|
-
calls.cleanupApply.push(input);
|
|
1952
|
-
return options.cleanupApply ?? Transport.CleanupResult.Cleaned({
|
|
1953
|
-
operationId: "cleanup-operation-1",
|
|
1954
|
-
results: []
|
|
1955
|
-
});
|
|
1956
|
-
},
|
|
1957
|
-
plan: async (input) => {
|
|
1958
|
-
calls.cleanupPlan.push(input);
|
|
1959
|
-
return options.cleanupPlan ?? Transport.CleanupPlan({
|
|
1960
|
-
digest: "cleanup-digest-1",
|
|
1961
|
-
expiresAt: "2099-01-01T00:00:00.000Z",
|
|
1962
|
-
operations: []
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
},
|
|
1966
|
-
connection: {
|
|
1967
|
-
connect: async (input) => {
|
|
1968
|
-
calls.connect.push(input);
|
|
1969
|
-
return options.connect ?? Transport.Connected({
|
|
1970
|
-
attachment: attachment({ domain: DomainName.parse(input.domain) }),
|
|
1971
|
-
connection: connection(),
|
|
1972
|
-
provider: provider()
|
|
1973
|
-
});
|
|
1974
|
-
},
|
|
1975
|
-
inspect: async (input) => {
|
|
1976
|
-
calls.inspect.push(input);
|
|
1977
|
-
const snapshot = inspections.shift() ?? inspections.at(-1) ?? options.inspect;
|
|
1978
|
-
if (Array.isArray(snapshot)) throw new Error("Fake inspection sequence is empty");
|
|
1979
|
-
if (snapshot._tag === "Failure") throw new Transport.Failure({
|
|
1980
|
-
message: snapshot.message,
|
|
1981
|
-
operation: snapshot.operation ?? "connection.inspect",
|
|
1982
|
-
retry: snapshot.retry
|
|
1983
|
-
});
|
|
1984
|
-
return snapshot;
|
|
1985
|
-
},
|
|
1986
|
-
attach: async (input) => {
|
|
1987
|
-
calls.attach.push(input);
|
|
1988
|
-
return options.attach ?? Transport.Connected({
|
|
1989
|
-
attachment: attachment({
|
|
1990
|
-
connectionId: input.connectionId,
|
|
1991
|
-
domain: DomainName.parse(input.domain),
|
|
1992
|
-
target: input.target
|
|
1993
|
-
}),
|
|
1994
|
-
connection: connection({ id: input.connectionId }),
|
|
1995
|
-
provider: provider()
|
|
1996
|
-
});
|
|
1997
|
-
},
|
|
1998
|
-
detach: async (input) => {
|
|
1999
|
-
calls.detach.push(input);
|
|
2000
|
-
return options.detach ?? Transport.DetachResult({
|
|
2001
|
-
attachment: attachment(),
|
|
2002
|
-
connection: connection(),
|
|
2003
|
-
remainingAttachments: 0
|
|
2004
|
-
});
|
|
2005
|
-
}
|
|
2006
|
-
},
|
|
2007
|
-
provisioning: {
|
|
2008
|
-
apply: async (input) => {
|
|
2009
|
-
calls.apply.push(input);
|
|
2010
|
-
return options.apply ?? Transport.ApplyResult.Applied({
|
|
2011
|
-
operationId: "apply-operation-1",
|
|
2012
|
-
receiptId: "receipt-1",
|
|
2013
|
-
results: []
|
|
2014
|
-
});
|
|
2015
|
-
},
|
|
2016
|
-
plan: async (input) => {
|
|
2017
|
-
calls.plan.push(input);
|
|
2018
|
-
return options.plan ?? Transport.ProvisioningPlan({
|
|
2019
|
-
digest: "plan-digest-1",
|
|
2020
|
-
expiresAt: "2099-01-01T00:00:00.000Z",
|
|
2021
|
-
operations: input.records.map((record) => Transport.PlanOperation.Create({
|
|
2022
|
-
id: `create-${record.id}`,
|
|
2023
|
-
record
|
|
2024
|
-
}))
|
|
2025
|
-
});
|
|
2026
|
-
}
|
|
2027
|
-
},
|
|
2028
|
-
verification: { observe: async (input) => {
|
|
2029
|
-
calls.observe.push(input);
|
|
2030
|
-
return options.observe ?? Transport.Observation({
|
|
2031
|
-
provider: input.sources.provider ? input.records.map((record) => Transport.ObservationEvidence.Found({ recordId: record.id })) : [],
|
|
2032
|
-
publicDns: input.sources.publicDns ? input.records.map((record) => Transport.ObservationEvidence.Found({ recordId: record.id })) : []
|
|
2033
|
-
});
|
|
2034
|
-
} }
|
|
2035
|
-
};
|
|
2036
|
-
return Object.assign(Transport.layerFromAsync(transport), transport, { calls });
|
|
2037
|
-
}
|
|
2431
|
+
/**
|
|
2432
|
+
* The fake transport `@domainkit/react` tests render against: an in-memory `domainkit/server`
|
|
2433
|
+
* with memory storage and a fake provider, recording every call.
|
|
2434
|
+
*/
|
|
2435
|
+
var testing_exports = /* @__PURE__ */ __exportAll({ transport: () => transport });
|
|
2436
|
+
const transport = Testing.transport;
|
|
2437
|
+
//#endregion
|
|
2438
|
+
//#region src/failure.ts
|
|
2439
|
+
const Failure = Data.taggedEnum();
|
|
2038
2440
|
//#endregion
|
|
2039
|
-
export { cleanup_exports as Cleanup,
|
|
2441
|
+
export { cleanup_exports as Cleanup, connect_exports as Connect, domain_exports as Domain, domain_kit_exports as DomainKit, Event, Failure, messages_exports as Messages, operations_exports as Operations, provider_exports as Provider, provision_exports as Provision, records_exports as Records, testing_exports as Testing, theme_exports as Theme, verify_exports as Verify, defaultIcons, useIcons };
|
|
2040
2442
|
|
|
2041
2443
|
//# sourceMappingURL=index.mjs.map
|