domainkit 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 +213 -41
- package/dist/Approval.mjs +34 -0
- package/dist/Approval.mjs.map +1 -0
- package/dist/Cleanup.mjs +97 -0
- package/dist/Cleanup.mjs.map +1 -0
- package/dist/Cloudflare.mjs +225 -0
- package/dist/Cloudflare.mjs.map +1 -0
- package/dist/Connect.mjs +463 -0
- package/dist/Connect.mjs.map +1 -0
- package/dist/Custody.mjs +64 -0
- package/dist/Custody.mjs.map +1 -0
- package/dist/DnsRecord.mjs +213 -0
- package/dist/DnsRecord.mjs.map +1 -0
- package/dist/DomainKit.mjs +34 -0
- package/dist/DomainKit.mjs.map +1 -0
- package/dist/DomainName.mjs +100 -0
- package/dist/DomainName.mjs.map +1 -0
- package/dist/Plan.mjs +102 -0
- package/dist/Plan.mjs.map +1 -0
- package/dist/Principal.mjs +23 -0
- package/dist/Principal.mjs.map +1 -0
- package/dist/Provider.mjs +130 -0
- package/dist/Provider.mjs.map +1 -0
- package/dist/Providers.mjs +40 -0
- package/dist/Providers.mjs.map +1 -0
- package/dist/Provision.mjs +93 -0
- package/dist/Provision.mjs.map +1 -0
- package/dist/Reason.mjs +162 -0
- package/dist/Reason.mjs.map +1 -0
- package/dist/Receipt.mjs +71 -0
- package/dist/Receipt.mjs.map +1 -0
- package/dist/Resolver.mjs +75 -0
- package/dist/Resolver.mjs.map +1 -0
- package/dist/Server.mjs +516 -0
- package/dist/Server.mjs.map +1 -0
- package/dist/Storage.mjs +236 -0
- package/dist/Storage.mjs.map +1 -0
- package/dist/Testing.mjs +226 -0
- package/dist/Testing.mjs.map +1 -0
- package/dist/Transport.mjs +187 -0
- package/dist/Transport.mjs.map +1 -0
- package/dist/Vercel.mjs +116 -0
- package/dist/Vercel.mjs.map +1 -0
- package/dist/Verify.mjs +292 -0
- package/dist/Verify.mjs.map +1 -0
- package/dist/{rolldown-runtime-D7D4PA-g.mjs → _virtual/_rolldown/runtime.mjs} +1 -1
- package/dist/entry/client.mjs +2 -0
- package/dist/entry/server.mjs +2 -0
- package/dist/entry/testing.mjs +3 -0
- package/dist/index.mjs +33 -462
- package/dist/index.mjs.map +1 -1
- package/dist/internal/aes.mjs +61 -0
- package/dist/internal/aes.mjs.map +1 -0
- package/dist/internal/attempts.mjs +284 -0
- package/dist/internal/attempts.mjs.map +1 -0
- package/dist/internal/cloudflare/client.mjs +100 -0
- package/dist/internal/cloudflare/client.mjs.map +1 -0
- package/dist/internal/cloudflare/protocol.mjs +59 -0
- package/dist/internal/cloudflare/protocol.mjs.map +1 -0
- package/dist/internal/cloudflare/records.mjs +156 -0
- package/dist/internal/cloudflare/records.mjs.map +1 -0
- package/dist/internal/config.mjs +13 -0
- package/dist/internal/config.mjs.map +1 -0
- package/dist/internal/conformance/provider.mjs +207 -0
- package/dist/internal/conformance/provider.mjs.map +1 -0
- package/dist/internal/conformance/storage.mjs +428 -0
- package/dist/internal/conformance/storage.mjs.map +1 -0
- package/dist/internal/digest.mjs +25 -0
- package/dist/internal/digest.mjs.map +1 -0
- package/dist/internal/doh.mjs +153 -0
- package/dist/internal/doh.mjs.map +1 -0
- package/dist/internal/error.mjs +69 -0
- package/dist/internal/error.mjs.map +1 -0
- package/dist/internal/http.mjs +90 -0
- package/dist/internal/http.mjs.map +1 -0
- package/dist/internal/ids.mjs +8 -0
- package/dist/internal/ids.mjs.map +1 -0
- package/dist/internal/oauth.mjs +113 -0
- package/dist/internal/oauth.mjs.map +1 -0
- package/dist/internal/planner.mjs +88 -0
- package/dist/internal/planner.mjs.map +1 -0
- package/dist/internal/provider-async.mjs +83 -0
- package/dist/internal/provider-async.mjs.map +1 -0
- package/dist/internal/storage-memory.mjs +302 -0
- package/dist/internal/storage-memory.mjs.map +1 -0
- package/dist/internal/vercel/client.mjs +122 -0
- package/dist/internal/vercel/client.mjs.map +1 -0
- package/dist/internal/vercel/protocol.mjs +80 -0
- package/dist/internal/vercel/protocol.mjs.map +1 -0
- package/dist/internal/vercel/records.mjs +151 -0
- package/dist/internal/vercel/records.mjs.map +1 -0
- package/dist/package.mjs +6 -0
- package/dist/package.mjs.map +1 -0
- package/dist/types/Approval.d.ts +26 -0
- package/dist/types/Cleanup.d.ts +41 -0
- package/dist/types/Cloudflare.d.ts +36 -0
- package/dist/types/Connect.d.ts +506 -0
- package/dist/types/Custody.d.ts +38 -0
- package/dist/types/DnsRecord.d.ts +158 -0
- package/dist/types/DomainKit.d.ts +31 -0
- package/dist/types/DomainName.d.ts +27 -0
- package/dist/types/Plan.d.ts +76 -0
- package/dist/types/Principal.d.ts +18 -0
- package/dist/types/Provider.d.ts +248 -0
- package/dist/types/Providers.d.ts +16 -0
- package/dist/types/Provision.d.ts +75 -0
- package/dist/types/Reason.d.ts +118 -0
- package/dist/types/Receipt.d.ts +55 -0
- package/dist/types/Resolver.d.ts +135 -0
- package/dist/types/Server.d.ts +6523 -0
- package/dist/types/Storage.d.ts +314 -0
- package/dist/types/Testing.d.ts +84 -0
- package/dist/types/Transport.d.ts +124 -0
- package/dist/types/Vercel.d.ts +25 -0
- package/dist/types/Verify.d.ts +109 -0
- package/dist/types/entry/client.d.ts +2 -0
- package/dist/types/entry/server.d.ts +2 -0
- package/dist/types/entry/testing.d.ts +3 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/internal/aes.d.ts +8 -0
- package/dist/types/internal/attempts.d.ts +40 -0
- package/dist/types/internal/cloudflare/client.d.ts +23 -0
- package/dist/types/internal/cloudflare/protocol.d.ts +71 -0
- package/dist/types/internal/cloudflare/records.d.ts +8 -0
- package/dist/types/internal/config.d.ts +4 -0
- package/dist/types/internal/conformance/provider.d.ts +12 -0
- package/dist/types/internal/conformance/storage.d.ts +14 -0
- package/dist/types/internal/digest.d.ts +10 -0
- package/dist/types/internal/doh.d.ts +19 -0
- package/dist/types/internal/error.d.ts +24 -0
- package/dist/types/internal/http.d.ts +27 -0
- package/dist/types/internal/ids.d.ts +3 -0
- package/dist/types/internal/oauth.d.ts +58 -0
- package/dist/types/internal/planner.d.ts +22 -0
- package/dist/types/internal/provider-async.d.ts +78 -0
- package/dist/types/internal/storage-memory.d.ts +2 -0
- package/dist/types/internal/vercel/client.d.ts +29 -0
- package/dist/types/internal/vercel/protocol.d.ts +124 -0
- package/dist/types/internal/vercel/records.d.ts +7 -0
- package/package.json +88 -12
- package/dist/canonical-json-CQYKsZw7.mjs +0 -310
- package/dist/canonical-json-CQYKsZw7.mjs.map +0 -1
- package/dist/connect-D-X8T9W8.d.mts +0 -1597
- package/dist/connect-oI8hcMxc.mjs +0 -185
- package/dist/connect-oI8hcMxc.mjs.map +0 -1
- package/dist/connection-Dp6ZdSo8.d.mts +0 -186
- package/dist/connection-api-lqG1nBtD.d.mts +0 -26
- package/dist/index.d.mts +0 -1551
- package/dist/managed-dns-connections-C3A_GBaz.mjs +0 -99
- package/dist/managed-dns-connections-C3A_GBaz.mjs.map +0 -1
- package/dist/promise.d.mts +0 -378
- package/dist/promise.mjs +0 -598
- package/dist/promise.mjs.map +0 -1
- package/dist/resolver-BeGz1ukw.mjs +0 -921
- package/dist/resolver-BeGz1ukw.mjs.map +0 -1
- package/dist/resolver-xoSwyXDJ.d.mts +0 -3734
- package/dist/server.d.mts +0 -128
- package/dist/server.mjs +0 -319
- package/dist/server.mjs.map +0 -1
- package/dist/testing.d.mts +0 -62
- package/dist/testing.mjs +0 -507
- package/dist/testing.mjs.map +0 -1
- package/dist/verify-DvGPb5C9.mjs +0 -2402
- package/dist/verify-DvGPb5C9.mjs.map +0 -1
- package/dist/verify-FpunAcM7.d.mts +0 -1335
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS record requirements a product asks a customer to satisfy, and the observed records a
|
|
3
|
+
* provider or resolver reports back.
|
|
4
|
+
*
|
|
5
|
+
* Constructors are lowercase functions (`DnsRecord.cname(...)`), Effect style. `policy` defaults
|
|
6
|
+
* to `exclusive` for CNAME and `append` for everything else; `ttl` defaults to `null` (provider
|
|
7
|
+
* default); `purpose` is an optional human label the UI shows.
|
|
8
|
+
*/
|
|
9
|
+
import { Schema } from "effect";
|
|
10
|
+
export declare const Type: Schema.Literals<readonly ["A", "AAAA", "CNAME", "TXT", "MX", "CAA", "NS", "SRV"]>;
|
|
11
|
+
export type Type = typeof Type.Type;
|
|
12
|
+
export declare const Policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
13
|
+
export type Policy = typeof Policy.Type;
|
|
14
|
+
declare const A_base: Schema.Class<A, Schema.TaggedStruct<"A", {
|
|
15
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
16
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
17
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
18
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
19
|
+
readonly address: Schema.String;
|
|
20
|
+
}>, {}>;
|
|
21
|
+
export declare class A extends A_base {
|
|
22
|
+
}
|
|
23
|
+
declare const AAAA_base: Schema.Class<AAAA, Schema.TaggedStruct<"AAAA", {
|
|
24
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
25
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
26
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
27
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
28
|
+
readonly address: Schema.String;
|
|
29
|
+
}>, {}>;
|
|
30
|
+
export declare class AAAA extends AAAA_base {
|
|
31
|
+
}
|
|
32
|
+
declare const CNAME_base: Schema.Class<CNAME, Schema.TaggedStruct<"CNAME", {
|
|
33
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
34
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
35
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
36
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
37
|
+
readonly target: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
38
|
+
}>, {}>;
|
|
39
|
+
export declare class CNAME extends CNAME_base {
|
|
40
|
+
}
|
|
41
|
+
declare const TXT_base: Schema.Class<TXT, Schema.TaggedStruct<"TXT", {
|
|
42
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
43
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
44
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
45
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
46
|
+
readonly value: Schema.String;
|
|
47
|
+
}>, {}>;
|
|
48
|
+
export declare class TXT extends TXT_base {
|
|
49
|
+
}
|
|
50
|
+
declare const MX_base: Schema.Class<MX, Schema.TaggedStruct<"MX", {
|
|
51
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
52
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
53
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
54
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
55
|
+
readonly exchange: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
56
|
+
readonly priority: Schema.Int;
|
|
57
|
+
}>, {}>;
|
|
58
|
+
export declare class MX extends MX_base {
|
|
59
|
+
}
|
|
60
|
+
declare const CAA_base: Schema.Class<CAA, Schema.TaggedStruct<"CAA", {
|
|
61
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
62
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
63
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
64
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
65
|
+
readonly flags: Schema.Int;
|
|
66
|
+
readonly tag: Schema.String;
|
|
67
|
+
readonly value: Schema.String;
|
|
68
|
+
}>, {}>;
|
|
69
|
+
export declare class CAA extends CAA_base {
|
|
70
|
+
}
|
|
71
|
+
declare const NS_base: Schema.Class<NS, Schema.TaggedStruct<"NS", {
|
|
72
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
73
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
74
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
75
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
76
|
+
readonly nameserver: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
77
|
+
}>, {}>;
|
|
78
|
+
export declare class NS extends NS_base {
|
|
79
|
+
}
|
|
80
|
+
declare const SRV_base: Schema.Class<SRV, Schema.TaggedStruct<"SRV", {
|
|
81
|
+
readonly name: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
82
|
+
readonly ttl: Schema.NullOr<Schema.Int>;
|
|
83
|
+
readonly policy: Schema.Literals<readonly ["exclusive", "append"]>;
|
|
84
|
+
readonly purpose: Schema.optionalKey<Schema.String>;
|
|
85
|
+
readonly target: Schema.suspend<Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>>;
|
|
86
|
+
readonly port: Schema.Int;
|
|
87
|
+
readonly priority: Schema.Int;
|
|
88
|
+
readonly weight: Schema.Int;
|
|
89
|
+
}>, {}>;
|
|
90
|
+
export declare class SRV extends SRV_base {
|
|
91
|
+
}
|
|
92
|
+
export declare const Model: Schema.Union<readonly [typeof A, typeof AAAA, typeof CNAME, typeof TXT, typeof MX, typeof CAA, typeof NS, typeof SRV]>;
|
|
93
|
+
export type Model = typeof Model.Type;
|
|
94
|
+
export type Encoded = typeof Model.Encoded;
|
|
95
|
+
declare const Opaque_base: Schema.Class<Opaque, Schema.TaggedStruct<"Opaque", {
|
|
96
|
+
readonly name: Schema.String;
|
|
97
|
+
readonly type: Schema.String;
|
|
98
|
+
readonly raw: Schema.Unknown;
|
|
99
|
+
}>, {}>;
|
|
100
|
+
/** A provider record DomainKit cannot model but must not overwrite. */
|
|
101
|
+
export declare class Opaque extends Opaque_base {
|
|
102
|
+
}
|
|
103
|
+
export declare const Observed: Schema.Union<readonly [Schema.Union<readonly [typeof A, typeof AAAA, typeof CNAME, typeof TXT, typeof MX, typeof CAA, typeof NS, typeof SRV]>, typeof Opaque]>;
|
|
104
|
+
export type Observed = typeof Observed.Type;
|
|
105
|
+
type Options = {
|
|
106
|
+
readonly ttl?: number;
|
|
107
|
+
readonly policy?: Policy;
|
|
108
|
+
readonly purpose?: string;
|
|
109
|
+
};
|
|
110
|
+
export declare const a: (input: {
|
|
111
|
+
readonly name: string;
|
|
112
|
+
readonly address: string;
|
|
113
|
+
} & Options) => A;
|
|
114
|
+
export declare const aaaa: (input: {
|
|
115
|
+
readonly name: string;
|
|
116
|
+
readonly address: string;
|
|
117
|
+
} & Options) => AAAA;
|
|
118
|
+
export declare const cname: (input: {
|
|
119
|
+
readonly name: string;
|
|
120
|
+
readonly target: string;
|
|
121
|
+
} & Omit<Options, "policy">) => CNAME;
|
|
122
|
+
export declare const txt: (input: {
|
|
123
|
+
readonly name: string;
|
|
124
|
+
readonly value: string;
|
|
125
|
+
} & Options) => TXT;
|
|
126
|
+
export declare const mx: (input: {
|
|
127
|
+
readonly name: string;
|
|
128
|
+
readonly exchange: string;
|
|
129
|
+
readonly priority: number;
|
|
130
|
+
} & Options) => MX;
|
|
131
|
+
export declare const caa: (input: {
|
|
132
|
+
readonly name: string;
|
|
133
|
+
readonly flags: number;
|
|
134
|
+
readonly tag: string;
|
|
135
|
+
readonly value: string;
|
|
136
|
+
} & Options) => CAA;
|
|
137
|
+
export declare const ns: (input: {
|
|
138
|
+
readonly name: string;
|
|
139
|
+
readonly nameserver: string;
|
|
140
|
+
} & Options) => NS;
|
|
141
|
+
export declare const srv: (input: {
|
|
142
|
+
readonly name: string;
|
|
143
|
+
readonly target: string;
|
|
144
|
+
readonly port: number;
|
|
145
|
+
readonly priority: number;
|
|
146
|
+
readonly weight: number;
|
|
147
|
+
} & Options) => SRV;
|
|
148
|
+
export declare const isDnsRecord: (input: unknown) => input is Model;
|
|
149
|
+
/** The record's data portion as a canonical string, for display and zone-file rendering. */
|
|
150
|
+
export declare const data: (record: Model) => string;
|
|
151
|
+
/**
|
|
152
|
+
* Structural equality over type, name, and data. `ttl`, `policy`, and `purpose` are requirement
|
|
153
|
+
* metadata, not record identity, so they are ignored; TTL drift is reported on plan operations.
|
|
154
|
+
*/
|
|
155
|
+
export declare const equals: (left: Observed, right: Observed) => boolean;
|
|
156
|
+
/** `true` when both records occupy the same name and type, regardless of data. */
|
|
157
|
+
export declare const sameSet: (left: Observed, right: Observed) => boolean;
|
|
158
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composed layer. Provides every lifecycle service given a list of providers; the host
|
|
3
|
+
* provides `Storage` and `Custody` beneath it, the same way `Persistence.layer` sits over a
|
|
4
|
+
* backing store in Effect.
|
|
5
|
+
*
|
|
6
|
+
* Defaults: `Resolver.layer` (Cloudflare + Google DoH) and the `Policy` references. Override a
|
|
7
|
+
* policy with `Effect.provideService`; pass `resolver` for a different pool.
|
|
8
|
+
*/
|
|
9
|
+
import { Layer } from "effect";
|
|
10
|
+
import * as Cleanup from "./Cleanup.ts";
|
|
11
|
+
import * as Connect from "./Connect.ts";
|
|
12
|
+
import * as Custody from "./Custody.ts";
|
|
13
|
+
import { DomainKitError } from "./internal/error.ts";
|
|
14
|
+
import type * as Provider from "./Provider.ts";
|
|
15
|
+
import * as Providers from "./Providers.ts";
|
|
16
|
+
import * as Provision from "./Provision.ts";
|
|
17
|
+
import * as Resolver from "./Resolver.ts";
|
|
18
|
+
import * as Storage from "./Storage.ts";
|
|
19
|
+
import * as Verify from "./Verify.ts";
|
|
20
|
+
export { DomainKitError as Error };
|
|
21
|
+
export type { Category as ErrorCategory } from "./internal/error.ts";
|
|
22
|
+
export declare const isError: (input: unknown) => input is DomainKitError;
|
|
23
|
+
export interface Options {
|
|
24
|
+
readonly providers: ReadonlyArray<Provider.Definition>;
|
|
25
|
+
/** Replace the public DNS pool (e.g. `Testing.resolver()`); default `Resolver.layer`. */
|
|
26
|
+
readonly resolver?: Layer.Layer<Resolver.Service>;
|
|
27
|
+
}
|
|
28
|
+
export type Services = Provision.Service | Cleanup.Service | Connect.Service | Verify.Service | Providers.Service | Resolver.Service;
|
|
29
|
+
export declare const layer: (options: Options) => Layer.Layer<Services, never, Storage.Service | Custody.Service>;
|
|
30
|
+
/** `layer` with `Storage.layerMemory` and a throwaway custody key. Tests and playgrounds only. */
|
|
31
|
+
export declare const layerMemory: (options: Options) => Layer.Layer<Services | Storage.Service | Custody.Service, DomainKitError>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A normalized, IDN-aware hostname. Lifecycle inputs accept plain strings and validate them, so
|
|
3
|
+
* most hosts never construct this directly; it exists for hosts that want the brand in their own
|
|
4
|
+
* types.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect, Option, Schema } from "effect";
|
|
7
|
+
import * as Errors from "./internal/error.ts";
|
|
8
|
+
declare const Branded: Schema.brand<Schema.String, "@domainkit/DomainName">;
|
|
9
|
+
/** Decodes any hostname spelling into its normalized, branded form; encodes back to a string. */
|
|
10
|
+
export declare const Model: Schema.decodeTo<Schema.brand<Schema.String, "@domainkit/DomainName">, Schema.String, never, never>;
|
|
11
|
+
export type Model = typeof Branded.Type;
|
|
12
|
+
/** Validates and normalizes; `None` when the input is not a hostname. */
|
|
13
|
+
export declare const fromString: (input: string) => Option.Option<Model>;
|
|
14
|
+
/** Validates and normalizes; throws `DomainKit.Error` (reason `InvalidInput`) when invalid. */
|
|
15
|
+
export declare const fromStringUnsafe: (input: string) => Model;
|
|
16
|
+
/** Validates and normalizes inside Effect; fails with reason `InvalidInput`. */
|
|
17
|
+
export declare const decode: (input: string, field?: string) => Effect.Effect<Model, Errors.DomainKitError>;
|
|
18
|
+
export declare const isDomainName: (input: unknown) => input is Model;
|
|
19
|
+
/**
|
|
20
|
+
* Zone candidates from the name itself down to the registrable domain, most specific first:
|
|
21
|
+
* `a.b.example.com` -> `a.b.example.com`, `b.example.com`, `example.com`. Empty when the name has
|
|
22
|
+
* no registrable suffix.
|
|
23
|
+
*/
|
|
24
|
+
export declare const candidates: (domain: Model) => ReadonlyArray<Model>;
|
|
25
|
+
/** `true` when `name` is `zone` or a subdomain of it. */
|
|
26
|
+
export declare const isWithin: (name: string, zone: string) => boolean;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reviewable, digest-bound set of DNS operations. Plans are additive and fail closed: matching
|
|
3
|
+
* records are `Noop`, missing records are `Create`, incompatible state is `Conflict`. A
|
|
4
|
+
* provisioning plan never updates or deletes; a cleanup plan carries `Delete` operations for
|
|
5
|
+
* records a receipt proves DomainKit created.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect, Schema } from "effect";
|
|
8
|
+
import * as DnsRecord from "./DnsRecord.ts";
|
|
9
|
+
import * as Errors from "./internal/error.ts";
|
|
10
|
+
export declare const PlanId: Schema.brand<Schema.String, "@domainkit/PlanId">;
|
|
11
|
+
export type PlanId = typeof PlanId.Type;
|
|
12
|
+
export declare const Digest: Schema.brand<Schema.String, "@domainkit/Digest">;
|
|
13
|
+
export type Digest = typeof Digest.Type;
|
|
14
|
+
export declare const OperationId: Schema.brand<Schema.String, "@domainkit/OperationId">;
|
|
15
|
+
export type OperationId = typeof OperationId.Type;
|
|
16
|
+
export declare const Kind: Schema.Literals<readonly ["provisioning", "cleanup"]>;
|
|
17
|
+
export type Kind = typeof Kind.Type;
|
|
18
|
+
declare const Create_base: Schema.Class<Create, Schema.TaggedStruct<"Create", {
|
|
19
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/OperationId">;
|
|
20
|
+
readonly record: Schema.suspend<Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>>;
|
|
21
|
+
}>, {}>;
|
|
22
|
+
export declare class Create extends Create_base {
|
|
23
|
+
}
|
|
24
|
+
declare const Noop_base: Schema.Class<Noop, Schema.TaggedStruct<"Noop", {
|
|
25
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/OperationId">;
|
|
26
|
+
readonly record: Schema.suspend<Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>>;
|
|
27
|
+
readonly existing: Schema.suspend<Schema.Union<readonly [Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>, typeof DnsRecord.Opaque]>>;
|
|
28
|
+
readonly ttlDrift: Schema.Boolean;
|
|
29
|
+
}>, {}>;
|
|
30
|
+
export declare class Noop extends Noop_base {
|
|
31
|
+
}
|
|
32
|
+
declare const Conflict_base: Schema.Class<Conflict, Schema.TaggedStruct<"Conflict", {
|
|
33
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/OperationId">;
|
|
34
|
+
readonly record: Schema.suspend<Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>>;
|
|
35
|
+
readonly existing: Schema.$Array<Schema.suspend<Schema.Union<readonly [Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>, typeof DnsRecord.Opaque]>>>;
|
|
36
|
+
readonly reason: Schema.Literals<readonly ["exclusive-name", "cname-collision", "value-mismatch", "opaque", "missing"]>;
|
|
37
|
+
}>, {}>;
|
|
38
|
+
export declare class Conflict extends Conflict_base {
|
|
39
|
+
}
|
|
40
|
+
declare const Delete_base: Schema.Class<Delete, Schema.TaggedStruct<"Delete", {
|
|
41
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/OperationId">;
|
|
42
|
+
readonly record: Schema.suspend<Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>>;
|
|
43
|
+
readonly providerRecordId: Schema.String;
|
|
44
|
+
}>, {}>;
|
|
45
|
+
/** Cleanup only: remove the provider record a receipt proves DomainKit created. */
|
|
46
|
+
export declare class Delete extends Delete_base {
|
|
47
|
+
}
|
|
48
|
+
export declare const Operation: Schema.Union<readonly [typeof Create, typeof Noop, typeof Conflict, typeof Delete]>;
|
|
49
|
+
export type Operation = typeof Operation.Type;
|
|
50
|
+
export declare const Version: Schema.Literal<"domainkit.plan.v2">;
|
|
51
|
+
declare const Model_base: Schema.Class<Model, Schema.Struct<{
|
|
52
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/PlanId">;
|
|
53
|
+
readonly version: Schema.Literal<"domainkit.plan.v2">;
|
|
54
|
+
readonly kind: Schema.Literals<readonly ["provisioning", "cleanup"]>;
|
|
55
|
+
readonly digest: Schema.brand<Schema.String, "@domainkit/Digest">;
|
|
56
|
+
readonly domain: Schema.String;
|
|
57
|
+
readonly zone: Schema.String;
|
|
58
|
+
readonly provider: Schema.String;
|
|
59
|
+
readonly attachmentId: Schema.String;
|
|
60
|
+
readonly operations: Schema.$Array<Schema.Union<readonly [typeof Create, typeof Noop, typeof Conflict, typeof Delete]>>;
|
|
61
|
+
readonly createdAt: Schema.DateTimeUtcFromString;
|
|
62
|
+
readonly expiresAt: Schema.DateTimeUtcFromString;
|
|
63
|
+
}>, {}>;
|
|
64
|
+
export declare class Model extends Model_base {
|
|
65
|
+
}
|
|
66
|
+
export type Encoded = typeof Model.Encoded;
|
|
67
|
+
export declare const decode: (input: unknown) => Effect.Effect<Model, Errors.DomainKitError>;
|
|
68
|
+
export declare const encode: (plan: Model) => Encoded;
|
|
69
|
+
/** `true` when the plan has no conflicts and at least one write (`Create` or `Delete`). */
|
|
70
|
+
export declare const isApplicable: (plan: Model) => boolean;
|
|
71
|
+
export declare const conflicts: (plan: Model) => ReadonlyArray<Conflict>;
|
|
72
|
+
/** The operations that would touch the provider: creates for provisioning, deletes for cleanup. */
|
|
73
|
+
export declare const writes: (plan: Model) => ReadonlyArray<Create | Delete>;
|
|
74
|
+
/** Manual instructions for hosts whose customers apply records by hand. */
|
|
75
|
+
export declare const renderInstructions: (plan: Model) => string;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who is acting. Required by every lifecycle operation and every Storage query; there is no
|
|
3
|
+
* default, so cross-tenant access is a type error rather than a runtime check. `domainkit/server`
|
|
4
|
+
* provides it per request from the host's `Identity`.
|
|
5
|
+
*/
|
|
6
|
+
import { Context, Layer } from "effect";
|
|
7
|
+
export interface Interface {
|
|
8
|
+
/** Tenant boundary: organization, workspace, account. Storage scopes every row by it. */
|
|
9
|
+
readonly ownerId: string;
|
|
10
|
+
/** The user or automation acting on the tenant's behalf; recorded on approvals and receipts. */
|
|
11
|
+
readonly actorId: string;
|
|
12
|
+
}
|
|
13
|
+
declare const Service_base: Context.ServiceClass<Service, "@domainkit/Principal", Interface>;
|
|
14
|
+
export declare class Service extends Service_base {
|
|
15
|
+
}
|
|
16
|
+
export declare const make: (input: Interface) => Interface;
|
|
17
|
+
export declare const layer: (input: Interface) => Layer.Layer<Service>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One declarative definition per DNS provider. Auth methods are optional cases, so a provider that
|
|
3
|
+
* only issues personal tokens declares `token` and nothing else. The definition drives connection
|
|
4
|
+
* routes, refresh, the UI method catalog, and rebuilding a session from stored context.
|
|
5
|
+
*/
|
|
6
|
+
import { Data, type DateTime, Effect, Redacted, Schema } from "effect";
|
|
7
|
+
import type * as DnsRecord from "./DnsRecord.ts";
|
|
8
|
+
import * as Errors from "./internal/error.ts";
|
|
9
|
+
import * as DomainName from "./DomainName.ts";
|
|
10
|
+
import type { Capability } from "./Storage.ts";
|
|
11
|
+
export type Fx<A> = Effect.Effect<A, Errors.DomainKitError>;
|
|
12
|
+
/** A record as the provider reports it, with the id needed to read or delete it later. */
|
|
13
|
+
export interface ObservedRecord {
|
|
14
|
+
readonly record: DnsRecord.Observed;
|
|
15
|
+
readonly providerRecordId: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** What a session can do inside one zone. The only thing planning and applying touch. */
|
|
18
|
+
export interface Dns {
|
|
19
|
+
readonly list: (zone: string) => Fx<ReadonlyArray<ObservedRecord>>;
|
|
20
|
+
/** Must return the provider's id for the new record; cleanup deletes by that id. */
|
|
21
|
+
readonly create: (zone: string, record: DnsRecord.Model) => Fx<{
|
|
22
|
+
readonly providerRecordId: string;
|
|
23
|
+
}>;
|
|
24
|
+
readonly get: (zone: string, providerRecordId: string) => Fx<DnsRecord.Observed | null>;
|
|
25
|
+
readonly delete: (zone: string, providerRecordId: string) => Fx<void>;
|
|
26
|
+
}
|
|
27
|
+
/** A zone the credential can reach, with the provider identity needed to address it later. */
|
|
28
|
+
export interface Target {
|
|
29
|
+
readonly zone: string;
|
|
30
|
+
readonly context: unknown;
|
|
31
|
+
readonly label: string;
|
|
32
|
+
/** The zone's nameservers as the provider reports them; `Connect.discover` matches on them. */
|
|
33
|
+
readonly nameservers?: ReadonlyArray<string>;
|
|
34
|
+
}
|
|
35
|
+
export type Resolution = Data.TaggedEnum<{
|
|
36
|
+
Resolved: {
|
|
37
|
+
readonly target: Target;
|
|
38
|
+
};
|
|
39
|
+
SelectionRequired: {
|
|
40
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
41
|
+
};
|
|
42
|
+
NotFound: {};
|
|
43
|
+
}>;
|
|
44
|
+
export declare const Resolution: {
|
|
45
|
+
readonly $is: <Tag extends "NotFound" | "Resolved" | "SelectionRequired">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
46
|
+
readonly _tag: "NotFound";
|
|
47
|
+
}, {
|
|
48
|
+
readonly _tag: Tag;
|
|
49
|
+
}> | Extract<{
|
|
50
|
+
readonly _tag: "Resolved";
|
|
51
|
+
readonly target: Target;
|
|
52
|
+
}, {
|
|
53
|
+
readonly _tag: Tag;
|
|
54
|
+
}> | Extract<{
|
|
55
|
+
readonly _tag: "SelectionRequired";
|
|
56
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
57
|
+
}, {
|
|
58
|
+
readonly _tag: Tag;
|
|
59
|
+
}>;
|
|
60
|
+
readonly $match: {
|
|
61
|
+
<Cases extends { readonly [Tag in "NotFound" | "Resolved" | "SelectionRequired"]: (args: Extract<{
|
|
62
|
+
readonly _tag: "NotFound";
|
|
63
|
+
} | {
|
|
64
|
+
readonly _tag: "Resolved";
|
|
65
|
+
readonly target: Target;
|
|
66
|
+
} | {
|
|
67
|
+
readonly _tag: "SelectionRequired";
|
|
68
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
69
|
+
}, {
|
|
70
|
+
readonly _tag: Tag;
|
|
71
|
+
}>) => any; }>(cases: Cases): (value: {
|
|
72
|
+
readonly _tag: "NotFound";
|
|
73
|
+
} | {
|
|
74
|
+
readonly _tag: "Resolved";
|
|
75
|
+
readonly target: Target;
|
|
76
|
+
} | {
|
|
77
|
+
readonly _tag: "SelectionRequired";
|
|
78
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
79
|
+
}) => import("effect/Unify").Unify<ReturnType<Cases["NotFound" | "Resolved" | "SelectionRequired"]>>;
|
|
80
|
+
<Cases extends { readonly [Tag in "NotFound" | "Resolved" | "SelectionRequired"]: (args: Extract<{
|
|
81
|
+
readonly _tag: "NotFound";
|
|
82
|
+
} | {
|
|
83
|
+
readonly _tag: "Resolved";
|
|
84
|
+
readonly target: Target;
|
|
85
|
+
} | {
|
|
86
|
+
readonly _tag: "SelectionRequired";
|
|
87
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
88
|
+
}, {
|
|
89
|
+
readonly _tag: Tag;
|
|
90
|
+
}>) => any; }>(value: {
|
|
91
|
+
readonly _tag: "NotFound";
|
|
92
|
+
} | {
|
|
93
|
+
readonly _tag: "Resolved";
|
|
94
|
+
readonly target: Target;
|
|
95
|
+
} | {
|
|
96
|
+
readonly _tag: "SelectionRequired";
|
|
97
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
98
|
+
}, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["NotFound" | "Resolved" | "SelectionRequired"]>>;
|
|
99
|
+
};
|
|
100
|
+
readonly NotFound: Data.TaggedEnum.ConstructorFrom<{
|
|
101
|
+
readonly _tag: "NotFound";
|
|
102
|
+
}, "_tag">;
|
|
103
|
+
readonly Resolved: Data.TaggedEnum.ConstructorFrom<{
|
|
104
|
+
readonly _tag: "Resolved";
|
|
105
|
+
readonly target: Target;
|
|
106
|
+
}, "_tag">;
|
|
107
|
+
readonly SelectionRequired: Data.TaggedEnum.ConstructorFrom<{
|
|
108
|
+
readonly _tag: "SelectionRequired";
|
|
109
|
+
readonly candidates: ReadonlyArray<Target>;
|
|
110
|
+
}, "_tag">;
|
|
111
|
+
};
|
|
112
|
+
/** A credential bound to provider account context. */
|
|
113
|
+
export interface Session {
|
|
114
|
+
readonly listTargets: () => Fx<ReadonlyArray<Target>>;
|
|
115
|
+
readonly resolveTarget: (domain: string) => Fx<Resolution>;
|
|
116
|
+
readonly dns: (target: Target) => Dns;
|
|
117
|
+
/** Capabilities actually held; promoted onto the authorization after first use. */
|
|
118
|
+
readonly capabilities: () => Fx<ReadonlyArray<Capability>>;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Secret material plus the account context needed to rebuild a session. `secret` is opaque to
|
|
122
|
+
* DomainKit: a provider may pack an access token and a refresh token into it.
|
|
123
|
+
*/
|
|
124
|
+
export interface Credential {
|
|
125
|
+
readonly secret: Redacted.Redacted<string>;
|
|
126
|
+
readonly context: unknown;
|
|
127
|
+
}
|
|
128
|
+
/** A credential the provider just issued or refreshed; `null` expiry means it does not expire. */
|
|
129
|
+
export interface IssuedCredential extends Credential {
|
|
130
|
+
readonly expiresAt: DateTime.Utc | null;
|
|
131
|
+
}
|
|
132
|
+
/** Raw token-method input keyed by the provider's declared field names. */
|
|
133
|
+
export type TokenValues = Readonly<Record<string, Redacted.Redacted<string> | undefined>>;
|
|
134
|
+
export interface TokenAuth {
|
|
135
|
+
readonly label: string;
|
|
136
|
+
/** Where the customer creates the token; shown in the UI. */
|
|
137
|
+
readonly docsUrl?: string;
|
|
138
|
+
readonly requiredCapabilities: ReadonlyArray<Capability>;
|
|
139
|
+
/**
|
|
140
|
+
* The values this method needs, declared once so forms render from it: secrets as
|
|
141
|
+
* `Schema.RedactedFromValue(Schema.String)`, optional ones through `Schema.optionalKey`.
|
|
142
|
+
*/
|
|
143
|
+
readonly fields: Schema.Struct<Schema.Struct.Fields>;
|
|
144
|
+
/** Validate the values (already decoded with `fields`) and return account context. */
|
|
145
|
+
readonly authenticate: (values: TokenValues) => Fx<IssuedCredential>;
|
|
146
|
+
}
|
|
147
|
+
/** Build a `TokenAuth` whose `authenticate` receives the record decoded by `fields`. */
|
|
148
|
+
/** Field schemas whose decoding needs no services, so `authenticate` stays a plain `Fx`. */
|
|
149
|
+
export type TokenFieldSchemas = {
|
|
150
|
+
readonly [name: string]: Schema.ConstraintDecoder<unknown>;
|
|
151
|
+
};
|
|
152
|
+
export declare const tokenAuth: <const Fields extends TokenFieldSchemas>(input: {
|
|
153
|
+
readonly label: string;
|
|
154
|
+
readonly docsUrl?: string;
|
|
155
|
+
readonly requiredCapabilities: ReadonlyArray<Capability>;
|
|
156
|
+
readonly fields: Schema.Struct<Fields>;
|
|
157
|
+
readonly authenticate: (values: Schema.Struct<Fields>["Type"]) => Fx<IssuedCredential>;
|
|
158
|
+
}) => TokenAuth;
|
|
159
|
+
export interface FieldDescriptor {
|
|
160
|
+
readonly name: string;
|
|
161
|
+
readonly required: boolean;
|
|
162
|
+
readonly secret: boolean;
|
|
163
|
+
}
|
|
164
|
+
/** What a UI needs to render one auth method; `fields` is `null` for interactive methods. */
|
|
165
|
+
export interface MethodDescriptor {
|
|
166
|
+
readonly kind: AuthMethod;
|
|
167
|
+
readonly label: string;
|
|
168
|
+
readonly docsUrl: string | null;
|
|
169
|
+
readonly fields: ReadonlyArray<FieldDescriptor> | null;
|
|
170
|
+
}
|
|
171
|
+
/** Field descriptors derived from `TokenAuth.fields`: optional keys are not required, `Redacted` values are secret. */
|
|
172
|
+
export declare const tokenFields: (auth: TokenAuth) => ReadonlyArray<FieldDescriptor>;
|
|
173
|
+
export declare const describeMethods: (definition: Definition) => ReadonlyArray<MethodDescriptor>;
|
|
174
|
+
export interface CallbackInput {
|
|
175
|
+
readonly code: string;
|
|
176
|
+
/** The redirect URI registered at start; token exchanges echo it. */
|
|
177
|
+
readonly callbackUrl: string;
|
|
178
|
+
/** Every query parameter the provider appended to the callback. */
|
|
179
|
+
readonly params: Readonly<Record<string, string>>;
|
|
180
|
+
}
|
|
181
|
+
export interface OAuthAuth {
|
|
182
|
+
readonly label: string;
|
|
183
|
+
readonly scopes: ReadonlyArray<string>;
|
|
184
|
+
readonly start: (input: {
|
|
185
|
+
readonly state: string;
|
|
186
|
+
readonly callbackUrl: string;
|
|
187
|
+
readonly codeChallenge: string;
|
|
188
|
+
}) => Fx<{
|
|
189
|
+
readonly authorizationUrl: string;
|
|
190
|
+
}>;
|
|
191
|
+
readonly complete: (input: CallbackInput & {
|
|
192
|
+
readonly codeVerifier: string;
|
|
193
|
+
}) => Fx<IssuedCredential>;
|
|
194
|
+
readonly refresh: (credential: Credential) => Fx<IssuedCredential>;
|
|
195
|
+
readonly revoke?: (credential: Credential) => Fx<void>;
|
|
196
|
+
}
|
|
197
|
+
/** Marketplace-style installs (Vercel integrations) that redirect but are not OAuth. */
|
|
198
|
+
export interface IntegrationAuth {
|
|
199
|
+
readonly label: string;
|
|
200
|
+
readonly start: (input: {
|
|
201
|
+
readonly state: string;
|
|
202
|
+
readonly callbackUrl: string;
|
|
203
|
+
}) => Fx<{
|
|
204
|
+
readonly authorizationUrl: string;
|
|
205
|
+
}>;
|
|
206
|
+
readonly complete: (input: CallbackInput) => Fx<IssuedCredential>;
|
|
207
|
+
readonly refresh?: (credential: Credential) => Fx<IssuedCredential>;
|
|
208
|
+
readonly revoke?: (credential: Credential) => Fx<void>;
|
|
209
|
+
}
|
|
210
|
+
export interface Definition<Context = unknown> {
|
|
211
|
+
readonly id: string;
|
|
212
|
+
readonly name: string;
|
|
213
|
+
readonly auth: {
|
|
214
|
+
readonly token?: TokenAuth;
|
|
215
|
+
readonly oauth?: OAuthAuth;
|
|
216
|
+
readonly integration?: IntegrationAuth;
|
|
217
|
+
};
|
|
218
|
+
/** Schema for the account/zone context stored on authorizations and attachments. */
|
|
219
|
+
readonly context: Schema.Codec<Context, unknown, never, never>;
|
|
220
|
+
/** Tag written into every stored context envelope, e.g. `cloudflare.v1`; bump it with the schema. */
|
|
221
|
+
readonly contextVersion: string;
|
|
222
|
+
/** Upgrade an envelope written under an older `contextVersion`; absent means `Unsupported`. */
|
|
223
|
+
readonly migrateContext?: (envelope: Envelope) => Fx<Context>;
|
|
224
|
+
readonly session: (credential: Credential) => Session;
|
|
225
|
+
}
|
|
226
|
+
/** How provider context is persisted: the definition's version tag beside the encoded value. */
|
|
227
|
+
export declare const Envelope: Schema.Struct<{
|
|
228
|
+
readonly version: Schema.String;
|
|
229
|
+
readonly value: Schema.Unknown;
|
|
230
|
+
}>;
|
|
231
|
+
export type Envelope = typeof Envelope.Type;
|
|
232
|
+
/** Wrap a context value for storage; a value the schema rejects fails `InvalidInput`. */
|
|
233
|
+
export declare const encodeContext: <Context>(definition: Definition<Context>, value: Context) => Effect.Effect<Envelope, Errors.DomainKitError>;
|
|
234
|
+
export type AuthMethod = "token" | "oauth" | "integration";
|
|
235
|
+
/** Validates a definition: an id and at least one auth method. Throws `DomainKit.Error` otherwise. */
|
|
236
|
+
export declare const make: <Context>(definition: Definition<Context>) => Definition<Context>;
|
|
237
|
+
export declare const methods: (definition: Definition) => ReadonlyArray<AuthMethod>;
|
|
238
|
+
/**
|
|
239
|
+
* Pick the most specific zone among `targets` for `domain`: exactly one match resolves, several
|
|
240
|
+
* matches at the same depth need a selection, none is `NotFound`.
|
|
241
|
+
*/
|
|
242
|
+
export declare const resolveAmong: (domain: DomainName.Model, targets: ReadonlyArray<Target>) => Resolution;
|
|
243
|
+
/**
|
|
244
|
+
* Decode a stored envelope: the current version decodes with `context`, an older one goes
|
|
245
|
+
* through `migrateContext`, anything else fails `Unsupported`.
|
|
246
|
+
*/
|
|
247
|
+
export declare const decodeContext: <Context>(definition: Definition<Context>, stored: unknown) => Effect.Effect<Context, Errors.DomainKitError>;
|
|
248
|
+
export { type AsyncCredential, type AsyncDefinition, type AsyncDns, type AsyncIntegrationAuth, type AsyncIssuedCredential, type AsyncOAuthAuth, type AsyncSession, type AsyncTokenAuth, fromAsync, } from "./internal/provider-async.ts";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The registry of provider definitions a host enabled. Built by `DomainKit.layer`. */
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
import * as Errors from "./internal/error.ts";
|
|
4
|
+
import * as Provider from "./Provider.ts";
|
|
5
|
+
export interface Interface {
|
|
6
|
+
readonly get: (id: string) => Effect.Effect<Provider.Definition, Errors.DomainKitError>;
|
|
7
|
+
readonly list: () => ReadonlyArray<Provider.Definition>;
|
|
8
|
+
/** For UI catalogs: which methods each provider offers. */
|
|
9
|
+
readonly methods: (id: string) => Effect.Effect<ReadonlyArray<Provider.AuthMethod>, Errors.DomainKitError>;
|
|
10
|
+
}
|
|
11
|
+
declare const Service_base: Context.ServiceClass<Service, "@domainkit/Providers", Interface>;
|
|
12
|
+
export declare class Service extends Service_base {
|
|
13
|
+
}
|
|
14
|
+
export declare const make: (definitions: ReadonlyArray<Provider.Definition>) => Interface;
|
|
15
|
+
export declare const layer: (definitions: ReadonlyArray<Provider.Definition>) => Layer.Layer<Service>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plan -> approve -> apply, durable. Every step is a stored attempt, so a host can render the
|
|
3
|
+
* plan in one request, collect consent in another, and apply in a third, and a retry of any step
|
|
4
|
+
* is idempotent.
|
|
5
|
+
*/
|
|
6
|
+
import { Context, Effect, Layer } from "effect";
|
|
7
|
+
import type * as Approval from "./Approval.ts";
|
|
8
|
+
import * as Connect from "./Connect.ts";
|
|
9
|
+
import type * as DnsRecord from "./DnsRecord.ts";
|
|
10
|
+
import * as Errors from "./internal/error.ts";
|
|
11
|
+
import * as Attempts from "./internal/attempts.ts";
|
|
12
|
+
import type * as Plan from "./Plan.ts";
|
|
13
|
+
import type * as Principal from "./Principal.ts";
|
|
14
|
+
import type * as Receipt from "./Receipt.ts";
|
|
15
|
+
import * as Storage from "./Storage.ts";
|
|
16
|
+
type Fx<A> = Effect.Effect<A, Errors.DomainKitError, Principal.Service>;
|
|
17
|
+
export interface Attempt {
|
|
18
|
+
readonly plan: Plan.Model;
|
|
19
|
+
readonly status: Storage.AttemptStatus;
|
|
20
|
+
readonly approval: Approval.Model | null;
|
|
21
|
+
readonly receipt: Receipt.Model | null;
|
|
22
|
+
readonly rejection: Storage.Rejection | null;
|
|
23
|
+
}
|
|
24
|
+
export interface RejectOptions {
|
|
25
|
+
readonly reason?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface Interface {
|
|
28
|
+
/** Read provider state and build an additive plan. Fails `NotFound` when the domain is not attached. */
|
|
29
|
+
readonly plan: (input: {
|
|
30
|
+
readonly domain: string;
|
|
31
|
+
readonly requirements: ReadonlyArray<DnsRecord.Model>;
|
|
32
|
+
}) => Fx<Plan.Model>;
|
|
33
|
+
/**
|
|
34
|
+
* Record the principal's consent. Fails `Conflict` unless `allowPartial` and the selected
|
|
35
|
+
* operations are conflict-free. Approving an already-approved plan returns the same approval.
|
|
36
|
+
*/
|
|
37
|
+
readonly approve: (plan: Plan.Model | Plan.PlanId, options?: Attempts.ApproveOptions) => Fx<Approval.Model>;
|
|
38
|
+
/**
|
|
39
|
+
* Decline the plan for the acting principal; terminal. Rejecting again returns the same
|
|
40
|
+
* attempt; a plan that was approved or applied fails `Stale`.
|
|
41
|
+
*/
|
|
42
|
+
readonly reject: (plan: Plan.Model | Plan.PlanId, options?: RejectOptions) => Fx<Attempt>;
|
|
43
|
+
/**
|
|
44
|
+
* Re-plan the zone, fail `Stale` if the digest moved, then create records. Partial success is a
|
|
45
|
+
* `partial` receipt. Applying an attempt that already completed returns its receipt.
|
|
46
|
+
*/
|
|
47
|
+
readonly apply: (approval: Approval.Model | Approval.ApprovalId) => Fx<Receipt.Model>;
|
|
48
|
+
readonly get: (planId: Plan.PlanId) => Fx<Attempt>;
|
|
49
|
+
readonly latest: (domain: string) => Fx<Attempt | null>;
|
|
50
|
+
}
|
|
51
|
+
declare const Service_base: Context.ServiceClass<Service, "@domainkit/Provision", Interface>;
|
|
52
|
+
export declare class Service extends Service_base {
|
|
53
|
+
}
|
|
54
|
+
export interface PolicyShape {
|
|
55
|
+
/** Plan lifetime before it must be rebuilt. Default 1 hour. */
|
|
56
|
+
readonly planTtlMs: number;
|
|
57
|
+
/** Apply lease; a crashed apply can be retried after this. Default 2 minutes. */
|
|
58
|
+
readonly applyLeaseMs: number;
|
|
59
|
+
}
|
|
60
|
+
export declare const defaults: PolicyShape;
|
|
61
|
+
declare const Policy_base: Context.Reference<PolicyShape>;
|
|
62
|
+
export declare class Policy extends Policy_base {
|
|
63
|
+
}
|
|
64
|
+
export declare const make: Effect.Effect<Interface, never, Storage.Service | Connect.Service>;
|
|
65
|
+
export declare const layer: Layer.Layer<Service, never, Storage.Service | Connect.Service>;
|
|
66
|
+
export declare const plan: (input: {
|
|
67
|
+
readonly domain: string;
|
|
68
|
+
readonly requirements: ReadonlyArray<DnsRecord.Model>;
|
|
69
|
+
}) => Effect.Effect<Plan.Model, Errors.DomainKitError, Principal.Service | Service>;
|
|
70
|
+
export declare const approve: (plan: Plan.Model | (string & import("effect/Brand").Brand<"@domainkit/PlanId">), options?: Attempts.ApproveOptions | undefined) => Effect.Effect<Approval.Model, Errors.DomainKitError, Principal.Service | Service>;
|
|
71
|
+
export declare const reject: (plan: Plan.Model | (string & import("effect/Brand").Brand<"@domainkit/PlanId">), options?: RejectOptions | undefined) => Effect.Effect<Attempt, Errors.DomainKitError, Principal.Service | Service>;
|
|
72
|
+
export declare const apply: (approval: Approval.Model | (string & import("effect/Brand").Brand<"@domainkit/ApprovalId">)) => Effect.Effect<Receipt.Model, Errors.DomainKitError, Principal.Service | Service>;
|
|
73
|
+
export declare const get: (planId: string & import("effect/Brand").Brand<"@domainkit/PlanId">) => Effect.Effect<Attempt, Errors.DomainKitError, Principal.Service | Service>;
|
|
74
|
+
export declare const latest: (domain: string) => Effect.Effect<Attempt | null, Errors.DomainKitError, Principal.Service | Service>;
|
|
75
|
+
export {};
|