domainkit 0.9.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/dist/Resolver.mjs +1 -1
- package/dist/Resolver.mjs.map +1 -1
- package/dist/Transport.mjs +1 -1
- package/dist/Transport.mjs.map +1 -1
- package/dist/internal/doh.mjs +2 -1
- package/dist/internal/doh.mjs.map +1 -1
- package/dist/internal/http.mjs +2 -1
- package/dist/internal/http.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/package.json +1 -1
package/dist/Resolver.mjs
CHANGED
|
@@ -36,7 +36,7 @@ const defaults = {
|
|
|
36
36
|
const make = (options = {}) => Effect.gen(function* () {
|
|
37
37
|
const endpoints = options.endpoints ?? defaults.endpoints;
|
|
38
38
|
const timeoutMs = options.timeoutMs ?? defaults.timeoutMs;
|
|
39
|
-
const fetch = options.fetch ?? globalThis.fetch;
|
|
39
|
+
const fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
40
40
|
for (const endpoint of endpoints) if (!URL.canParse(endpoint.url)) return yield* fail(new InvalidInput({
|
|
41
41
|
message: `Resolver ${endpoint.name} has an invalid URL`,
|
|
42
42
|
field: "endpoints"
|
package/dist/Resolver.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resolver.mjs","names":["Errors.fail","Reason.InvalidInput","Doh.query","DomainName.decode"],"sources":["../src/Resolver.ts"],"sourcesContent":["/**\n * Public DNS observation. The default layer fans out to Cloudflare and Google DNS-over-HTTPS and\n * keeps every answer, so verification can show \"found at Cloudflare, missing at Google\".\n */\nimport { Context, Data, Effect, Layer } from \"effect\";\n\nimport type * as DnsRecord from \"./DnsRecord.ts\";\nimport * as Errors from \"./internal/error.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as DomainName from \"./DomainName.ts\";\nimport * as Doh from \"./internal/doh.ts\";\nimport type { Fetch } from \"./internal/http.ts\";\n\nexport interface Answer {\n readonly resolver: string;\n readonly records: ReadonlyArray<DnsRecord.Observed>;\n readonly negative: boolean;\n readonly ttl: number | null;\n}\n\nexport type Outcome = Data.TaggedEnum<{\n Answered: { readonly answer: Answer };\n Failed: { readonly resolver: string; readonly message: string };\n TimedOut: { readonly resolver: string };\n}>;\nexport const Outcome = Data.taggedEnum<Outcome>();\n\nexport interface Interface {\n /** Never fails: each resolver's outcome is preserved. */\n readonly resolve: (\n name: string,\n type: DnsRecord.Type,\n options?: { readonly signal?: AbortSignal | undefined },\n ) => Effect.Effect<ReadonlyArray<Outcome>>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@domainkit/Resolver\") {}\n\nexport interface Endpoint {\n readonly name: string;\n readonly url: string;\n}\n\nexport interface Options {\n readonly endpoints?: ReadonlyArray<Endpoint>;\n readonly timeoutMs?: number;\n readonly fetch?: Fetch;\n}\n\nexport const cloudflare: Endpoint = {\n name: \"cloudflare\",\n url: \"https://cloudflare-dns.com/dns-query\",\n};\nexport const google: Endpoint = { name: \"google\", url: \"https://dns.google/dns-query\" };\n\nexport const defaults = { endpoints: [cloudflare, google], timeoutMs: 3_000 } as const;\n\nexport const make = (options: Options = {}): Effect.Effect<Interface, Errors.DomainKitError> =>\n Effect.gen(function* () {\n const endpoints = options.endpoints ?? defaults.endpoints;\n const timeoutMs = options.timeoutMs ?? defaults.timeoutMs;\n const fetch = options.fetch ?? globalThis.fetch;\n for (const endpoint of endpoints) {\n if (!URL.canParse(endpoint.url)) {\n return yield* Errors.fail(\n new Reason.InvalidInput({\n message: `Resolver ${endpoint.name} has an invalid URL`,\n field: \"endpoints\",\n }),\n );\n }\n }\n const one = (\n endpoint: Endpoint,\n name: DomainName.Model,\n type: DnsRecord.Type,\n signal: AbortSignal | undefined,\n ) =>\n Doh.query({ resolver: endpoint.name, url: endpoint.url, fetch, name, type, signal }).pipe(\n Effect.timeout(timeoutMs),\n Effect.match({\n onSuccess: (answer): Outcome =>\n Outcome.Answered({ answer: { resolver: endpoint.name, ...answer } }),\n onFailure: (failure): Outcome =>\n failure._tag === \"TimeoutError\"\n ? Outcome.TimedOut({ resolver: endpoint.name })\n : Outcome.Failed({ resolver: endpoint.name, message: failure.message }),\n }),\n );\n return {\n resolve: (input, type, query) =>\n DomainName.decode(input).pipe(\n Effect.match({\n onFailure: (failure): ReadonlyArray<Outcome> =>\n endpoints.map((endpoint) =>\n Outcome.Failed({ resolver: endpoint.name, message: failure.message }),\n ),\n onSuccess: (name) => name,\n }),\n Effect.flatMap((name) =>\n typeof name === \"string\"\n ? Effect.forEach(endpoints, (endpoint) => one(endpoint, name, type, query?.signal), {\n concurrency: \"unbounded\",\n })\n : Effect.succeed(name),\n ),\n ),\n };\n });\n\n/** Cloudflare + Google DoH, 3s timeout. */\nexport const layer: Layer.Layer<Service> = Layer.effect(Service)(make().pipe(Effect.orDie));\n\nexport const layerWith = (options: Options): Layer.Layer<Service, Errors.DomainKitError> =>\n Layer.effect(Service)(make(options));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,UAAU,KAAK,WAAoB;AAWhD,IAAa,UAAb,cAA6B,QAAQ,QAA4B,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAa3F,MAAa,aAAuB;CAClC,MAAM;CACN,KAAK;AACP;AACA,MAAa,SAAmB;CAAE,MAAM;CAAU,KAAK;AAA+B;AAEtF,MAAa,WAAW;CAAE,WAAW,CAAC,YAAY,MAAM;CAAG,WAAW;AAAM;AAE5E,MAAa,QAAQ,UAAmB,CAAC,MACvC,OAAO,IAAI,aAAa;CACtB,MAAM,YAAY,QAAQ,aAAa,SAAS;CAChD,MAAM,YAAY,QAAQ,aAAa,SAAS;
|
|
1
|
+
{"version":3,"file":"Resolver.mjs","names":["Errors.fail","Reason.InvalidInput","Doh.query","DomainName.decode"],"sources":["../src/Resolver.ts"],"sourcesContent":["/**\n * Public DNS observation. The default layer fans out to Cloudflare and Google DNS-over-HTTPS and\n * keeps every answer, so verification can show \"found at Cloudflare, missing at Google\".\n */\nimport { Context, Data, Effect, Layer } from \"effect\";\n\nimport type * as DnsRecord from \"./DnsRecord.ts\";\nimport * as Errors from \"./internal/error.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as DomainName from \"./DomainName.ts\";\nimport * as Doh from \"./internal/doh.ts\";\nimport type { Fetch } from \"./internal/http.ts\";\n\nexport interface Answer {\n readonly resolver: string;\n readonly records: ReadonlyArray<DnsRecord.Observed>;\n readonly negative: boolean;\n readonly ttl: number | null;\n}\n\nexport type Outcome = Data.TaggedEnum<{\n Answered: { readonly answer: Answer };\n Failed: { readonly resolver: string; readonly message: string };\n TimedOut: { readonly resolver: string };\n}>;\nexport const Outcome = Data.taggedEnum<Outcome>();\n\nexport interface Interface {\n /** Never fails: each resolver's outcome is preserved. */\n readonly resolve: (\n name: string,\n type: DnsRecord.Type,\n options?: { readonly signal?: AbortSignal | undefined },\n ) => Effect.Effect<ReadonlyArray<Outcome>>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@domainkit/Resolver\") {}\n\nexport interface Endpoint {\n readonly name: string;\n readonly url: string;\n}\n\nexport interface Options {\n readonly endpoints?: ReadonlyArray<Endpoint>;\n readonly timeoutMs?: number;\n readonly fetch?: Fetch;\n}\n\nexport const cloudflare: Endpoint = {\n name: \"cloudflare\",\n url: \"https://cloudflare-dns.com/dns-query\",\n};\nexport const google: Endpoint = { name: \"google\", url: \"https://dns.google/dns-query\" };\n\nexport const defaults = { endpoints: [cloudflare, google], timeoutMs: 3_000 } as const;\n\nexport const make = (options: Options = {}): Effect.Effect<Interface, Errors.DomainKitError> =>\n Effect.gen(function* () {\n const endpoints = options.endpoints ?? defaults.endpoints;\n const timeoutMs = options.timeoutMs ?? defaults.timeoutMs;\n // See Transport.fromFetch: resolved at call time, never invoked as a method.\n const fetch: Fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n for (const endpoint of endpoints) {\n if (!URL.canParse(endpoint.url)) {\n return yield* Errors.fail(\n new Reason.InvalidInput({\n message: `Resolver ${endpoint.name} has an invalid URL`,\n field: \"endpoints\",\n }),\n );\n }\n }\n const one = (\n endpoint: Endpoint,\n name: DomainName.Model,\n type: DnsRecord.Type,\n signal: AbortSignal | undefined,\n ) =>\n Doh.query({ resolver: endpoint.name, url: endpoint.url, fetch, name, type, signal }).pipe(\n Effect.timeout(timeoutMs),\n Effect.match({\n onSuccess: (answer): Outcome =>\n Outcome.Answered({ answer: { resolver: endpoint.name, ...answer } }),\n onFailure: (failure): Outcome =>\n failure._tag === \"TimeoutError\"\n ? Outcome.TimedOut({ resolver: endpoint.name })\n : Outcome.Failed({ resolver: endpoint.name, message: failure.message }),\n }),\n );\n return {\n resolve: (input, type, query) =>\n DomainName.decode(input).pipe(\n Effect.match({\n onFailure: (failure): ReadonlyArray<Outcome> =>\n endpoints.map((endpoint) =>\n Outcome.Failed({ resolver: endpoint.name, message: failure.message }),\n ),\n onSuccess: (name) => name,\n }),\n Effect.flatMap((name) =>\n typeof name === \"string\"\n ? Effect.forEach(endpoints, (endpoint) => one(endpoint, name, type, query?.signal), {\n concurrency: \"unbounded\",\n })\n : Effect.succeed(name),\n ),\n ),\n };\n });\n\n/** Cloudflare + Google DoH, 3s timeout. */\nexport const layer: Layer.Layer<Service> = Layer.effect(Service)(make().pipe(Effect.orDie));\n\nexport const layerWith = (options: Options): Layer.Layer<Service, Errors.DomainKitError> =>\n Layer.effect(Service)(make(options));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,UAAU,KAAK,WAAoB;AAWhD,IAAa,UAAb,cAA6B,QAAQ,QAA4B,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAa3F,MAAa,aAAuB;CAClC,MAAM;CACN,KAAK;AACP;AACA,MAAa,SAAmB;CAAE,MAAM;CAAU,KAAK;AAA+B;AAEtF,MAAa,WAAW;CAAE,WAAW,CAAC,YAAY,MAAM;CAAG,WAAW;AAAM;AAE5E,MAAa,QAAQ,UAAmB,CAAC,MACvC,OAAO,IAAI,aAAa;CACtB,MAAM,YAAY,QAAQ,aAAa,SAAS;CAChD,MAAM,YAAY,QAAQ,aAAa,SAAS;CAEhD,MAAM,QAAe,QAAQ,WAAW,OAAO,SAAS,WAAW,MAAM,OAAO,IAAI;CACpF,KAAK,MAAM,YAAY,WACrB,IAAI,CAAC,IAAI,SAAS,SAAS,GAAG,GAC5B,OAAO,OAAOA,KACZ,IAAIC,aAAoB;EACtB,SAAS,YAAY,SAAS,KAAK;EACnC,OAAO;CACT,CAAC,CACH;CAGJ,MAAM,OACJ,UACA,MACA,MACA,WAEAC,MAAU;EAAE,UAAU,SAAS;EAAM,KAAK,SAAS;EAAK;EAAO;EAAM;EAAM;CAAO,CAAC,CAAC,CAAC,KACnF,OAAO,QAAQ,SAAS,GACxB,OAAO,MAAM;EACX,YAAY,WACV,QAAQ,SAAS,EAAE,QAAQ;GAAE,UAAU,SAAS;GAAM,GAAG;EAAO,EAAE,CAAC;EACrE,YAAY,YACV,QAAQ,SAAS,iBACb,QAAQ,SAAS,EAAE,UAAU,SAAS,KAAK,CAAC,IAC5C,QAAQ,OAAO;GAAE,UAAU,SAAS;GAAM,SAAS,QAAQ;EAAQ,CAAC;CAC5E,CAAC,CACH;CACF,OAAO,EACL,UAAU,OAAO,MAAM,UACrBC,OAAkB,KAAK,CAAC,CAAC,KACvB,OAAO,MAAM;EACX,YAAY,YACV,UAAU,KAAK,aACb,QAAQ,OAAO;GAAE,UAAU,SAAS;GAAM,SAAS,QAAQ;EAAQ,CAAC,CACtE;EACF,YAAY,SAAS;CACvB,CAAC,GACD,OAAO,SAAS,SACd,OAAO,SAAS,WACZ,OAAO,QAAQ,YAAY,aAAa,IAAI,UAAU,MAAM,MAAM,OAAO,MAAM,GAAG,EAChF,aAAa,YACf,CAAC,IACD,OAAO,QAAQ,IAAI,CACzB,CACF,EACJ;AACF,CAAC;;AAGH,MAAa,QAA8B,MAAM,OAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,CAAC;AAE1F,MAAa,aAAa,YACxB,MAAM,OAAO,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC"}
|
package/dist/Transport.mjs
CHANGED
|
@@ -45,7 +45,7 @@ const capabilities = (transport) => allCapabilities.filter((capability) => trans
|
|
|
45
45
|
const fromFetch = (baseUrl, options = {}) => {
|
|
46
46
|
const base = baseUrl.replace(/\/+$/, "");
|
|
47
47
|
const source = safeOrigin(base);
|
|
48
|
-
const call = options.fetch ?? globalThis.fetch;
|
|
48
|
+
const call = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
49
49
|
const declared = options.capabilities ?? allCapabilities;
|
|
50
50
|
const request = (input) => Effect.gen(function* () {
|
|
51
51
|
const headers = yield* headersFrom(options.headers);
|
package/dist/Transport.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transport.mjs","names":["Server.Token","Server.OAuth","Server.Integration","Http.headersFrom","Http.requestJson","Errors.decode","Errors.DomainKitError","Http.classify","Server.ApprovePayload","Approval.Model","Server.RejectPayload","Server.Attempt","Receipt.Model","Server.Snapshot","Server.Discovery","Server.StartPayload","Server.Started","Server.AttachPayload","Server.PlanPayload","Plan.Model","Server.ObservePayload","Server.Readiness","Errors.isDomainKitError","Reason.ProviderUnavailable"],"sources":["../src/Transport.ts"],"sourcesContent":["/**\n * domainkit/client — the browser-side transport `@domainkit/react` consumes. Capability groups are\n * optional: a host that only exposes connection routes declares just `connection`, and the parts\n * of the UI that plan or clean up do not render.\n *\n * const transport = Transport.fromFetch(\"/api/domainkit\")\n *\n * Every method decodes the same wire schemas `domainkit/server` encodes, so a failure arrives as\n * the `DomainKit.Error` the lifecycle raised, reason intact.\n */\nimport { Effect, Schema } from \"effect\";\n\nimport * as Approval from \"./Approval.ts\";\nimport type * as DnsRecord from \"./DnsRecord.ts\";\nimport * as Errors from \"./internal/error.ts\";\nimport * as Http from \"./internal/http.ts\";\nimport * as Plan from \"./Plan.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as Receipt from \"./Receipt.ts\";\nimport * as Server from \"./Server.ts\";\n\ntype Fx<A> = Effect.Effect<A, Errors.DomainKitError>;\n\nexport type Snapshot = Server.Snapshot;\nexport type Started = Server.Started;\nexport type Readiness = Server.Readiness;\nexport type Attempt = Server.Attempt;\nexport type Candidate = Server.Candidate;\nexport type Discovery = Server.Discovery;\nexport type Field = Server.Field;\nexport type MethodDescriptor = Server.MethodDescriptor;\nexport type Method = Server.Method;\n\n/** How a client asks to connect. Mirrors `Connect.Method`, over the wire. */\nexport const Method = {\n /** A lone string for the common one-field provider, or the values its descriptor names. */\n token: (values: string | Readonly<Record<string, string>>): Method =>\n new Server.Token({ values: typeof values === \"string\" ? { token: values } : values }),\n oauth: (options: { readonly returnTo?: string } = {}): Method => new Server.OAuth(options),\n integration: (options: { readonly returnTo?: string } = {}): Method =>\n new Server.Integration(options),\n} as const;\n\nexport interface ConnectionGroup {\n readonly inspect: (domain: string) => Fx<Snapshot>;\n /** Which of this owner's existing connections already reaches the domain. */\n readonly discover: (domain: string) => Fx<Discovery>;\n readonly start: (input: {\n readonly domain: string;\n readonly provider: string;\n readonly method: Method;\n }) => Fx<Started>;\n readonly attach: (input: {\n readonly connectionId: string;\n readonly domain: string;\n readonly zone?: string;\n }) => Fx<Started>;\n readonly detach: (attachmentId: string) => Fx<void>;\n readonly disconnect: (connectionId: string) => Fx<void>;\n}\n\nexport interface ProvisioningGroup {\n readonly plan: (input: {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n }) => Fx<Plan.Model>;\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Fx<Approval.Model>;\n /** Decline the plan; terminal, and approving it afterwards fails `Stale`. */\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Fx<Attempt>;\n readonly apply: (approvalId: Approval.ApprovalId) => Fx<Receipt.Model>;\n /** The stored plan with its status, approval, receipt, and rejection. */\n readonly attempt: (planId: Plan.PlanId) => Fx<Attempt>;\n}\n\nexport interface VerificationGroup {\n /**\n * Observe the domain's provisioning receipt, or `options.requirements` when supplied (required\n * for a domain with no attachment).\n */\n readonly observe: (\n domain: string,\n options?: { readonly requirements?: ReadonlyArray<DnsRecord.Model> },\n ) => Fx<Readiness>;\n}\n\nexport interface CleanupGroup {\n readonly plan: (receiptId: Receipt.ReceiptId) => Fx<Plan.Model>;\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Fx<Approval.Model>;\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Fx<Attempt>;\n readonly apply: (approvalId: Approval.ApprovalId) => Fx<Receipt.Model>;\n}\n\nexport interface Interface {\n readonly connection?: ConnectionGroup;\n readonly provisioning?: ProvisioningGroup;\n readonly verification?: VerificationGroup;\n readonly cleanup?: CleanupGroup;\n}\n\nexport type Capability = keyof Interface;\n\nexport const allCapabilities: ReadonlyArray<Capability> = [\n \"connection\",\n \"provisioning\",\n \"verification\",\n \"cleanup\",\n];\n\n/** Which groups this transport actually carries, in declaration order. */\nexport const capabilities = (transport: Interface): ReadonlyArray<Capability> =>\n allCapabilities.filter((capability) => transport[capability] !== undefined);\n\nexport interface FetchOptions {\n readonly fetch?: Http.Fetch;\n readonly headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n /** Which groups the server exposes. Default: all. */\n readonly capabilities?: ReadonlyArray<Capability>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// fetch\n// ---------------------------------------------------------------------------------------------\n\n/** A transport over `domainkit/server` routes mounted at `baseUrl`. */\nexport const fromFetch = (baseUrl: string, options: FetchOptions = {}): Interface => {\n const base = baseUrl.replace(/\\/+$/, \"\");\n const source = safeOrigin(base);\n const call = options.fetch ?? globalThis.fetch;\n const declared = options.capabilities ?? allCapabilities;\n\n const request = <A>(input: {\n readonly method: \"GET\" | \"POST\" | \"DELETE\";\n readonly path: string;\n readonly body?: unknown;\n readonly success: Schema.Codec<A, unknown> | null;\n }): Fx<A> =>\n Effect.gen(function* () {\n const headers = yield* Http.headersFrom(options.headers);\n if (input.body !== undefined) headers.set(\"content-type\", \"application/json\");\n const reply = yield* Http.requestJson({\n fetch: call,\n provider: source,\n url: `${base}${input.path}`,\n init: {\n method: input.method,\n headers,\n ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),\n },\n });\n if (!reply.ok) {\n // The server answers failures with the `DomainKit.Error` value itself. Anything else came\n // from in front of it: a proxy, a login page, a maintenance window.\n const decoded = yield* Effect.result(\n Errors.decode(Errors.DomainKitError, reply.body, \"response\"),\n );\n return yield* decoded._tag === \"Success\"\n ? Effect.fail(decoded.success)\n : Effect.fail(\n new Errors.DomainKitError({\n reason: Http.classify(\n source,\n reply.status,\n reply.headers,\n `${input.method} ${input.path} answered ${reply.status}`,\n ),\n }),\n );\n }\n if (input.success === null) return undefined as A;\n return yield* Errors.decode(input.success, reply.body, \"response\");\n });\n\n /** Provisioning and cleanup share these routes; the attempt knows its kind. */\n const approve = (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) =>\n request({\n method: \"POST\",\n path: `/plans/${encodeURIComponent(input.planId)}/approvals`,\n body: Schema.encodeSync(Server.ApprovePayload)(\n input.operationIds === undefined ? {} : { operationIds: input.operationIds },\n ),\n success: Approval.Model,\n });\n\n const reject = (input: { readonly planId: Plan.PlanId; readonly reason?: string }) =>\n request({\n method: \"POST\",\n path: `/plans/${encodeURIComponent(input.planId)}/rejections`,\n body: Schema.encodeSync(Server.RejectPayload)(\n input.reason === undefined ? {} : { reason: input.reason },\n ),\n success: Server.Attempt,\n });\n\n const apply = (approvalId: Approval.ApprovalId) =>\n request({\n method: \"POST\",\n path: `/approvals/${encodeURIComponent(approvalId)}/apply`,\n success: Receipt.Model,\n });\n\n const connection: ConnectionGroup = {\n inspect: (domain) =>\n request({\n method: \"GET\",\n path: `/domains/${encodeURIComponent(domain)}`,\n success: Server.Snapshot,\n }),\n discover: (domain) =>\n request({\n method: \"GET\",\n path: `/domains/${encodeURIComponent(domain)}/discovery`,\n success: Server.Discovery,\n }),\n start: (input) =>\n request({\n method: \"POST\",\n path: \"/connections\",\n body: Schema.encodeSync(Server.StartPayload)(input),\n success: Server.Started,\n }),\n attach: (input) =>\n request({\n method: \"POST\",\n path: `/connections/${encodeURIComponent(input.connectionId)}/attachments`,\n body: Schema.encodeSync(Server.AttachPayload)(\n input.zone === undefined\n ? { domain: input.domain }\n : { domain: input.domain, zone: input.zone },\n ),\n success: Server.Started,\n }),\n detach: (attachmentId) =>\n request({\n method: \"DELETE\",\n path: `/attachments/${encodeURIComponent(attachmentId)}`,\n success: null,\n }),\n disconnect: (connectionId) =>\n request({\n method: \"DELETE\",\n path: `/connections/${encodeURIComponent(connectionId)}`,\n success: null,\n }),\n };\n\n const provisioning: ProvisioningGroup = {\n plan: (input) =>\n request({\n method: \"POST\",\n path: `/domains/${encodeURIComponent(input.domain)}/plans`,\n body: Schema.encodeSync(Server.PlanPayload)({ requirements: input.requirements }),\n success: Plan.Model,\n }),\n approve,\n reject,\n apply,\n attempt: (planId) =>\n request({\n method: \"GET\",\n path: `/plans/${encodeURIComponent(planId)}`,\n success: Server.Attempt,\n }),\n };\n\n const verification: VerificationGroup = {\n observe: (domain, input) =>\n request({\n method: \"POST\",\n path: `/domains/${encodeURIComponent(domain)}/observations`,\n body: Schema.encodeSync(Server.ObservePayload)(\n input?.requirements === undefined ? {} : { requirements: input.requirements },\n ),\n success: Server.Readiness,\n }),\n };\n\n const cleanup: CleanupGroup = {\n plan: (receiptId) =>\n request({\n method: \"POST\",\n path: `/receipts/${encodeURIComponent(receiptId)}/cleanup-plans`,\n success: Plan.Model,\n }),\n approve,\n reject,\n apply,\n };\n\n const groups = { connection, provisioning, verification, cleanup };\n return Object.fromEntries(\n allCapabilities\n .filter((capability) => declared.includes(capability))\n .map((capability) => [capability, groups[capability]]),\n );\n};\n\n// ---------------------------------------------------------------------------------------------\n// Promise adapters\n// ---------------------------------------------------------------------------------------------\n\n/** The same transport in Promises, for hosts and tests that do not run Effect. */\nexport type AsyncTransport = {\n readonly [K in keyof Interface]?: {\n readonly [M in keyof NonNullable<Interface[K]>]: NonNullable<Interface[K]>[M] extends (\n ...args: infer A\n ) => Effect.Effect<infer R, Errors.DomainKitError>\n ? (...args: A) => Promise<R>\n : never;\n };\n};\n\n/** Adapt a Promise-shaped transport; a rejection that is not a `DomainKit.Error` becomes one. */\nexport const fromAsync = (transport: AsyncTransport): Interface =>\n mapGroups(\n transport,\n (method) =>\n (...args: ReadonlyArray<never>) =>\n Effect.tryPromise({\n try: () => method(...args) as Promise<unknown>,\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider: \"domainkit\",\n message: `The transport rejected: ${String(cause)}`,\n }),\n }),\n }),\n ) as Interface;\n\n/** Adapt to Promises; every rejection is the `DomainKit.Error` the lifecycle raised. */\nexport const toAsync = (transport: Interface): AsyncTransport =>\n mapGroups(\n transport,\n (method) =>\n (...args: ReadonlyArray<never>) =>\n Effect.runPromise(method(...args) as Effect.Effect<unknown, Errors.DomainKitError>),\n ) as AsyncTransport;\n\ntype AnyMethod = (...args: ReadonlyArray<never>) => unknown;\ntype AnyGroups = { readonly [key: string]: Record<string, AnyMethod> | undefined };\n\n/** Rebuild every declared group with each method wrapped; the two adapters differ only in `wrap`. */\nconst mapGroups = (source: object, wrap: (method: AnyMethod) => AnyMethod): unknown =>\n Object.fromEntries(\n allCapabilities.flatMap((capability) => {\n const group = (source as AnyGroups)[capability];\n if (group === undefined) return [];\n return [\n [\n capability,\n Object.fromEntries(Object.entries(group).map(([name, method]) => [name, wrap(method)])),\n ],\n ];\n }),\n );\n\n// ---------------------------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------------------------\n\nconst safeOrigin = (base: string): string => {\n try {\n return new URL(base).origin;\n } catch {\n return base === \"\" ? \"domainkit\" : base;\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Transport.mjs","names":["Server.Token","Server.OAuth","Server.Integration","Http.headersFrom","Http.requestJson","Errors.decode","Errors.DomainKitError","Http.classify","Server.ApprovePayload","Approval.Model","Server.RejectPayload","Server.Attempt","Receipt.Model","Server.Snapshot","Server.Discovery","Server.StartPayload","Server.Started","Server.AttachPayload","Server.PlanPayload","Plan.Model","Server.ObservePayload","Server.Readiness","Errors.isDomainKitError","Reason.ProviderUnavailable"],"sources":["../src/Transport.ts"],"sourcesContent":["/**\n * domainkit/client — the browser-side transport `@domainkit/react` consumes. Capability groups are\n * optional: a host that only exposes connection routes declares just `connection`, and the parts\n * of the UI that plan or clean up do not render.\n *\n * const transport = Transport.fromFetch(\"/api/domainkit\")\n *\n * Every method decodes the same wire schemas `domainkit/server` encodes, so a failure arrives as\n * the `DomainKit.Error` the lifecycle raised, reason intact.\n */\nimport { Effect, Schema } from \"effect\";\n\nimport * as Approval from \"./Approval.ts\";\nimport type * as DnsRecord from \"./DnsRecord.ts\";\nimport * as Errors from \"./internal/error.ts\";\nimport * as Http from \"./internal/http.ts\";\nimport * as Plan from \"./Plan.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as Receipt from \"./Receipt.ts\";\nimport * as Server from \"./Server.ts\";\n\ntype Fx<A> = Effect.Effect<A, Errors.DomainKitError>;\n\nexport type Snapshot = Server.Snapshot;\nexport type Started = Server.Started;\nexport type Readiness = Server.Readiness;\nexport type Attempt = Server.Attempt;\nexport type Candidate = Server.Candidate;\nexport type Discovery = Server.Discovery;\nexport type Field = Server.Field;\nexport type MethodDescriptor = Server.MethodDescriptor;\nexport type Method = Server.Method;\n\n/** How a client asks to connect. Mirrors `Connect.Method`, over the wire. */\nexport const Method = {\n /** A lone string for the common one-field provider, or the values its descriptor names. */\n token: (values: string | Readonly<Record<string, string>>): Method =>\n new Server.Token({ values: typeof values === \"string\" ? { token: values } : values }),\n oauth: (options: { readonly returnTo?: string } = {}): Method => new Server.OAuth(options),\n integration: (options: { readonly returnTo?: string } = {}): Method =>\n new Server.Integration(options),\n} as const;\n\nexport interface ConnectionGroup {\n readonly inspect: (domain: string) => Fx<Snapshot>;\n /** Which of this owner's existing connections already reaches the domain. */\n readonly discover: (domain: string) => Fx<Discovery>;\n readonly start: (input: {\n readonly domain: string;\n readonly provider: string;\n readonly method: Method;\n }) => Fx<Started>;\n readonly attach: (input: {\n readonly connectionId: string;\n readonly domain: string;\n readonly zone?: string;\n }) => Fx<Started>;\n readonly detach: (attachmentId: string) => Fx<void>;\n readonly disconnect: (connectionId: string) => Fx<void>;\n}\n\nexport interface ProvisioningGroup {\n readonly plan: (input: {\n readonly domain: string;\n readonly requirements: ReadonlyArray<DnsRecord.Model>;\n }) => Fx<Plan.Model>;\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Fx<Approval.Model>;\n /** Decline the plan; terminal, and approving it afterwards fails `Stale`. */\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Fx<Attempt>;\n readonly apply: (approvalId: Approval.ApprovalId) => Fx<Receipt.Model>;\n /** The stored plan with its status, approval, receipt, and rejection. */\n readonly attempt: (planId: Plan.PlanId) => Fx<Attempt>;\n}\n\nexport interface VerificationGroup {\n /**\n * Observe the domain's provisioning receipt, or `options.requirements` when supplied (required\n * for a domain with no attachment).\n */\n readonly observe: (\n domain: string,\n options?: { readonly requirements?: ReadonlyArray<DnsRecord.Model> },\n ) => Fx<Readiness>;\n}\n\nexport interface CleanupGroup {\n readonly plan: (receiptId: Receipt.ReceiptId) => Fx<Plan.Model>;\n readonly approve: (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) => Fx<Approval.Model>;\n readonly reject: (input: {\n readonly planId: Plan.PlanId;\n readonly reason?: string;\n }) => Fx<Attempt>;\n readonly apply: (approvalId: Approval.ApprovalId) => Fx<Receipt.Model>;\n}\n\nexport interface Interface {\n readonly connection?: ConnectionGroup;\n readonly provisioning?: ProvisioningGroup;\n readonly verification?: VerificationGroup;\n readonly cleanup?: CleanupGroup;\n}\n\nexport type Capability = keyof Interface;\n\nexport const allCapabilities: ReadonlyArray<Capability> = [\n \"connection\",\n \"provisioning\",\n \"verification\",\n \"cleanup\",\n];\n\n/** Which groups this transport actually carries, in declaration order. */\nexport const capabilities = (transport: Interface): ReadonlyArray<Capability> =>\n allCapabilities.filter((capability) => transport[capability] !== undefined);\n\nexport interface FetchOptions {\n readonly fetch?: Http.Fetch;\n readonly headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n /** Which groups the server exposes. Default: all. */\n readonly capabilities?: ReadonlyArray<Capability>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// fetch\n// ---------------------------------------------------------------------------------------------\n\n/** A transport over `domainkit/server` routes mounted at `baseUrl`. */\nexport const fromFetch = (baseUrl: string, options: FetchOptions = {}): Interface => {\n const base = baseUrl.replace(/\\/+$/, \"\");\n const source = safeOrigin(base);\n // Resolved at call time and invoked as a free function: a browser `fetch` throws \"Illegal\n // invocation\" when called as a method of anything but `window`, and a host may polyfill later.\n const call: Http.Fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n const declared = options.capabilities ?? allCapabilities;\n\n const request = <A>(input: {\n readonly method: \"GET\" | \"POST\" | \"DELETE\";\n readonly path: string;\n readonly body?: unknown;\n readonly success: Schema.Codec<A, unknown> | null;\n }): Fx<A> =>\n Effect.gen(function* () {\n const headers = yield* Http.headersFrom(options.headers);\n if (input.body !== undefined) headers.set(\"content-type\", \"application/json\");\n const reply = yield* Http.requestJson({\n fetch: call,\n provider: source,\n url: `${base}${input.path}`,\n init: {\n method: input.method,\n headers,\n ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),\n },\n });\n if (!reply.ok) {\n // The server answers failures with the `DomainKit.Error` value itself. Anything else came\n // from in front of it: a proxy, a login page, a maintenance window.\n const decoded = yield* Effect.result(\n Errors.decode(Errors.DomainKitError, reply.body, \"response\"),\n );\n return yield* decoded._tag === \"Success\"\n ? Effect.fail(decoded.success)\n : Effect.fail(\n new Errors.DomainKitError({\n reason: Http.classify(\n source,\n reply.status,\n reply.headers,\n `${input.method} ${input.path} answered ${reply.status}`,\n ),\n }),\n );\n }\n if (input.success === null) return undefined as A;\n return yield* Errors.decode(input.success, reply.body, \"response\");\n });\n\n /** Provisioning and cleanup share these routes; the attempt knows its kind. */\n const approve = (input: {\n readonly planId: Plan.PlanId;\n readonly operationIds?: ReadonlyArray<Plan.OperationId>;\n }) =>\n request({\n method: \"POST\",\n path: `/plans/${encodeURIComponent(input.planId)}/approvals`,\n body: Schema.encodeSync(Server.ApprovePayload)(\n input.operationIds === undefined ? {} : { operationIds: input.operationIds },\n ),\n success: Approval.Model,\n });\n\n const reject = (input: { readonly planId: Plan.PlanId; readonly reason?: string }) =>\n request({\n method: \"POST\",\n path: `/plans/${encodeURIComponent(input.planId)}/rejections`,\n body: Schema.encodeSync(Server.RejectPayload)(\n input.reason === undefined ? {} : { reason: input.reason },\n ),\n success: Server.Attempt,\n });\n\n const apply = (approvalId: Approval.ApprovalId) =>\n request({\n method: \"POST\",\n path: `/approvals/${encodeURIComponent(approvalId)}/apply`,\n success: Receipt.Model,\n });\n\n const connection: ConnectionGroup = {\n inspect: (domain) =>\n request({\n method: \"GET\",\n path: `/domains/${encodeURIComponent(domain)}`,\n success: Server.Snapshot,\n }),\n discover: (domain) =>\n request({\n method: \"GET\",\n path: `/domains/${encodeURIComponent(domain)}/discovery`,\n success: Server.Discovery,\n }),\n start: (input) =>\n request({\n method: \"POST\",\n path: \"/connections\",\n body: Schema.encodeSync(Server.StartPayload)(input),\n success: Server.Started,\n }),\n attach: (input) =>\n request({\n method: \"POST\",\n path: `/connections/${encodeURIComponent(input.connectionId)}/attachments`,\n body: Schema.encodeSync(Server.AttachPayload)(\n input.zone === undefined\n ? { domain: input.domain }\n : { domain: input.domain, zone: input.zone },\n ),\n success: Server.Started,\n }),\n detach: (attachmentId) =>\n request({\n method: \"DELETE\",\n path: `/attachments/${encodeURIComponent(attachmentId)}`,\n success: null,\n }),\n disconnect: (connectionId) =>\n request({\n method: \"DELETE\",\n path: `/connections/${encodeURIComponent(connectionId)}`,\n success: null,\n }),\n };\n\n const provisioning: ProvisioningGroup = {\n plan: (input) =>\n request({\n method: \"POST\",\n path: `/domains/${encodeURIComponent(input.domain)}/plans`,\n body: Schema.encodeSync(Server.PlanPayload)({ requirements: input.requirements }),\n success: Plan.Model,\n }),\n approve,\n reject,\n apply,\n attempt: (planId) =>\n request({\n method: \"GET\",\n path: `/plans/${encodeURIComponent(planId)}`,\n success: Server.Attempt,\n }),\n };\n\n const verification: VerificationGroup = {\n observe: (domain, input) =>\n request({\n method: \"POST\",\n path: `/domains/${encodeURIComponent(domain)}/observations`,\n body: Schema.encodeSync(Server.ObservePayload)(\n input?.requirements === undefined ? {} : { requirements: input.requirements },\n ),\n success: Server.Readiness,\n }),\n };\n\n const cleanup: CleanupGroup = {\n plan: (receiptId) =>\n request({\n method: \"POST\",\n path: `/receipts/${encodeURIComponent(receiptId)}/cleanup-plans`,\n success: Plan.Model,\n }),\n approve,\n reject,\n apply,\n };\n\n const groups = { connection, provisioning, verification, cleanup };\n return Object.fromEntries(\n allCapabilities\n .filter((capability) => declared.includes(capability))\n .map((capability) => [capability, groups[capability]]),\n );\n};\n\n// ---------------------------------------------------------------------------------------------\n// Promise adapters\n// ---------------------------------------------------------------------------------------------\n\n/** The same transport in Promises, for hosts and tests that do not run Effect. */\nexport type AsyncTransport = {\n readonly [K in keyof Interface]?: {\n readonly [M in keyof NonNullable<Interface[K]>]: NonNullable<Interface[K]>[M] extends (\n ...args: infer A\n ) => Effect.Effect<infer R, Errors.DomainKitError>\n ? (...args: A) => Promise<R>\n : never;\n };\n};\n\n/** Adapt a Promise-shaped transport; a rejection that is not a `DomainKit.Error` becomes one. */\nexport const fromAsync = (transport: AsyncTransport): Interface =>\n mapGroups(\n transport,\n (method) =>\n (...args: ReadonlyArray<never>) =>\n Effect.tryPromise({\n try: () => method(...args) as Promise<unknown>,\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider: \"domainkit\",\n message: `The transport rejected: ${String(cause)}`,\n }),\n }),\n }),\n ) as Interface;\n\n/** Adapt to Promises; every rejection is the `DomainKit.Error` the lifecycle raised. */\nexport const toAsync = (transport: Interface): AsyncTransport =>\n mapGroups(\n transport,\n (method) =>\n (...args: ReadonlyArray<never>) =>\n Effect.runPromise(method(...args) as Effect.Effect<unknown, Errors.DomainKitError>),\n ) as AsyncTransport;\n\ntype AnyMethod = (...args: ReadonlyArray<never>) => unknown;\ntype AnyGroups = { readonly [key: string]: Record<string, AnyMethod> | undefined };\n\n/** Rebuild every declared group with each method wrapped; the two adapters differ only in `wrap`. */\nconst mapGroups = (source: object, wrap: (method: AnyMethod) => AnyMethod): unknown =>\n Object.fromEntries(\n allCapabilities.flatMap((capability) => {\n const group = (source as AnyGroups)[capability];\n if (group === undefined) return [];\n return [\n [\n capability,\n Object.fromEntries(Object.entries(group).map(([name, method]) => [name, wrap(method)])),\n ],\n ];\n }),\n );\n\n// ---------------------------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------------------------\n\nconst safeOrigin = (base: string): string => {\n try {\n return new URL(base).origin;\n } catch {\n return base === \"\" ? \"domainkit\" : base;\n }\n};\n"],"mappings":"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"}
|
package/dist/internal/doh.mjs
CHANGED
|
@@ -26,7 +26,8 @@ const query = (input) => Effect.tryPromise({
|
|
|
26
26
|
}],
|
|
27
27
|
type: "query"
|
|
28
28
|
}));
|
|
29
|
-
const
|
|
29
|
+
const { fetch: send } = input;
|
|
30
|
+
const response = await send(input.url, {
|
|
30
31
|
body,
|
|
31
32
|
headers: {
|
|
32
33
|
accept: "application/dns-message",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doh.mjs","names":["Errors.DomainKitError","Reason.ResolverFailed","Errors.isDomainKitError","DnsRecord.Opaque","DnsRecord.a","DnsRecord.aaaa","DnsRecord.cname","DnsRecord.ns","DnsRecord.txt","DnsRecord.mx","DnsRecord.caa","DnsRecord.srv"],"sources":["../../src/internal/doh.ts"],"sourcesContent":["import * as DnsPacket from \"@leichtgewicht/dns-packet\";\nimport { Effect } from \"effect\";\n\nimport * as DnsRecord from \"../DnsRecord.ts\";\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport type { Fetch } from \"./http.ts\";\n\nexport interface Answer {\n readonly records: ReadonlyArray<DnsRecord.Observed>;\n readonly negative: boolean;\n readonly ttl: number | null;\n}\n\nconst failed = (resolver: string, message: string) =>\n new Errors.DomainKitError({\n reason: new Reason.ResolverFailed({ resolver, message }),\n });\n\n/** One RFC 8484 wire-format query; the caller applies the timeout. */\nexport const query = (input: {\n readonly resolver: string;\n readonly url: string;\n readonly fetch: Fetch;\n readonly name: string;\n readonly type: DnsRecord.Type;\n /** Host-supplied abort, combined with the fiber's own interruption signal. */\n readonly signal?: AbortSignal | undefined;\n}): Effect.Effect<Answer, Errors.DomainKitError> =>\n Effect.tryPromise({\n try: async (fiberSignal) => {\n const controller = new AbortController();\n const abort = (reason: unknown) => controller.abort(reason);\n fiberSignal.addEventListener(\"abort\", () => abort(fiberSignal.reason), { once: true });\n input.signal?.addEventListener(\"abort\", () => abort(input.signal?.reason), { once: true });\n if (input.signal?.aborted === true) abort(input.signal.reason);\n const signal = controller.signal;\n const body = Uint8Array.from(\n DnsPacket.encode({\n flags: DnsPacket.RECURSION_DESIRED,\n id: 0,\n questions: [{ name: input.name, type: input.type }],\n type: \"query\",\n }),\n );\n const response = await input.fetch(input.url, {\n body,\n headers: { accept: \"application/dns-message\", \"content-type\": \"application/dns-message\" },\n method: \"POST\",\n signal,\n });\n if (!response.ok) throw failed(input.resolver, `DoH returned HTTP ${response.status}`);\n const contentType = response.headers\n .get(\"content-type\")\n ?.split(\";\", 1)[0]\n ?.trim()\n .toLowerCase();\n if (contentType !== \"application/dns-message\") {\n throw failed(\n input.resolver,\n `DoH returned unsupported content type ${contentType ?? \"<missing>\"}`,\n );\n }\n return decode(\n input.resolver,\n input.name,\n input.type,\n new Uint8Array(await response.arrayBuffer()),\n );\n },\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : failed(input.resolver, cause instanceof Error ? cause.message : \"DNS resolution failed\"),\n });\n\nfunction decode(resolver: string, name: string, type: DnsRecord.Type, message: Uint8Array): Answer {\n let packet: DnsPacket.Packet;\n try {\n packet = DnsPacket.decode(message);\n } catch {\n throw failed(resolver, \"DoH returned an invalid DNS message\");\n }\n if (packet.type !== \"response\") throw failed(resolver, \"DoH returned a DNS query\");\n if (packet.id !== 0) throw failed(resolver, \"DoH response used an unexpected message ID\");\n if (packet.flag_tc) throw failed(resolver, \"DoH returned a truncated DNS response\");\n const question = packet.questions?.[0];\n if (\n packet.questions?.length !== 1 ||\n question === undefined ||\n question.class !== \"IN\" ||\n question.type !== type ||\n question.name.toLowerCase().replace(/\\.$/, \"\") !== name\n ) {\n throw failed(resolver, \"DoH response did not match the DNS question\");\n }\n if (packet.rcode === \"NXDOMAIN\") return { records: [], negative: true, ttl: null };\n if (packet.rcode !== \"NOERROR\") {\n throw failed(resolver, `DNS resolver returned ${packet.rcode ?? \"an unknown response code\"}`);\n }\n const answers = (packet.answers ?? []).filter((answer) => answer.class === \"IN\");\n if (answers.some((answer) => answer.ttl === undefined)) {\n throw failed(resolver, \"DoH response omitted the DNS record TTL\");\n }\n const records = answers.map(toRecord);\n const ttls = answers.flatMap((answer) => (answer.ttl === undefined ? [] : [answer.ttl]));\n return {\n records,\n negative: records.length === 0,\n ttl: ttls.length === 0 ? null : Math.min(...ttls),\n };\n}\n\nfunction toRecord(answer: DnsPacket.Answer): DnsRecord.Observed {\n const name = answer.name;\n const opaque = () => new DnsRecord.Opaque({ name, type: answer.type, raw: answer });\n const ttl = answer.ttl === undefined || answer.ttl <= 0 ? {} : { ttl: answer.ttl };\n try {\n switch (answer.type) {\n case \"A\":\n return DnsRecord.a({ name, address: answer.data, ...ttl });\n case \"AAAA\":\n return DnsRecord.aaaa({ name, address: answer.data, ...ttl });\n case \"CNAME\":\n return DnsRecord.cname({ name, target: answer.data, ...ttl });\n case \"NS\":\n return DnsRecord.ns({ name, nameserver: answer.data, ...ttl });\n case \"TXT\":\n return DnsRecord.txt({ name, value: decodeTxt(answer.data), ...ttl });\n case \"MX\":\n return DnsRecord.mx({\n name,\n exchange: answer.data.exchange,\n priority: answer.data.preference ?? 0,\n ...ttl,\n });\n case \"CAA\":\n return DnsRecord.caa({\n name,\n flags: answer.data.flags ?? 0,\n tag: answer.data.tag,\n value: answer.data.value,\n ...ttl,\n });\n case \"SRV\":\n return DnsRecord.srv({\n name,\n target: answer.data.target,\n port: required(answer.data.port),\n priority: answer.data.priority ?? 0,\n weight: answer.data.weight ?? 0,\n ...ttl,\n });\n default:\n return opaque();\n }\n } catch {\n return opaque();\n }\n}\n\nfunction required<A>(value: A | undefined): A {\n if (value === undefined) throw new Error(\"DoH answer omitted a required field\");\n return value;\n}\n\nfunction decodeTxt(data: DnsPacket.TxtData): string {\n const chunks = Array.isArray(data) ? data : [data];\n const encoded = chunks.map((chunk) =>\n typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk,\n );\n const joined = new Uint8Array(encoded.reduce((total, chunk) => total + chunk.length, 0));\n let offset = 0;\n for (const chunk of encoded) {\n joined.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(joined);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"doh.mjs","names":["Errors.DomainKitError","Reason.ResolverFailed","Errors.isDomainKitError","DnsRecord.Opaque","DnsRecord.a","DnsRecord.aaaa","DnsRecord.cname","DnsRecord.ns","DnsRecord.txt","DnsRecord.mx","DnsRecord.caa","DnsRecord.srv"],"sources":["../../src/internal/doh.ts"],"sourcesContent":["import * as DnsPacket from \"@leichtgewicht/dns-packet\";\nimport { Effect } from \"effect\";\n\nimport * as DnsRecord from \"../DnsRecord.ts\";\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport type { Fetch } from \"./http.ts\";\n\nexport interface Answer {\n readonly records: ReadonlyArray<DnsRecord.Observed>;\n readonly negative: boolean;\n readonly ttl: number | null;\n}\n\nconst failed = (resolver: string, message: string) =>\n new Errors.DomainKitError({\n reason: new Reason.ResolverFailed({ resolver, message }),\n });\n\n/** One RFC 8484 wire-format query; the caller applies the timeout. */\nexport const query = (input: {\n readonly resolver: string;\n readonly url: string;\n readonly fetch: Fetch;\n readonly name: string;\n readonly type: DnsRecord.Type;\n /** Host-supplied abort, combined with the fiber's own interruption signal. */\n readonly signal?: AbortSignal | undefined;\n}): Effect.Effect<Answer, Errors.DomainKitError> =>\n Effect.tryPromise({\n try: async (fiberSignal) => {\n const controller = new AbortController();\n const abort = (reason: unknown) => controller.abort(reason);\n fiberSignal.addEventListener(\"abort\", () => abort(fiberSignal.reason), { once: true });\n input.signal?.addEventListener(\"abort\", () => abort(input.signal?.reason), { once: true });\n if (input.signal?.aborted === true) abort(input.signal.reason);\n const signal = controller.signal;\n const body = Uint8Array.from(\n DnsPacket.encode({\n flags: DnsPacket.RECURSION_DESIRED,\n id: 0,\n questions: [{ name: input.name, type: input.type }],\n type: \"query\",\n }),\n );\n const { fetch: send } = input; // a free call keeps `this` undefined for a native fetch\n const response = await send(input.url, {\n body,\n headers: { accept: \"application/dns-message\", \"content-type\": \"application/dns-message\" },\n method: \"POST\",\n signal,\n });\n if (!response.ok) throw failed(input.resolver, `DoH returned HTTP ${response.status}`);\n const contentType = response.headers\n .get(\"content-type\")\n ?.split(\";\", 1)[0]\n ?.trim()\n .toLowerCase();\n if (contentType !== \"application/dns-message\") {\n throw failed(\n input.resolver,\n `DoH returned unsupported content type ${contentType ?? \"<missing>\"}`,\n );\n }\n return decode(\n input.resolver,\n input.name,\n input.type,\n new Uint8Array(await response.arrayBuffer()),\n );\n },\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : failed(input.resolver, cause instanceof Error ? cause.message : \"DNS resolution failed\"),\n });\n\nfunction decode(resolver: string, name: string, type: DnsRecord.Type, message: Uint8Array): Answer {\n let packet: DnsPacket.Packet;\n try {\n packet = DnsPacket.decode(message);\n } catch {\n throw failed(resolver, \"DoH returned an invalid DNS message\");\n }\n if (packet.type !== \"response\") throw failed(resolver, \"DoH returned a DNS query\");\n if (packet.id !== 0) throw failed(resolver, \"DoH response used an unexpected message ID\");\n if (packet.flag_tc) throw failed(resolver, \"DoH returned a truncated DNS response\");\n const question = packet.questions?.[0];\n if (\n packet.questions?.length !== 1 ||\n question === undefined ||\n question.class !== \"IN\" ||\n question.type !== type ||\n question.name.toLowerCase().replace(/\\.$/, \"\") !== name\n ) {\n throw failed(resolver, \"DoH response did not match the DNS question\");\n }\n if (packet.rcode === \"NXDOMAIN\") return { records: [], negative: true, ttl: null };\n if (packet.rcode !== \"NOERROR\") {\n throw failed(resolver, `DNS resolver returned ${packet.rcode ?? \"an unknown response code\"}`);\n }\n const answers = (packet.answers ?? []).filter((answer) => answer.class === \"IN\");\n if (answers.some((answer) => answer.ttl === undefined)) {\n throw failed(resolver, \"DoH response omitted the DNS record TTL\");\n }\n const records = answers.map(toRecord);\n const ttls = answers.flatMap((answer) => (answer.ttl === undefined ? [] : [answer.ttl]));\n return {\n records,\n negative: records.length === 0,\n ttl: ttls.length === 0 ? null : Math.min(...ttls),\n };\n}\n\nfunction toRecord(answer: DnsPacket.Answer): DnsRecord.Observed {\n const name = answer.name;\n const opaque = () => new DnsRecord.Opaque({ name, type: answer.type, raw: answer });\n const ttl = answer.ttl === undefined || answer.ttl <= 0 ? {} : { ttl: answer.ttl };\n try {\n switch (answer.type) {\n case \"A\":\n return DnsRecord.a({ name, address: answer.data, ...ttl });\n case \"AAAA\":\n return DnsRecord.aaaa({ name, address: answer.data, ...ttl });\n case \"CNAME\":\n return DnsRecord.cname({ name, target: answer.data, ...ttl });\n case \"NS\":\n return DnsRecord.ns({ name, nameserver: answer.data, ...ttl });\n case \"TXT\":\n return DnsRecord.txt({ name, value: decodeTxt(answer.data), ...ttl });\n case \"MX\":\n return DnsRecord.mx({\n name,\n exchange: answer.data.exchange,\n priority: answer.data.preference ?? 0,\n ...ttl,\n });\n case \"CAA\":\n return DnsRecord.caa({\n name,\n flags: answer.data.flags ?? 0,\n tag: answer.data.tag,\n value: answer.data.value,\n ...ttl,\n });\n case \"SRV\":\n return DnsRecord.srv({\n name,\n target: answer.data.target,\n port: required(answer.data.port),\n priority: answer.data.priority ?? 0,\n weight: answer.data.weight ?? 0,\n ...ttl,\n });\n default:\n return opaque();\n }\n } catch {\n return opaque();\n }\n}\n\nfunction required<A>(value: A | undefined): A {\n if (value === undefined) throw new Error(\"DoH answer omitted a required field\");\n return value;\n}\n\nfunction decodeTxt(data: DnsPacket.TxtData): string {\n const chunks = Array.isArray(data) ? data : [data];\n const encoded = chunks.map((chunk) =>\n typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk,\n );\n const joined = new Uint8Array(encoded.reduce((total, chunk) => total + chunk.length, 0));\n let offset = 0;\n for (const chunk of encoded) {\n joined.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(joined);\n}\n"],"mappings":";;;;;;AAcA,MAAM,UAAU,UAAkB,YAChC,IAAIA,eAAsB,EACxB,QAAQ,IAAIC,eAAsB;CAAE;CAAU;AAAQ,CAAC,EACzD,CAAC;;AAGH,MAAa,SAAS,UASpB,OAAO,WAAW;CAChB,KAAK,OAAO,gBAAgB;EAC1B,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,SAAS,WAAoB,WAAW,MAAM,MAAM;EAC1D,YAAY,iBAAiB,eAAe,MAAM,YAAY,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;EACrF,MAAM,QAAQ,iBAAiB,eAAe,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;EACzF,IAAI,MAAM,QAAQ,YAAY,MAAM,MAAM,MAAM,OAAO,MAAM;EAC7D,MAAM,SAAS,WAAW;EAC1B,MAAM,OAAO,WAAW,KACtB,UAAU,OAAO;GACf,OAAO,UAAU;GACjB,IAAI;GACJ,WAAW,CAAC;IAAE,MAAM,MAAM;IAAM,MAAM,MAAM;GAAK,CAAC;GAClD,MAAM;EACR,CAAC,CACH;EACA,MAAM,EAAE,OAAO,SAAS;EACxB,MAAM,WAAW,MAAM,KAAK,MAAM,KAAK;GACrC;GACA,SAAS;IAAE,QAAQ;IAA2B,gBAAgB;GAA0B;GACxF,QAAQ;GACR;EACF,CAAC;EACD,IAAI,CAAC,SAAS,IAAI,MAAM,OAAO,MAAM,UAAU,qBAAqB,SAAS,QAAQ;EACrF,MAAM,cAAc,SAAS,QAC1B,IAAI,cAAc,CAAC,EAClB,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,EAChB,KAAK,CAAC,CACP,YAAY;EACf,IAAI,gBAAgB,2BAClB,MAAM,OACJ,MAAM,UACN,yCAAyC,eAAe,aAC1D;EAEF,OAAO,OACL,MAAM,UACN,MAAM,MACN,MAAM,MACN,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC,CAC7C;CACF;CACA,QAAQ,UACNC,iBAAwB,KAAK,IACzB,QACA,OAAO,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,uBAAuB;AAC/F,CAAC;AAEH,SAAS,OAAO,UAAkB,MAAc,MAAsB,SAA6B;CACjG,IAAI;CACJ,IAAI;EACF,SAAS,UAAU,OAAO,OAAO;CACnC,QAAQ;EACN,MAAM,OAAO,UAAU,qCAAqC;CAC9D;CACA,IAAI,OAAO,SAAS,YAAY,MAAM,OAAO,UAAU,0BAA0B;CACjF,IAAI,OAAO,OAAO,GAAG,MAAM,OAAO,UAAU,4CAA4C;CACxF,IAAI,OAAO,SAAS,MAAM,OAAO,UAAU,uCAAuC;CAClF,MAAM,WAAW,OAAO,YAAY;CACpC,IACE,OAAO,WAAW,WAAW,KAC7B,aAAa,KAAA,KACb,SAAS,UAAU,QACnB,SAAS,SAAS,QAClB,SAAS,KAAK,YAAY,CAAC,CAAC,QAAQ,OAAO,EAAE,MAAM,MAEnD,MAAM,OAAO,UAAU,6CAA6C;CAEtE,IAAI,OAAO,UAAU,YAAY,OAAO;EAAE,SAAS,CAAC;EAAG,UAAU;EAAM,KAAK;CAAK;CACjF,IAAI,OAAO,UAAU,WACnB,MAAM,OAAO,UAAU,yBAAyB,OAAO,SAAS,4BAA4B;CAE9F,MAAM,WAAW,OAAO,WAAW,CAAC,EAAA,CAAG,QAAQ,WAAW,OAAO,UAAU,IAAI;CAC/E,IAAI,QAAQ,MAAM,WAAW,OAAO,QAAQ,KAAA,CAAS,GACnD,MAAM,OAAO,UAAU,yCAAyC;CAElE,MAAM,UAAU,QAAQ,IAAI,QAAQ;CACpC,MAAM,OAAO,QAAQ,SAAS,WAAY,OAAO,QAAQ,KAAA,IAAY,CAAC,IAAI,CAAC,OAAO,GAAG,CAAE;CACvF,OAAO;EACL;EACA,UAAU,QAAQ,WAAW;EAC7B,KAAK,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,IAAI;CAClD;AACF;AAEA,SAAS,SAAS,QAA8C;CAC9D,MAAM,OAAO,OAAO;CACpB,MAAM,eAAe,IAAIC,OAAiB;EAAE;EAAM,MAAM,OAAO;EAAM,KAAK;CAAO,CAAC;CAClF,MAAM,MAAM,OAAO,QAAQ,KAAA,KAAa,OAAO,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO,IAAI;CACjF,IAAI;EACF,QAAQ,OAAO,MAAf;GACE,KAAK,KACH,OAAOC,EAAY;IAAE;IAAM,SAAS,OAAO;IAAM,GAAG;GAAI,CAAC;GAC3D,KAAK,QACH,OAAOC,KAAe;IAAE;IAAM,SAAS,OAAO;IAAM,GAAG;GAAI,CAAC;GAC9D,KAAK,SACH,OAAOC,MAAgB;IAAE;IAAM,QAAQ,OAAO;IAAM,GAAG;GAAI,CAAC;GAC9D,KAAK,MACH,OAAOC,GAAa;IAAE;IAAM,YAAY,OAAO;IAAM,GAAG;GAAI,CAAC;GAC/D,KAAK,OACH,OAAOC,IAAc;IAAE;IAAM,OAAO,UAAU,OAAO,IAAI;IAAG,GAAG;GAAI,CAAC;GACtE,KAAK,MACH,OAAOC,GAAa;IAClB;IACA,UAAU,OAAO,KAAK;IACtB,UAAU,OAAO,KAAK,cAAc;IACpC,GAAG;GACL,CAAC;GACH,KAAK,OACH,OAAOC,IAAc;IACnB;IACA,OAAO,OAAO,KAAK,SAAS;IAC5B,KAAK,OAAO,KAAK;IACjB,OAAO,OAAO,KAAK;IACnB,GAAG;GACL,CAAC;GACH,KAAK,OACH,OAAOC,IAAc;IACnB;IACA,QAAQ,OAAO,KAAK;IACpB,MAAM,SAAS,OAAO,KAAK,IAAI;IAC/B,UAAU,OAAO,KAAK,YAAY;IAClC,QAAQ,OAAO,KAAK,UAAU;IAC9B,GAAG;GACL,CAAC;GACH,SACE,OAAO,OAAO;EAClB;CACF,QAAQ;EACN,OAAO,OAAO;CAChB;AACF;AAEA,SAAS,SAAY,OAAyB;CAC5C,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,qCAAqC;CAC9E,OAAO;AACT;AAEA,SAAS,UAAU,MAAiC;CAElD,MAAM,WADS,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,EAAA,CAC1B,KAAK,UAC1B,OAAO,UAAU,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,IAAI,KAChE;CACA,MAAM,SAAS,IAAI,WAAW,QAAQ,QAAQ,OAAO,UAAU,QAAQ,MAAM,QAAQ,CAAC,CAAC;CACvF,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,SAAS;EAC3B,OAAO,IAAI,OAAO,MAAM;EACxB,UAAU,MAAM;CAClB;CACA,OAAO,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,MAAM;AAChE"}
|
package/dist/internal/http.mjs
CHANGED
|
@@ -5,7 +5,8 @@ import { Effect } from "effect";
|
|
|
5
5
|
/** One provider HTTP round trip: transport failures and non-JSON replies are already classified. */
|
|
6
6
|
const requestJson = (input) => Effect.tryPromise({
|
|
7
7
|
try: async (signal) => {
|
|
8
|
-
const
|
|
8
|
+
const { fetch: send } = input;
|
|
9
|
+
const response = await send(input.url, {
|
|
9
10
|
...input.init,
|
|
10
11
|
signal
|
|
11
12
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.mjs","names":["Errors.DomainKitError","Reason.ProviderRejected","Errors.isDomainKitError","Reason.ProviderUnavailable","Reason.Unauthenticated","Reason.Forbidden","Reason.ProviderConflict"],"sources":["../../src/internal/http.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\n\nexport type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nexport interface Reply {\n readonly status: number;\n readonly ok: boolean;\n readonly headers: Headers;\n /** Parsed JSON, or `null` for an empty body. */\n readonly body: unknown;\n}\n\n/** One provider HTTP round trip: transport failures and non-JSON replies are already classified. */\nexport const requestJson = (input: {\n readonly fetch: Fetch;\n readonly provider: string;\n readonly url: URL | string;\n readonly init?: RequestInit;\n}): Effect.Effect<Reply, Errors.DomainKitError> =>\n Effect.tryPromise({\n try: async (signal): Promise<Reply> => {\n const response = await
|
|
1
|
+
{"version":3,"file":"http.mjs","names":["Errors.DomainKitError","Reason.ProviderRejected","Errors.isDomainKitError","Reason.ProviderUnavailable","Reason.Unauthenticated","Reason.Forbidden","Reason.ProviderConflict"],"sources":["../../src/internal/http.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\n\nexport type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nexport interface Reply {\n readonly status: number;\n readonly ok: boolean;\n readonly headers: Headers;\n /** Parsed JSON, or `null` for an empty body. */\n readonly body: unknown;\n}\n\n/** One provider HTTP round trip: transport failures and non-JSON replies are already classified. */\nexport const requestJson = (input: {\n readonly fetch: Fetch;\n readonly provider: string;\n readonly url: URL | string;\n readonly init?: RequestInit;\n}): Effect.Effect<Reply, Errors.DomainKitError> =>\n Effect.tryPromise({\n try: async (signal): Promise<Reply> => {\n const { fetch: send } = input; // a free call keeps `this` undefined for a native fetch\n const response = await send(input.url, { ...input.init, signal });\n const text = await response.text();\n let body: unknown = null;\n if (text.length > 0) {\n try {\n body = JSON.parse(text);\n } catch {\n throw new Errors.DomainKitError({\n reason: response.ok\n ? new Reason.ProviderRejected({\n provider: input.provider,\n message: `${input.provider} returned a non-JSON response`,\n })\n : classify(\n input.provider,\n response.status,\n response.headers,\n `HTTP ${response.status}`,\n ),\n });\n }\n }\n return { status: response.status, ok: response.ok, headers: response.headers, body };\n },\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider: input.provider,\n message: cause instanceof Error ? cause.message : `${input.provider} request failed`,\n }),\n }),\n });\n\n/** Host-supplied request headers, given as a value or as a thunk that may await a fresh token. */\nexport const headersFrom = (\n source: HeadersInit | (() => HeadersInit | Promise<HeadersInit>) | undefined,\n): Effect.Effect<Headers, Errors.DomainKitError> =>\n source === undefined\n ? Effect.sync(() => new Headers())\n : typeof source !== \"function\"\n ? Effect.sync(() => new Headers(source))\n : Effect.tryPromise({\n try: async () => new Headers(await source()),\n catch: (cause) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.Unauthenticated({\n message:\n cause instanceof Error ? cause.message : \"Request headers were unavailable\",\n }),\n }),\n });\n\n/**\n * Map an HTTP failure to a reason: 401 -> Unauthenticated, 403 -> Forbidden, 409 or a provider\n * conflict code -> ProviderConflict, 429/5xx -> ProviderUnavailable, else ProviderRejected.\n */\nexport const classify = (\n provider: string,\n status: number,\n headers: Headers,\n message: string,\n code?: string,\n): Reason.Model => {\n if (status === 401) return new Reason.Unauthenticated({ message });\n if (status === 403) return new Reason.Forbidden({ message });\n if (status === 409 || code === \"conflict\") {\n return new Reason.ProviderConflict({\n provider,\n message,\n code: code ?? String(status),\n });\n }\n if (status === 429 || status >= 500) {\n const retryAfterMs = retryAfter(headers.get(\"retry-after\"));\n return new Reason.ProviderUnavailable({\n provider,\n message,\n ...(retryAfterMs === undefined ? {} : { retryAfterMs }),\n });\n }\n return new Reason.ProviderRejected({\n provider,\n message,\n code: code ?? String(status),\n });\n};\n\nexport const rejected = (provider: string, message: string, code?: string) =>\n new Errors.DomainKitError({\n reason: new Reason.ProviderRejected({\n provider,\n message,\n ...(code === undefined ? {} : { code }),\n }),\n });\n\nfunction retryAfter(value: string | null): number | undefined {\n if (value === null) return undefined;\n const seconds = Number(value);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1_000);\n const date = Date.parse(value);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n}\n\nexport const bearer = (token: string, init?: RequestInit): RequestInit => ({\n ...init,\n headers: {\n Accept: \"application/json\",\n Authorization: `Bearer ${token}`,\n ...(init?.body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n ...init?.headers,\n },\n});\n"],"mappings":"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"}
|
package/dist/package.mjs
CHANGED