domainkit 0.20.1 → 0.21.0
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 +29 -0
- package/dist/Cloudflare.mjs +19 -10
- package/dist/Cloudflare.mjs.map +1 -1
- package/dist/Connect.mjs +30 -10
- package/dist/Connect.mjs.map +1 -1
- package/dist/Provider.mjs.map +1 -1
- package/dist/Server.mjs +121 -22
- package/dist/Server.mjs.map +1 -1
- package/dist/Vercel.mjs +20 -10
- package/dist/Vercel.mjs.map +1 -1
- package/dist/entry/client.mjs +1 -2
- package/dist/entry/server.mjs +1 -2
- package/dist/internal/callback.mjs +13 -0
- package/dist/internal/callback.mjs.map +1 -0
- package/dist/internal/config.mjs +19 -5
- package/dist/internal/config.mjs.map +1 -1
- package/dist/internal/provider-async.mjs +2 -0
- package/dist/internal/provider-async.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/types/Connect.d.ts +134 -0
- package/dist/types/Provider.d.ts +9 -0
- package/dist/types/Server.d.ts +45 -0
- package/dist/types/internal/callback.d.ts +4 -0
- package/dist/types/internal/config.d.ts +8 -1
- package/dist/types/internal/provider-async.d.ts +2 -0
- package/package.json +9 -9
package/dist/Vercel.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { Unauthenticated } from "./Reason.mjs";
|
|
|
4
4
|
import { fail } from "./internal/error.mjs";
|
|
5
5
|
import { make, resolveAmong, tokenAuth } from "./Provider.mjs";
|
|
6
6
|
import { rejectedToken } from "./internal/http.mjs";
|
|
7
|
-
import { resolve } from "./internal/config.mjs";
|
|
7
|
+
import { endpoint, nonempty, resolve, secret } from "./internal/config.mjs";
|
|
8
8
|
import { dns, exchangeCode, teams, user, zones } from "./internal/vercel/client.mjs";
|
|
9
9
|
import { Effect, Redacted, Schema } from "effect";
|
|
10
10
|
//#region src/Vercel.ts
|
|
@@ -24,11 +24,11 @@ const TokenFields = Schema.Struct({
|
|
|
24
24
|
const capabilities = ["dns:read", "dns:write"];
|
|
25
25
|
const provider = (options = {}) => {
|
|
26
26
|
const fetch = options.fetch ?? globalThis.fetch;
|
|
27
|
-
const baseUrl =
|
|
27
|
+
const baseUrl = options.baseUrl ?? "https://api.vercel.com";
|
|
28
28
|
const client = (token) => ({
|
|
29
29
|
token,
|
|
30
30
|
fetch,
|
|
31
|
-
baseUrl
|
|
31
|
+
baseUrl: baseUrl.replace(/\/$/, "")
|
|
32
32
|
});
|
|
33
33
|
const targetOf = (domain, label) => ({
|
|
34
34
|
zone: domain.name,
|
|
@@ -38,18 +38,28 @@ const provider = (options = {}) => {
|
|
|
38
38
|
});
|
|
39
39
|
const integration = options.integration === void 0 ? void 0 : integrationAuth(options.integration);
|
|
40
40
|
function integrationAuth(settings) {
|
|
41
|
-
const installOrigin =
|
|
41
|
+
const installOrigin = settings.installOrigin ?? "https://vercel.com";
|
|
42
|
+
const credentials = () => Effect.gen(function* () {
|
|
43
|
+
yield* endpoint(settings.installOrigin ?? "https://vercel.com", "integration.installOrigin");
|
|
44
|
+
yield* endpoint(options.baseUrl ?? "https://api.vercel.com", "baseUrl");
|
|
45
|
+
yield* nonempty(settings.slug, "integration.slug");
|
|
46
|
+
return {
|
|
47
|
+
clientId: yield* resolve(settings.clientId, "integration.clientId").pipe(Effect.flatMap((v) => nonempty(v, "integration.clientId"))),
|
|
48
|
+
clientSecret: yield* resolve(settings.clientSecret, "integration.clientSecret").pipe(Effect.flatMap((v) => secret(v, "integration.clientSecret")))
|
|
49
|
+
};
|
|
50
|
+
});
|
|
42
51
|
return {
|
|
43
52
|
label: "Install the Vercel integration",
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
registration: { clientAuth: "client_secret_post" },
|
|
54
|
+
start: (input) => Effect.gen(function* () {
|
|
55
|
+
yield* credentials();
|
|
56
|
+
const authorizationUrl = new URL(`${installOrigin.replace(/\/$/, "")}/integrations/${encodeURIComponent(settings.slug)}/new`);
|
|
46
57
|
authorizationUrl.searchParams.set("source", "external");
|
|
47
58
|
authorizationUrl.searchParams.set("state", input.state);
|
|
48
|
-
return
|
|
49
|
-
},
|
|
59
|
+
return { authorizationUrl: authorizationUrl.toString() };
|
|
60
|
+
}),
|
|
50
61
|
complete: (input) => Effect.gen(function* () {
|
|
51
|
-
const clientId = yield*
|
|
52
|
-
const clientSecret = yield* resolve(settings.clientSecret, "integration.clientSecret");
|
|
62
|
+
const { clientId, clientSecret } = yield* credentials();
|
|
53
63
|
const token = yield* exchangeCode({
|
|
54
64
|
options: client(""),
|
|
55
65
|
clientId,
|
package/dist/Vercel.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Vercel.mjs","names":["Client.exchangeCode","Errors.fail","Reason.Unauthenticated","Provider.make","Provider.tokenAuth","Client.user","Client.zones","teams","Client.teams","DomainName.decode","Provider.resolveAmong","Client.dns"],"sources":["../src/Vercel.ts"],"sourcesContent":["/** Vercel: personal tokens and marketplace integrations. */\nimport { type Config, Effect, Redacted, Schema } from \"effect\";\n\nimport * as Errors from \"./internal/error.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as DomainName from \"./DomainName.ts\";\nimport { resolve } from \"./internal/config.ts\";\nimport { type Fetch, rejectedToken } from \"./internal/http.ts\";\nimport * as Client from \"./internal/vercel/client.ts\";\nimport type * as Protocol from \"./internal/vercel/protocol.ts\";\nimport * as Provider from \"./Provider.ts\";\n\n/** `teamId` is `null` for a personal account; targets carry the team that owns the zone. */\nexport const TeamContext = Schema.Struct({ teamId: Schema.NullOr(Schema.String) });\nexport type TeamContext = typeof TeamContext.Type;\n\n/** Token-method input: the access token, and a team id to scope the connection to one team. */\nexport const TokenFields = Schema.Struct({\n token: Schema.RedactedFromValue(Schema.String),\n teamId: Schema.optionalKey(Schema.String),\n});\n\nexport interface Options {\n /** Omit to offer tokens only. */\n readonly integration?: {\n readonly clientId: string | Config.Config<string>;\n readonly clientSecret: Redacted.Redacted<string> | Config.Config<Redacted.Redacted<string>>;\n readonly slug: string;\n /**\n * Origin of the install page, which Vercel serves at `/integrations/{slug}/new` beneath it.\n * Default `https://vercel.com`; a stage points it at an emulator that mounts the same path.\n * It stays separate from `baseUrl` because in production these are different hosts:\n * `vercel.com` for the browser install, `api.vercel.com` for the code exchange and the REST API.\n */\n readonly installOrigin?: string;\n };\n readonly fetch?: Fetch;\n readonly baseUrl?: string;\n}\n\nconst capabilities = [\"dns:read\", \"dns:write\"] as const;\n\nexport const provider = (options: Options = {}): Provider.Definition<TeamContext> => {\n const fetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"https://api.vercel.com\").replace(/\\/$/, \"\");\n const client = (token: string): Client.Options => ({ token, fetch, baseUrl });\n\n const targetOf = (domain: Protocol.Domain, label: string): Provider.Target => ({\n zone: domain.name,\n context: { teamId: domain.teamId } satisfies TeamContext,\n label: `${domain.name} (${label})`,\n nameservers: domain.nameservers.length > 0 ? domain.nameservers : domain.intendedNameservers,\n });\n\n const integration =\n options.integration === undefined ? undefined : integrationAuth(options.integration);\n\n function integrationAuth(\n settings: NonNullable<Options[\"integration\"]>,\n ): Provider.IntegrationAuth {\n const installOrigin = (settings.installOrigin ?? \"https://vercel.com\").replace(/\\/$/, \"\");\n return {\n label: \"Install the Vercel integration\",\n start: (input) => {\n const authorizationUrl = new URL(\n `${installOrigin}/integrations/${encodeURIComponent(settings.slug)}/new`,\n );\n authorizationUrl.searchParams.set(\"source\", \"external\");\n authorizationUrl.searchParams.set(\"state\", input.state);\n return Effect.succeed({ authorizationUrl: authorizationUrl.toString() });\n },\n complete: (input) =>\n Effect.gen(function* () {\n const clientId = yield* resolve(settings.clientId, \"integration.clientId\");\n const clientSecret = yield* resolve(settings.clientSecret, \"integration.clientSecret\");\n const token = yield* Client.exchangeCode({\n options: client(\"\"),\n clientId,\n clientSecret: Redacted.value(clientSecret),\n code: input.code,\n callbackUrl: input.callbackUrl,\n });\n const callbackTeam = input.params.teamId;\n if (callbackTeam !== undefined && callbackTeam !== token.team_id) {\n return yield* Errors.fail(\n new Reason.Unauthenticated({\n message: \"Vercel integration callback team does not match the installed team\",\n }),\n );\n }\n return {\n secret: Redacted.make(token.access_token),\n context: { teamId: token.team_id } satisfies TeamContext,\n expiresAt: null,\n };\n }),\n };\n }\n\n return Provider.make<TeamContext>({\n id: \"vercel\",\n name: \"Vercel\",\n nameservers: [\"vercel-dns.com\"],\n context: TeamContext,\n contextVersion: \"vercel.v1\",\n auth: {\n token: Provider.tokenAuth({\n label: \"Access token\",\n docsUrl: \"https://vercel.com/account/settings/tokens\",\n requiredCapabilities: capabilities,\n fields: TokenFields,\n authenticate: ({ token, teamId }) =>\n Client.user(client(Redacted.value(token))).pipe(\n Effect.map(() => ({\n secret: token,\n context: { teamId: teamId ?? null } satisfies TeamContext,\n expiresAt: null,\n })),\n rejectedToken,\n ),\n }),\n ...(integration === undefined ? {} : { integration }),\n },\n session: (credential) => {\n const clientOptions = client(Redacted.value(credential.secret));\n const context = Schema.decodeUnknownOption(TeamContext)(credential.context);\n const teamId = context._tag === \"Some\" ? context.value.teamId : null;\n const listTargets = (): Effect.Effect<\n ReadonlyArray<Provider.Target>,\n Errors.DomainKitError\n > =>\n teamId !== null\n ? Client.zones(clientOptions, teamId).pipe(\n Effect.map((domains) => domains.map((domain) => targetOf(domain, teamId))),\n )\n : Effect.gen(function* () {\n const personal = yield* Client.zones(clientOptions, null);\n const teams = yield* Client.teams(clientOptions).pipe(\n Effect.catchIf(\n (error) => error.reason._tag !== \"ProviderUnavailable\",\n () => Effect.succeed([]),\n ),\n );\n const perTeam = yield* Effect.forEach(teams, (team) =>\n Client.zones(clientOptions, team.id).pipe(\n Effect.map((domains) =>\n domains.map((domain) => targetOf(domain, team.name ?? team.slug)),\n ),\n ),\n );\n return [...personal.map((domain) => targetOf(domain, \"personal\")), ...perTeam.flat()];\n });\n return {\n capabilities: () => Effect.succeed(capabilities),\n listTargets,\n resolveTarget: (domain) =>\n Effect.gen(function* () {\n const name = yield* DomainName.decode(domain);\n const targets = yield* listTargets();\n return Provider.resolveAmong(name, targets);\n }),\n dns: (target) => {\n const scope = Schema.decodeUnknownOption(TeamContext)(target.context);\n return Client.dns(clientOptions, scope._tag === \"Some\" ? scope.value.teamId : teamId);\n },\n };\n },\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Vercel.mjs","names":["Configuration.endpoint","Configuration.nonempty","Configuration.resolve","Configuration.secret","Client.exchangeCode","Errors.fail","Reason.Unauthenticated","Provider.make","Provider.tokenAuth","Client.user","Client.zones","teams","Client.teams","DomainName.decode","Provider.resolveAmong","Client.dns"],"sources":["../src/Vercel.ts"],"sourcesContent":["/** Vercel: personal tokens and marketplace integrations. */\nimport { type Config, Effect, Redacted, Schema } from \"effect\";\n\nimport * as Errors from \"./internal/error.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as DomainName from \"./DomainName.ts\";\nimport * as Configuration from \"./internal/config.ts\";\nimport { type Fetch, rejectedToken } from \"./internal/http.ts\";\nimport * as Client from \"./internal/vercel/client.ts\";\nimport type * as Protocol from \"./internal/vercel/protocol.ts\";\nimport * as Provider from \"./Provider.ts\";\n\n/** `teamId` is `null` for a personal account; targets carry the team that owns the zone. */\nexport const TeamContext = Schema.Struct({ teamId: Schema.NullOr(Schema.String) });\nexport type TeamContext = typeof TeamContext.Type;\n\n/** Token-method input: the access token, and a team id to scope the connection to one team. */\nexport const TokenFields = Schema.Struct({\n token: Schema.RedactedFromValue(Schema.String),\n teamId: Schema.optionalKey(Schema.String),\n});\n\nexport interface Options {\n /** Omit to offer tokens only. */\n readonly integration?: {\n readonly clientId: string | Config.Config<string>;\n readonly clientSecret: Redacted.Redacted<string> | Config.Config<Redacted.Redacted<string>>;\n readonly slug: string;\n /**\n * Origin of the install page, which Vercel serves at `/integrations/{slug}/new` beneath it.\n * Default `https://vercel.com`; a stage points it at an emulator that mounts the same path.\n * It stays separate from `baseUrl` because in production these are different hosts:\n * `vercel.com` for the browser install, `api.vercel.com` for the code exchange and the REST API.\n */\n readonly installOrigin?: string;\n };\n readonly fetch?: Fetch;\n readonly baseUrl?: string;\n}\n\nconst capabilities = [\"dns:read\", \"dns:write\"] as const;\n\nexport const provider = (options: Options = {}): Provider.Definition<TeamContext> => {\n const fetch = options.fetch ?? globalThis.fetch;\n const baseUrl = options.baseUrl ?? \"https://api.vercel.com\";\n const client = (token: string): Client.Options => ({\n token,\n fetch,\n baseUrl: baseUrl.replace(/\\/$/, \"\"),\n });\n\n const targetOf = (domain: Protocol.Domain, label: string): Provider.Target => ({\n zone: domain.name,\n context: { teamId: domain.teamId } satisfies TeamContext,\n label: `${domain.name} (${label})`,\n nameservers: domain.nameservers.length > 0 ? domain.nameservers : domain.intendedNameservers,\n });\n\n const integration =\n options.integration === undefined ? undefined : integrationAuth(options.integration);\n\n function integrationAuth(\n settings: NonNullable<Options[\"integration\"]>,\n ): Provider.IntegrationAuth {\n const installOrigin = settings.installOrigin ?? \"https://vercel.com\";\n const credentials = () =>\n Effect.gen(function* () {\n yield* Configuration.endpoint(\n settings.installOrigin ?? \"https://vercel.com\",\n \"integration.installOrigin\",\n );\n yield* Configuration.endpoint(options.baseUrl ?? \"https://api.vercel.com\", \"baseUrl\");\n yield* Configuration.nonempty(settings.slug, \"integration.slug\");\n const clientId = yield* Configuration.resolve(\n settings.clientId,\n \"integration.clientId\",\n ).pipe(Effect.flatMap((v) => Configuration.nonempty(v, \"integration.clientId\")));\n const clientSecret = yield* Configuration.resolve(\n settings.clientSecret,\n \"integration.clientSecret\",\n ).pipe(Effect.flatMap((v) => Configuration.secret(v, \"integration.clientSecret\")));\n return { clientId, clientSecret };\n });\n return {\n label: \"Install the Vercel integration\",\n registration: { clientAuth: \"client_secret_post\" },\n start: (input) =>\n Effect.gen(function* () {\n yield* credentials();\n const authorizationUrl = new URL(\n `${installOrigin.replace(/\\/$/, \"\")}/integrations/${encodeURIComponent(settings.slug)}/new`,\n );\n authorizationUrl.searchParams.set(\"source\", \"external\");\n authorizationUrl.searchParams.set(\"state\", input.state);\n return { authorizationUrl: authorizationUrl.toString() };\n }),\n complete: (input) =>\n Effect.gen(function* () {\n const { clientId, clientSecret } = yield* credentials();\n const token = yield* Client.exchangeCode({\n options: client(\"\"),\n clientId,\n clientSecret: Redacted.value(clientSecret),\n code: input.code,\n callbackUrl: input.callbackUrl,\n });\n const callbackTeam = input.params.teamId;\n if (callbackTeam !== undefined && callbackTeam !== token.team_id) {\n return yield* Errors.fail(\n new Reason.Unauthenticated({\n message: \"Vercel integration callback team does not match the installed team\",\n }),\n );\n }\n return {\n secret: Redacted.make(token.access_token),\n context: { teamId: token.team_id } satisfies TeamContext,\n expiresAt: null,\n };\n }),\n };\n }\n\n return Provider.make<TeamContext>({\n id: \"vercel\",\n name: \"Vercel\",\n nameservers: [\"vercel-dns.com\"],\n context: TeamContext,\n contextVersion: \"vercel.v1\",\n auth: {\n token: Provider.tokenAuth({\n label: \"Access token\",\n docsUrl: \"https://vercel.com/account/settings/tokens\",\n requiredCapabilities: capabilities,\n fields: TokenFields,\n authenticate: ({ token, teamId }) =>\n Client.user(client(Redacted.value(token))).pipe(\n Effect.map(() => ({\n secret: token,\n context: { teamId: teamId ?? null } satisfies TeamContext,\n expiresAt: null,\n })),\n rejectedToken,\n ),\n }),\n ...(integration === undefined ? {} : { integration }),\n },\n session: (credential) => {\n const clientOptions = client(Redacted.value(credential.secret));\n const context = Schema.decodeUnknownOption(TeamContext)(credential.context);\n const teamId = context._tag === \"Some\" ? context.value.teamId : null;\n const listTargets = (): Effect.Effect<\n ReadonlyArray<Provider.Target>,\n Errors.DomainKitError\n > =>\n teamId !== null\n ? Client.zones(clientOptions, teamId).pipe(\n Effect.map((domains) => domains.map((domain) => targetOf(domain, teamId))),\n )\n : Effect.gen(function* () {\n const personal = yield* Client.zones(clientOptions, null);\n const teams = yield* Client.teams(clientOptions).pipe(\n Effect.catchIf(\n (error) => error.reason._tag !== \"ProviderUnavailable\",\n () => Effect.succeed([]),\n ),\n );\n const perTeam = yield* Effect.forEach(teams, (team) =>\n Client.zones(clientOptions, team.id).pipe(\n Effect.map((domains) =>\n domains.map((domain) => targetOf(domain, team.name ?? team.slug)),\n ),\n ),\n );\n return [...personal.map((domain) => targetOf(domain, \"personal\")), ...perTeam.flat()];\n });\n return {\n capabilities: () => Effect.succeed(capabilities),\n listTargets,\n resolveTarget: (domain) =>\n Effect.gen(function* () {\n const name = yield* DomainName.decode(domain);\n const targets = yield* listTargets();\n return Provider.resolveAmong(name, targets);\n }),\n dns: (target) => {\n const scope = Schema.decodeUnknownOption(TeamContext)(target.context);\n return Client.dns(clientOptions, scope._tag === \"Some\" ? scope.value.teamId : teamId);\n },\n };\n },\n });\n};\n"],"mappings":"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"}
|
package/dist/entry/client.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { Transport_exports as Transport };
|
|
1
|
+
export { Transport_exports as Transport } from "../Transport.mjs";
|
package/dist/entry/server.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { Server_exports as Server };
|
|
1
|
+
export { Server_exports as Server } from "../Server.mjs";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { InvalidInput } from "../Reason.mjs";
|
|
2
|
+
import { fail } from "./error.mjs";
|
|
3
|
+
//#region src/internal/callback.ts
|
|
4
|
+
/** A leaked flow id must reveal neither existence nor ownership, including read races. */
|
|
5
|
+
const refuse = fail(new InvalidInput({
|
|
6
|
+
message: "This callback does not match a connection you started",
|
|
7
|
+
field: "state"
|
|
8
|
+
}));
|
|
9
|
+
const missing = (error) => error.reason._tag === "NotFound" || error.reason._tag === "Expired";
|
|
10
|
+
//#endregion
|
|
11
|
+
export { missing, refuse };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=callback.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.mjs","names":["Errors.fail","Reason.InvalidInput"],"sources":["../../src/internal/callback.ts"],"sourcesContent":["import * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\n\n/** A leaked flow id must reveal neither existence nor ownership, including read races. */\nexport const refuse = Errors.fail(\n new Reason.InvalidInput({\n message: \"This callback does not match a connection you started\",\n field: \"state\",\n }),\n);\nexport const missing = (error: Errors.DomainKitError): boolean =>\n error.reason._tag === \"NotFound\" || error.reason._tag === \"Expired\";\n"],"mappings":";;;;AAIA,MAAa,SAASA,KACpB,IAAIC,aAAoB;CACtB,SAAS;CACT,OAAO;AACT,CAAC,CACH;AACA,MAAa,WAAW,UACtB,MAAM,OAAO,SAAS,cAAc,MAAM,OAAO,SAAS"}
|
package/dist/internal/config.mjs
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { InvalidInput } from "../Reason.mjs";
|
|
2
|
-
import { DomainKitError } from "./error.mjs";
|
|
3
|
-
import { Config, Effect } from "effect";
|
|
2
|
+
import { DomainKitError, fail } from "./error.mjs";
|
|
3
|
+
import { Config, Effect, Redacted } from "effect";
|
|
4
4
|
//#region src/internal/config.ts
|
|
5
5
|
/** Accept a literal or a `Config`; config failures surface as `InvalidInput` on `field`. */
|
|
6
|
-
const resolve = (value, field) => Config.isConfig(value) ? value.pipe(Effect.mapError((
|
|
7
|
-
message:
|
|
6
|
+
const resolve = (value, field) => Config.isConfig(value) ? value.pipe(Effect.mapError(() => new DomainKitError({ reason: new InvalidInput({
|
|
7
|
+
message: `Could not resolve ${field}`,
|
|
8
8
|
field
|
|
9
9
|
}) }))) : Effect.succeed(value);
|
|
10
|
+
/** Configuration diagnostics name the field, never the rejected value. */
|
|
11
|
+
const requireValue = (value, valid, field, message) => Effect.suspend(() => valid(value) ? Effect.succeed(value) : fail(new InvalidInput({
|
|
12
|
+
field,
|
|
13
|
+
message
|
|
14
|
+
})));
|
|
15
|
+
const nonempty = (value, field) => requireValue(value, (v) => typeof v === "string" && v.trim().length > 0, field, `${field} must be a nonempty string`);
|
|
16
|
+
const secret = (value, field) => requireValue(value, (v) => Redacted.isRedacted(v) && typeof Redacted.value(v) === "string" && Redacted.value(v).trim().length > 0, field, `${field} must be a nonempty Redacted string`);
|
|
17
|
+
/** Paths and split emulator origins are supported; URL suffixes must remain paths. */
|
|
18
|
+
const endpoint = (value, field) => requireValue(value, (v) => {
|
|
19
|
+
if (typeof v !== "string" || v !== v.trim() || [...v].some((character) => character.charCodeAt(0) < 32)) return false;
|
|
20
|
+
const url = URL.parse(v);
|
|
21
|
+
return url !== null && (url.protocol === "https:" || url.protocol === "http:") && url.username === "" && url.password === "" && !url.href.includes("?") && !url.href.includes("#");
|
|
22
|
+
}, field, `${field} must be an HTTP(S) URL without surrounding whitespace, control characters, credentials, query, or fragment`);
|
|
23
|
+
const scopes = (value, field) => requireValue(value, (v) => Array.isArray(v) && v.every((scope) => typeof scope === "string" && /^[\x21\x23-\x5B\x5D-\x7E]+$/.test(scope)), field, `${field} must contain valid OAuth scope tokens`);
|
|
10
24
|
//#endregion
|
|
11
|
-
export { resolve };
|
|
25
|
+
export { endpoint, nonempty, requireValue, resolve, scopes, secret };
|
|
12
26
|
|
|
13
27
|
//# sourceMappingURL=config.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":["Errors.DomainKitError","Reason.InvalidInput"],"sources":["../../src/internal/config.ts"],"sourcesContent":["import { Config, Effect } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\n\n/** Accept a literal or a `Config`; config failures surface as `InvalidInput` on `field`. */\nexport const resolve = <A>(\n value: A | Config.Config<A>,\n field: string,\n): Effect.Effect<A, Errors.DomainKitError> =>\n Config.isConfig(value)\n ? value.pipe(\n Effect.mapError(\n (
|
|
1
|
+
{"version":3,"file":"config.mjs","names":["Errors.DomainKitError","Reason.InvalidInput","Errors.fail"],"sources":["../../src/internal/config.ts"],"sourcesContent":["import { Config, Effect, Redacted } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\n\n/** Accept a literal or a `Config`; config failures surface as `InvalidInput` on `field`. */\nexport const resolve = <A>(\n value: A | Config.Config<A>,\n field: string,\n): Effect.Effect<A, Errors.DomainKitError> =>\n Config.isConfig(value)\n ? value.pipe(\n Effect.mapError(\n () =>\n new Errors.DomainKitError({\n reason: new Reason.InvalidInput({ message: `Could not resolve ${field}`, field }),\n }),\n ),\n )\n : Effect.succeed(value);\n\n/** Configuration diagnostics name the field, never the rejected value. */\nexport const requireValue = <A>(\n value: A,\n valid: (value: A) => boolean,\n field: string,\n message: string,\n): Effect.Effect<A, Errors.DomainKitError> =>\n Effect.suspend(() =>\n valid(value) ? Effect.succeed(value) : Errors.fail(new Reason.InvalidInput({ field, message })),\n );\n\nexport const nonempty = (value: string, field: string) =>\n requireValue(\n value,\n (v) => typeof v === \"string\" && v.trim().length > 0,\n field,\n `${field} must be a nonempty string`,\n );\n\nexport const secret = (value: Redacted.Redacted<string>, field: string) =>\n requireValue(\n value,\n (v) =>\n Redacted.isRedacted(v) &&\n typeof Redacted.value(v) === \"string\" &&\n Redacted.value(v).trim().length > 0,\n field,\n `${field} must be a nonempty Redacted string`,\n );\n\n/** Paths and split emulator origins are supported; URL suffixes must remain paths. */\nexport const endpoint = (value: string, field: string) =>\n requireValue(\n value,\n (v) => {\n if (\n typeof v !== \"string\" ||\n v !== v.trim() ||\n [...v].some((character) => character.charCodeAt(0) < 0x20)\n )\n return false;\n const url = URL.parse(v);\n return (\n url !== null &&\n (url.protocol === \"https:\" || url.protocol === \"http:\") &&\n url.username === \"\" &&\n url.password === \"\" &&\n !url.href.includes(\"?\") &&\n !url.href.includes(\"#\")\n );\n },\n field,\n `${field} must be an HTTP(S) URL without surrounding whitespace, control characters, credentials, query, or fragment`,\n );\n\nexport const scopes = (value: ReadonlyArray<string>, field: string) =>\n requireValue(\n value,\n (v) =>\n Array.isArray(v) &&\n v.every((scope) => typeof scope === \"string\" && /^[\\x21\\x23-\\x5B\\x5D-\\x7E]+$/.test(scope)),\n field,\n `${field} must contain valid OAuth scope tokens`,\n );\n"],"mappings":";;;;;AAMA,MAAa,WACX,OACA,UAEA,OAAO,SAAS,KAAK,IACjB,MAAM,KACJ,OAAO,eAEH,IAAIA,eAAsB,EACxB,QAAQ,IAAIC,aAAoB;CAAE,SAAS,qBAAqB;CAAS;AAAM,CAAC,EAClF,CAAC,CACL,CACF,IACA,OAAO,QAAQ,KAAK;;AAG1B,MAAa,gBACX,OACA,OACA,OACA,YAEA,OAAO,cACL,MAAM,KAAK,IAAI,OAAO,QAAQ,KAAK,IAAIC,KAAY,IAAID,aAAoB;CAAE;CAAO;AAAQ,CAAC,CAAC,CAChG;AAEF,MAAa,YAAY,OAAe,UACtC,aACE,QACC,MAAM,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,CAAC,SAAS,GAClD,OACA,GAAG,MAAM,2BACX;AAEF,MAAa,UAAU,OAAkC,UACvD,aACE,QACC,MACC,SAAS,WAAW,CAAC,KACrB,OAAO,SAAS,MAAM,CAAC,MAAM,YAC7B,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GACpC,OACA,GAAG,MAAM,oCACX;;AAGF,MAAa,YAAY,OAAe,UACtC,aACE,QACC,MAAM;CACL,IACE,OAAO,MAAM,YACb,MAAM,EAAE,KAAK,KACb,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,cAAc,UAAU,WAAW,CAAC,IAAI,EAAI,GAEzD,OAAO;CACT,MAAM,MAAM,IAAI,MAAM,CAAC;CACvB,OACE,QAAQ,SACP,IAAI,aAAa,YAAY,IAAI,aAAa,YAC/C,IAAI,aAAa,MACjB,IAAI,aAAa,MACjB,CAAC,IAAI,KAAK,SAAS,GAAG,KACtB,CAAC,IAAI,KAAK,SAAS,GAAG;AAE1B,GACA,OACA,GAAG,MAAM,4GACX;AAEF,MAAa,UAAU,OAA8B,UACnD,aACE,QACC,MACC,MAAM,QAAQ,CAAC,KACf,EAAE,OAAO,UAAU,OAAO,UAAU,YAAY,8BAA8B,KAAK,KAAK,CAAC,GAC3F,OACA,GAAG,MAAM,uCACX"}
|
|
@@ -60,6 +60,7 @@ const fromAsync = (definition) => {
|
|
|
60
60
|
}) },
|
|
61
61
|
...oauth === void 0 ? {} : { oauth: {
|
|
62
62
|
label: oauth.label,
|
|
63
|
+
...oauth.registration === void 0 ? {} : { registration: oauth.registration },
|
|
63
64
|
scopes: oauth.scopes,
|
|
64
65
|
start: (input) => call(() => oauth.start(input)),
|
|
65
66
|
complete: (input) => call(() => oauth.complete(input)).pipe(Effect.map(issued)),
|
|
@@ -68,6 +69,7 @@ const fromAsync = (definition) => {
|
|
|
68
69
|
} },
|
|
69
70
|
...integration === void 0 ? {} : { integration: {
|
|
70
71
|
label: integration.label,
|
|
72
|
+
...integration.registration === void 0 ? {} : { registration: integration.registration },
|
|
71
73
|
start: (input) => call(() => integration.start(input)),
|
|
72
74
|
complete: (input) => call(() => integration.complete(input)).pipe(Effect.map(issued)),
|
|
73
75
|
...integrationRefresh === void 0 ? {} : { refresh: (credential) => call(() => integrationRefresh(plain(credential))).pipe(Effect.map(issued)) },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-async.mjs","names":["Errors.isDomainKitError","Errors.DomainKitError","Reason.ProviderUnavailable","Provider.make","Provider.tokenAuth"],"sources":["../../src/internal/provider-async.ts"],"sourcesContent":["import { DateTime, Effect, Redacted, type Schema } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport type * as DnsRecord from \"../DnsRecord.ts\";\nimport * as Provider from \"../Provider.ts\";\nimport type { Capability } from \"../Storage.ts\";\n\n/** Plain-object credential for Promise-shaped providers; `secret` is the raw string. */\nexport interface AsyncCredential {\n readonly secret: string;\n readonly context: unknown;\n}\n\nexport interface AsyncIssuedCredential extends AsyncCredential {\n readonly expiresAt: Date | null;\n}\n\nexport interface AsyncDns {\n readonly list: (zone: string) => Promise<ReadonlyArray<Provider.ObservedRecord>>;\n readonly create: (\n zone: string,\n record: DnsRecord.Model,\n ) => Promise<{ readonly providerRecordId: string }>;\n readonly get: (zone: string, providerRecordId: string) => Promise<DnsRecord.Observed | null>;\n readonly delete: (zone: string, providerRecordId: string) => Promise<void>;\n}\n\nexport interface AsyncSession {\n readonly listTargets: () => Promise<ReadonlyArray<Provider.Target>>;\n readonly resolveTarget: (domain: string) => Promise<Provider.Resolution>;\n readonly dns: (target: Provider.Target) => AsyncDns;\n readonly capabilities: () => Promise<ReadonlyArray<Capability>>;\n}\n\nexport interface AsyncTokenAuth {\n readonly label: string;\n readonly docsUrl?: string;\n readonly requiredCapabilities: ReadonlyArray<Capability>;\n readonly fields: Schema.Struct<Provider.TokenFieldSchemas>;\n /** Decoded field values with secrets unwrapped to strings. */\n readonly authenticate: (\n values: Readonly<Record<string, string | undefined>>,\n ) => Promise<AsyncIssuedCredential>;\n}\n\nexport interface AsyncOAuthAuth {\n readonly label: string;\n readonly scopes: ReadonlyArray<string>;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n readonly codeChallenge: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (\n input: Provider.CallbackInput & { readonly codeVerifier: string },\n ) => Promise<AsyncIssuedCredential>;\n readonly refresh: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\nexport interface AsyncIntegrationAuth {\n readonly label: string;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (input: Provider.CallbackInput) => Promise<AsyncIssuedCredential>;\n readonly refresh?: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\n/** `Provider.Definition` with every operation returning a Promise. */\nexport interface AsyncDefinition<Context = unknown> {\n readonly id: string;\n readonly name: string;\n readonly auth: {\n readonly token?: AsyncTokenAuth;\n readonly oauth?: AsyncOAuthAuth;\n readonly integration?: AsyncIntegrationAuth;\n };\n readonly context: Schema.Codec<Context, unknown, never, never>;\n readonly contextVersion: string;\n readonly migrateContext?: (envelope: Provider.Envelope) => Promise<Context>;\n readonly session: (credential: AsyncCredential) => AsyncSession;\n}\n\nconst failure = (provider: string) => (cause: unknown) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider,\n message: cause instanceof Error ? cause.message : `${provider} request failed`,\n }),\n });\n\nconst issued = (value: AsyncIssuedCredential): Provider.IssuedCredential => ({\n secret: Redacted.make(value.secret),\n context: value.context,\n expiresAt: value.expiresAt === null ? null : DateTime.fromDateUnsafe(value.expiresAt),\n});\n\nconst plain = (credential: Provider.Credential): AsyncCredential => ({\n secret: Redacted.value(credential.secret),\n context: credential.context,\n});\n\n/** Adapt a Promise-shaped provider; rejections become `DomainKit.Error` (a thrown one passes through). */\nexport const fromAsync = <Context>(\n definition: AsyncDefinition<Context>,\n): Provider.Definition<Context> => {\n const call = <A>(run: () => Promise<A>): Provider.Fx<A> =>\n Effect.tryPromise({ try: run, catch: failure(definition.id) });\n const dns = (target: Provider.Target, inner: AsyncDns): Provider.Dns => ({\n list: (zone) => call(() => inner.list(zone)),\n create: (zone, record) => call(() => inner.create(zone, record)),\n get: (zone, providerRecordId) => call(() => inner.get(zone, providerRecordId)),\n delete: (zone, providerRecordId) => call(() => inner.delete(zone, providerRecordId)),\n });\n const session = (credential: Provider.Credential): Provider.Session => {\n const inner = definition.session(plain(credential));\n return {\n listTargets: () => call(() => inner.listTargets()),\n resolveTarget: (domain) => call(() => inner.resolveTarget(domain)),\n capabilities: () => call(() => inner.capabilities()),\n dns: (target) => dns(target, inner.dns(target)),\n };\n };\n const token = definition.auth.token;\n const oauth = definition.auth.oauth;\n const integration = definition.auth.integration;\n const migrate = definition.migrateContext;\n const oauthRevoke = oauth?.revoke;\n const integrationRefresh = integration?.refresh;\n const integrationRevoke = integration?.revoke;\n return Provider.make<Context>({\n id: definition.id,\n name: definition.name,\n context: definition.context,\n contextVersion: definition.contextVersion,\n ...(migrate === undefined\n ? {}\n : {\n migrateContext: (envelope: Provider.Envelope) => call(() => migrate(envelope)),\n }),\n auth: {\n ...(token === undefined\n ? {}\n : {\n token: Provider.tokenAuth({\n label: token.label,\n ...(token.docsUrl === undefined ? {} : { docsUrl: token.docsUrl }),\n requiredCapabilities: token.requiredCapabilities,\n fields: token.fields,\n authenticate: (values) =>\n call(() =>\n token.authenticate(\n Object.fromEntries(\n Object.entries(values as Record<string, unknown>).map(([name, value]) => [\n name,\n Redacted.isRedacted(value)\n ? String(Redacted.value(value))\n : value === undefined\n ? undefined\n : String(value),\n ]),\n ),\n ),\n ).pipe(Effect.map(issued)),\n }),\n }),\n ...(oauth === undefined\n ? {}\n : {\n oauth: {\n label: oauth.label,\n scopes: oauth.scopes,\n start: (input) => call(() => oauth.start(input)),\n complete: (input) => call(() => oauth.complete(input)).pipe(Effect.map(issued)),\n refresh: (credential) =>\n call(() => oauth.refresh(plain(credential))).pipe(Effect.map(issued)),\n ...(oauthRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => oauthRevoke(plain(credential))),\n }),\n } satisfies Provider.OAuthAuth,\n }),\n ...(integration === undefined\n ? {}\n : {\n integration: {\n label: integration.label,\n start: (input) => call(() => integration.start(input)),\n complete: (input) => call(() => integration.complete(input)).pipe(Effect.map(issued)),\n ...(integrationRefresh === undefined\n ? {}\n : {\n refresh: (credential: Provider.Credential) =>\n call(() => integrationRefresh(plain(credential))).pipe(Effect.map(issued)),\n }),\n ...(integrationRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => integrationRevoke(plain(credential))),\n }),\n } satisfies Provider.IntegrationAuth,\n }),\n },\n session,\n });\n};\n"],"mappings":";;;;;AAuFA,MAAM,WAAW,cAAsB,UACrCA,iBAAwB,KAAK,IACzB,QACA,IAAIC,eAAsB,EACxB,QAAQ,IAAIC,oBAA2B;CACrC;CACA,SAAS,iBAAiB,QAAQ,MAAM,UAAU,GAAG,SAAS;AAChE,CAAC,EACH,CAAC;AAEP,MAAM,UAAU,WAA6D;CAC3E,QAAQ,SAAS,KAAK,MAAM,MAAM;CAClC,SAAS,MAAM;CACf,WAAW,MAAM,cAAc,OAAO,OAAO,SAAS,eAAe,MAAM,SAAS;AACtF;AAEA,MAAM,SAAS,gBAAsD;CACnE,QAAQ,SAAS,MAAM,WAAW,MAAM;CACxC,SAAS,WAAW;AACtB;;AAGA,MAAa,aACX,eACiC;CACjC,MAAM,QAAW,QACf,OAAO,WAAW;EAAE,KAAK;EAAK,OAAO,QAAQ,WAAW,EAAE;CAAE,CAAC;CAC/D,MAAM,OAAO,QAAyB,WAAmC;EACvE,OAAO,SAAS,WAAW,MAAM,KAAK,IAAI,CAAC;EAC3C,SAAS,MAAM,WAAW,WAAW,MAAM,OAAO,MAAM,MAAM,CAAC;EAC/D,MAAM,MAAM,qBAAqB,WAAW,MAAM,IAAI,MAAM,gBAAgB,CAAC;EAC7E,SAAS,MAAM,qBAAqB,WAAW,MAAM,OAAO,MAAM,gBAAgB,CAAC;CACrF;CACA,MAAM,WAAW,eAAsD;EACrE,MAAM,QAAQ,WAAW,QAAQ,MAAM,UAAU,CAAC;EAClD,OAAO;GACL,mBAAmB,WAAW,MAAM,YAAY,CAAC;GACjD,gBAAgB,WAAW,WAAW,MAAM,cAAc,MAAM,CAAC;GACjE,oBAAoB,WAAW,MAAM,aAAa,CAAC;GACnD,MAAM,WAAW,IAAI,QAAQ,MAAM,IAAI,MAAM,CAAC;EAChD;CACF;CACA,MAAM,QAAQ,WAAW,KAAK;CAC9B,MAAM,QAAQ,WAAW,KAAK;CAC9B,MAAM,cAAc,WAAW,KAAK;CACpC,MAAM,UAAU,WAAW;CAC3B,MAAM,cAAc,OAAO;CAC3B,MAAM,qBAAqB,aAAa;CACxC,MAAM,oBAAoB,aAAa;CACvC,OAAOC,KAAuB;EAC5B,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,gBAAgB,WAAW;EAC3B,GAAI,YAAY,KAAA,IACZ,CAAC,IACD,EACE,iBAAiB,aAAgC,WAAW,QAAQ,QAAQ,CAAC,EAC/E;EACJ,MAAM;GACJ,GAAI,UAAU,KAAA,IACV,CAAC,IACD,EACE,OAAOC,UAAmB;IACxB,OAAO,MAAM;IACb,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;IAChE,sBAAsB,MAAM;IAC5B,QAAQ,MAAM;IACd,eAAe,WACb,WACE,MAAM,aACJ,OAAO,YACL,OAAO,QAAQ,MAAiC,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CACvE,MACA,SAAS,WAAW,KAAK,IACrB,OAAO,SAAS,MAAM,KAAK,CAAC,IAC5B,UAAU,KAAA,IACR,KAAA,IACA,OAAO,KAAK,CACpB,CAAC,CACH,CACF,CACF,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC;GAC7B,CAAC,EACH;GACJ,GAAI,UAAU,KAAA,IACV,CAAC,IACD,EACE,OAAO;IACL,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,QAAQ,UAAU,WAAW,MAAM,MAAM,KAAK,CAAC;IAC/C,WAAW,UAAU,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC;IAC9E,UAAU,eACR,WAAW,MAAM,QAAQ,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC;IACtE,GAAI,gBAAgB,KAAA,IAChB,CAAC,IACD,EACE,SAAS,eACP,WAAW,YAAY,MAAM,UAAU,CAAC,CAAC,EAC7C;GACN,EACF;GACJ,GAAI,gBAAgB,KAAA,IAChB,CAAC,IACD,EACE,aAAa;IACX,OAAO,YAAY;IACnB,QAAQ,UAAU,WAAW,YAAY,MAAM,KAAK,CAAC;IACrD,WAAW,UAAU,WAAW,YAAY,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC;IACpF,GAAI,uBAAuB,KAAA,IACvB,CAAC,IACD,EACE,UAAU,eACR,WAAW,mBAAmB,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC,EAC7E;IACJ,GAAI,sBAAsB,KAAA,IACtB,CAAC,IACD,EACE,SAAS,eACP,WAAW,kBAAkB,MAAM,UAAU,CAAC,CAAC,EACnD;GACN,EACF;EACN;EACA;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"provider-async.mjs","names":["Errors.isDomainKitError","Errors.DomainKitError","Reason.ProviderUnavailable","Provider.make","Provider.tokenAuth"],"sources":["../../src/internal/provider-async.ts"],"sourcesContent":["import { DateTime, Effect, Redacted, type Schema } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport type * as DnsRecord from \"../DnsRecord.ts\";\nimport * as Provider from \"../Provider.ts\";\nimport type { Capability } from \"../Storage.ts\";\n\n/** Plain-object credential for Promise-shaped providers; `secret` is the raw string. */\nexport interface AsyncCredential {\n readonly secret: string;\n readonly context: unknown;\n}\n\nexport interface AsyncIssuedCredential extends AsyncCredential {\n readonly expiresAt: Date | null;\n}\n\nexport interface AsyncDns {\n readonly list: (zone: string) => Promise<ReadonlyArray<Provider.ObservedRecord>>;\n readonly create: (\n zone: string,\n record: DnsRecord.Model,\n ) => Promise<{ readonly providerRecordId: string }>;\n readonly get: (zone: string, providerRecordId: string) => Promise<DnsRecord.Observed | null>;\n readonly delete: (zone: string, providerRecordId: string) => Promise<void>;\n}\n\nexport interface AsyncSession {\n readonly listTargets: () => Promise<ReadonlyArray<Provider.Target>>;\n readonly resolveTarget: (domain: string) => Promise<Provider.Resolution>;\n readonly dns: (target: Provider.Target) => AsyncDns;\n readonly capabilities: () => Promise<ReadonlyArray<Capability>>;\n}\n\nexport interface AsyncTokenAuth {\n readonly label: string;\n readonly docsUrl?: string;\n readonly requiredCapabilities: ReadonlyArray<Capability>;\n readonly fields: Schema.Struct<Provider.TokenFieldSchemas>;\n /** Decoded field values with secrets unwrapped to strings. */\n readonly authenticate: (\n values: Readonly<Record<string, string | undefined>>,\n ) => Promise<AsyncIssuedCredential>;\n}\n\nexport interface AsyncOAuthAuth {\n readonly registration?: Provider.OAuthAuth[\"registration\"];\n readonly label: string;\n readonly scopes: ReadonlyArray<string>;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n readonly codeChallenge: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (\n input: Provider.CallbackInput & { readonly codeVerifier: string },\n ) => Promise<AsyncIssuedCredential>;\n readonly refresh: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\nexport interface AsyncIntegrationAuth {\n readonly registration?: Provider.IntegrationAuth[\"registration\"];\n readonly label: string;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (input: Provider.CallbackInput) => Promise<AsyncIssuedCredential>;\n readonly refresh?: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\n/** `Provider.Definition` with every operation returning a Promise. */\nexport interface AsyncDefinition<Context = unknown> {\n readonly id: string;\n readonly name: string;\n readonly auth: {\n readonly token?: AsyncTokenAuth;\n readonly oauth?: AsyncOAuthAuth;\n readonly integration?: AsyncIntegrationAuth;\n };\n readonly context: Schema.Codec<Context, unknown, never, never>;\n readonly contextVersion: string;\n readonly migrateContext?: (envelope: Provider.Envelope) => Promise<Context>;\n readonly session: (credential: AsyncCredential) => AsyncSession;\n}\n\nconst failure = (provider: string) => (cause: unknown) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider,\n message: cause instanceof Error ? cause.message : `${provider} request failed`,\n }),\n });\n\nconst issued = (value: AsyncIssuedCredential): Provider.IssuedCredential => ({\n secret: Redacted.make(value.secret),\n context: value.context,\n expiresAt: value.expiresAt === null ? null : DateTime.fromDateUnsafe(value.expiresAt),\n});\n\nconst plain = (credential: Provider.Credential): AsyncCredential => ({\n secret: Redacted.value(credential.secret),\n context: credential.context,\n});\n\n/** Adapt a Promise-shaped provider; rejections become `DomainKit.Error` (a thrown one passes through). */\nexport const fromAsync = <Context>(\n definition: AsyncDefinition<Context>,\n): Provider.Definition<Context> => {\n const call = <A>(run: () => Promise<A>): Provider.Fx<A> =>\n Effect.tryPromise({ try: run, catch: failure(definition.id) });\n const dns = (target: Provider.Target, inner: AsyncDns): Provider.Dns => ({\n list: (zone) => call(() => inner.list(zone)),\n create: (zone, record) => call(() => inner.create(zone, record)),\n get: (zone, providerRecordId) => call(() => inner.get(zone, providerRecordId)),\n delete: (zone, providerRecordId) => call(() => inner.delete(zone, providerRecordId)),\n });\n const session = (credential: Provider.Credential): Provider.Session => {\n const inner = definition.session(plain(credential));\n return {\n listTargets: () => call(() => inner.listTargets()),\n resolveTarget: (domain) => call(() => inner.resolveTarget(domain)),\n capabilities: () => call(() => inner.capabilities()),\n dns: (target) => dns(target, inner.dns(target)),\n };\n };\n const token = definition.auth.token;\n const oauth = definition.auth.oauth;\n const integration = definition.auth.integration;\n const migrate = definition.migrateContext;\n const oauthRevoke = oauth?.revoke;\n const integrationRefresh = integration?.refresh;\n const integrationRevoke = integration?.revoke;\n return Provider.make<Context>({\n id: definition.id,\n name: definition.name,\n context: definition.context,\n contextVersion: definition.contextVersion,\n ...(migrate === undefined\n ? {}\n : {\n migrateContext: (envelope: Provider.Envelope) => call(() => migrate(envelope)),\n }),\n auth: {\n ...(token === undefined\n ? {}\n : {\n token: Provider.tokenAuth({\n label: token.label,\n ...(token.docsUrl === undefined ? {} : { docsUrl: token.docsUrl }),\n requiredCapabilities: token.requiredCapabilities,\n fields: token.fields,\n authenticate: (values) =>\n call(() =>\n token.authenticate(\n Object.fromEntries(\n Object.entries(values as Record<string, unknown>).map(([name, value]) => [\n name,\n Redacted.isRedacted(value)\n ? String(Redacted.value(value))\n : value === undefined\n ? undefined\n : String(value),\n ]),\n ),\n ),\n ).pipe(Effect.map(issued)),\n }),\n }),\n ...(oauth === undefined\n ? {}\n : {\n oauth: {\n label: oauth.label,\n ...(oauth.registration === undefined ? {} : { registration: oauth.registration }),\n scopes: oauth.scopes,\n start: (input) => call(() => oauth.start(input)),\n complete: (input) => call(() => oauth.complete(input)).pipe(Effect.map(issued)),\n refresh: (credential) =>\n call(() => oauth.refresh(plain(credential))).pipe(Effect.map(issued)),\n ...(oauthRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => oauthRevoke(plain(credential))),\n }),\n } satisfies Provider.OAuthAuth,\n }),\n ...(integration === undefined\n ? {}\n : {\n integration: {\n label: integration.label,\n ...(integration.registration === undefined\n ? {}\n : { registration: integration.registration }),\n start: (input) => call(() => integration.start(input)),\n complete: (input) => call(() => integration.complete(input)).pipe(Effect.map(issued)),\n ...(integrationRefresh === undefined\n ? {}\n : {\n refresh: (credential: Provider.Credential) =>\n call(() => integrationRefresh(plain(credential))).pipe(Effect.map(issued)),\n }),\n ...(integrationRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => integrationRevoke(plain(credential))),\n }),\n } satisfies Provider.IntegrationAuth,\n }),\n },\n session,\n });\n};\n"],"mappings":"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"}
|
package/dist/package.mjs
CHANGED
package/dist/types/Connect.d.ts
CHANGED
|
@@ -233,6 +233,113 @@ export declare const Started: {
|
|
|
233
233
|
readonly candidates: ReadonlyArray<Provider.Target>;
|
|
234
234
|
}, "_tag">;
|
|
235
235
|
};
|
|
236
|
+
/** A verified completion result. Errors stay on the server; do not serialize them to a browser. */
|
|
237
|
+
export type Completion = Data.TaggedEnum<{
|
|
238
|
+
Connected: {
|
|
239
|
+
readonly started: Exclude<Started, {
|
|
240
|
+
readonly _tag: "Redirect";
|
|
241
|
+
}>;
|
|
242
|
+
};
|
|
243
|
+
Cancelled: {
|
|
244
|
+
readonly error: Errors.DomainKitError;
|
|
245
|
+
};
|
|
246
|
+
Failed: {
|
|
247
|
+
readonly error: Errors.DomainKitError;
|
|
248
|
+
readonly recovery: "restart" | "inspect";
|
|
249
|
+
};
|
|
250
|
+
}>;
|
|
251
|
+
export declare const Completion: {
|
|
252
|
+
readonly $is: <Tag extends "Cancelled" | "Connected" | "Failed">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
253
|
+
readonly _tag: "Cancelled";
|
|
254
|
+
readonly error: Errors.DomainKitError;
|
|
255
|
+
}, {
|
|
256
|
+
readonly _tag: Tag;
|
|
257
|
+
}> | Extract<{
|
|
258
|
+
readonly _tag: "Connected";
|
|
259
|
+
readonly started: Exclude<Started, {
|
|
260
|
+
readonly _tag: "Redirect";
|
|
261
|
+
}>;
|
|
262
|
+
}, {
|
|
263
|
+
readonly _tag: Tag;
|
|
264
|
+
}> | Extract<{
|
|
265
|
+
readonly _tag: "Failed";
|
|
266
|
+
readonly error: Errors.DomainKitError;
|
|
267
|
+
readonly recovery: "restart" | "inspect";
|
|
268
|
+
}, {
|
|
269
|
+
readonly _tag: Tag;
|
|
270
|
+
}>;
|
|
271
|
+
readonly $match: {
|
|
272
|
+
<Cases extends { readonly [Tag in "Cancelled" | "Connected" | "Failed"]: (args: Extract<{
|
|
273
|
+
readonly _tag: "Cancelled";
|
|
274
|
+
readonly error: Errors.DomainKitError;
|
|
275
|
+
} | {
|
|
276
|
+
readonly _tag: "Connected";
|
|
277
|
+
readonly started: Exclude<Started, {
|
|
278
|
+
readonly _tag: "Redirect";
|
|
279
|
+
}>;
|
|
280
|
+
} | {
|
|
281
|
+
readonly _tag: "Failed";
|
|
282
|
+
readonly error: Errors.DomainKitError;
|
|
283
|
+
readonly recovery: "restart" | "inspect";
|
|
284
|
+
}, {
|
|
285
|
+
readonly _tag: Tag;
|
|
286
|
+
}>) => any; }>(cases: Cases): (value: {
|
|
287
|
+
readonly _tag: "Cancelled";
|
|
288
|
+
readonly error: Errors.DomainKitError;
|
|
289
|
+
} | {
|
|
290
|
+
readonly _tag: "Connected";
|
|
291
|
+
readonly started: Exclude<Started, {
|
|
292
|
+
readonly _tag: "Redirect";
|
|
293
|
+
}>;
|
|
294
|
+
} | {
|
|
295
|
+
readonly _tag: "Failed";
|
|
296
|
+
readonly error: Errors.DomainKitError;
|
|
297
|
+
readonly recovery: "restart" | "inspect";
|
|
298
|
+
}) => import("effect/Unify").Unify<ReturnType<Cases["Cancelled" | "Connected" | "Failed"]>>;
|
|
299
|
+
<Cases extends { readonly [Tag in "Cancelled" | "Connected" | "Failed"]: (args: Extract<{
|
|
300
|
+
readonly _tag: "Cancelled";
|
|
301
|
+
readonly error: Errors.DomainKitError;
|
|
302
|
+
} | {
|
|
303
|
+
readonly _tag: "Connected";
|
|
304
|
+
readonly started: Exclude<Started, {
|
|
305
|
+
readonly _tag: "Redirect";
|
|
306
|
+
}>;
|
|
307
|
+
} | {
|
|
308
|
+
readonly _tag: "Failed";
|
|
309
|
+
readonly error: Errors.DomainKitError;
|
|
310
|
+
readonly recovery: "restart" | "inspect";
|
|
311
|
+
}, {
|
|
312
|
+
readonly _tag: Tag;
|
|
313
|
+
}>) => any; }>(value: {
|
|
314
|
+
readonly _tag: "Cancelled";
|
|
315
|
+
readonly error: Errors.DomainKitError;
|
|
316
|
+
} | {
|
|
317
|
+
readonly _tag: "Connected";
|
|
318
|
+
readonly started: Exclude<Started, {
|
|
319
|
+
readonly _tag: "Redirect";
|
|
320
|
+
}>;
|
|
321
|
+
} | {
|
|
322
|
+
readonly _tag: "Failed";
|
|
323
|
+
readonly error: Errors.DomainKitError;
|
|
324
|
+
readonly recovery: "restart" | "inspect";
|
|
325
|
+
}, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Cancelled" | "Connected" | "Failed"]>>;
|
|
326
|
+
};
|
|
327
|
+
readonly Cancelled: Data.TaggedEnum.ConstructorFrom<{
|
|
328
|
+
readonly _tag: "Cancelled";
|
|
329
|
+
readonly error: Errors.DomainKitError;
|
|
330
|
+
}, "_tag">;
|
|
331
|
+
readonly Connected: Data.TaggedEnum.ConstructorFrom<{
|
|
332
|
+
readonly _tag: "Connected";
|
|
333
|
+
readonly started: Exclude<Started, {
|
|
334
|
+
readonly _tag: "Redirect";
|
|
335
|
+
}>;
|
|
336
|
+
}, "_tag">;
|
|
337
|
+
readonly Failed: Data.TaggedEnum.ConstructorFrom<{
|
|
338
|
+
readonly _tag: "Failed";
|
|
339
|
+
readonly error: Errors.DomainKitError;
|
|
340
|
+
readonly recovery: "restart" | "inspect";
|
|
341
|
+
}, "_tag">;
|
|
342
|
+
};
|
|
236
343
|
/** `attach` either attached the domain or needs the caller to pick a zone. */
|
|
237
344
|
export type Selection = Data.TaggedEnum<{
|
|
238
345
|
SelectionRequired: {
|
|
@@ -477,6 +584,16 @@ export interface Interface {
|
|
|
477
584
|
readonly continuationId: string;
|
|
478
585
|
readonly callbackUrl: string;
|
|
479
586
|
}) => Fx<Started>;
|
|
587
|
+
/**
|
|
588
|
+
* Classify only after live owner/actor verification inside the completion lock. Optional
|
|
589
|
+
* `provider` binds the flow to a mounted route. Invalid flows fail without an outcome.
|
|
590
|
+
* Cancellation and failure leave the continuation retryable; persistence is not atomic.
|
|
591
|
+
*/
|
|
592
|
+
readonly completeOutcome: (input: {
|
|
593
|
+
readonly continuationId: string;
|
|
594
|
+
readonly callbackUrl: string;
|
|
595
|
+
readonly provider?: string;
|
|
596
|
+
}) => Fx<Completion>;
|
|
480
597
|
readonly attach: (input: {
|
|
481
598
|
readonly connectionId: string;
|
|
482
599
|
readonly domain: string;
|
|
@@ -586,6 +703,23 @@ export declare const complete: (input: {
|
|
|
586
703
|
readonly connection: Storage.Connection;
|
|
587
704
|
readonly candidates: ReadonlyArray<Provider.Target>;
|
|
588
705
|
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
706
|
+
export declare const completeOutcome: (input: {
|
|
707
|
+
readonly continuationId: string;
|
|
708
|
+
readonly callbackUrl: string;
|
|
709
|
+
readonly provider?: string;
|
|
710
|
+
}) => Effect.Effect<{
|
|
711
|
+
readonly _tag: "Cancelled";
|
|
712
|
+
readonly error: Errors.DomainKitError;
|
|
713
|
+
} | {
|
|
714
|
+
readonly _tag: "Connected";
|
|
715
|
+
readonly started: Exclude<Started, {
|
|
716
|
+
readonly _tag: "Redirect";
|
|
717
|
+
}>;
|
|
718
|
+
} | {
|
|
719
|
+
readonly _tag: "Failed";
|
|
720
|
+
readonly error: Errors.DomainKitError;
|
|
721
|
+
readonly recovery: "restart" | "inspect";
|
|
722
|
+
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
589
723
|
export declare const attach: (input: {
|
|
590
724
|
readonly connectionId: string;
|
|
591
725
|
readonly domain: string;
|
package/dist/types/Provider.d.ts
CHANGED
|
@@ -189,6 +189,11 @@ export interface CallbackInput {
|
|
|
189
189
|
readonly params: Readonly<Record<string, string>>;
|
|
190
190
|
}
|
|
191
191
|
export interface OAuthAuth {
|
|
192
|
+
/** Optional setup requirements; absence makes offline registration settings unsupported. */
|
|
193
|
+
readonly registration?: {
|
|
194
|
+
readonly clientAuth: "none" | "client_secret_basic" | "client_secret_post";
|
|
195
|
+
readonly pkce: "S256";
|
|
196
|
+
};
|
|
192
197
|
readonly label: string;
|
|
193
198
|
readonly scopes: ReadonlyArray<string>;
|
|
194
199
|
readonly start: (input: {
|
|
@@ -206,6 +211,10 @@ export interface OAuthAuth {
|
|
|
206
211
|
}
|
|
207
212
|
/** Marketplace-style installs (Vercel integrations) that redirect but are not OAuth. */
|
|
208
213
|
export interface IntegrationAuth {
|
|
214
|
+
/** Authentication used by the integration code exchange, without credentials. */
|
|
215
|
+
readonly registration?: {
|
|
216
|
+
readonly clientAuth: "client_secret_post";
|
|
217
|
+
};
|
|
209
218
|
readonly label: string;
|
|
210
219
|
readonly start: (input: {
|
|
211
220
|
readonly state: string;
|
package/dist/types/Server.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import * as DnsRecord from "./DnsRecord.ts";
|
|
|
24
24
|
import * as Errors from "./internal/error.ts";
|
|
25
25
|
import * as Plan from "./Plan.ts";
|
|
26
26
|
import * as Principal from "./Principal.ts";
|
|
27
|
+
import type * as Provider from "./Provider.ts";
|
|
27
28
|
import * as Providers from "./Providers.ts";
|
|
28
29
|
import * as Provision from "./Provision.ts";
|
|
29
30
|
import * as Reason from "./Reason.ts";
|
|
@@ -11393,6 +11394,23 @@ export declare const group: HttpApiGroup.HttpApiGroup<"domainkit", HttpApiEndpoi
|
|
|
11393
11394
|
export type Group = typeof group;
|
|
11394
11395
|
/** Every route in the group, by name; what `Identity.authorize` is asked about. */
|
|
11395
11396
|
export type EndpointName = HttpApiGroup.Endpoints<Group>["identifier"];
|
|
11397
|
+
/** Browser-safe summaries of an authenticated live callback. Connected is not DNS readiness. */
|
|
11398
|
+
export declare const CallbackOutcome: Schema.Union<readonly [Schema.Struct<{
|
|
11399
|
+
readonly _tag: Schema.Literal<"Connected">;
|
|
11400
|
+
readonly provider: Schema.String;
|
|
11401
|
+
readonly connectionId: Schema.String;
|
|
11402
|
+
readonly returnTo: Schema.String;
|
|
11403
|
+
}>, Schema.Struct<{
|
|
11404
|
+
readonly _tag: Schema.Literal<"Cancelled">;
|
|
11405
|
+
readonly provider: Schema.String;
|
|
11406
|
+
readonly returnTo: Schema.String;
|
|
11407
|
+
}>, Schema.Struct<{
|
|
11408
|
+
readonly _tag: Schema.Literal<"Failed">;
|
|
11409
|
+
readonly provider: Schema.String;
|
|
11410
|
+
readonly returnTo: Schema.String;
|
|
11411
|
+
readonly recovery: Schema.Literals<readonly ["restart", "inspect"]>;
|
|
11412
|
+
}>]>;
|
|
11413
|
+
export type CallbackOutcome = typeof CallbackOutcome.Type;
|
|
11396
11414
|
export interface Options {
|
|
11397
11415
|
/**
|
|
11398
11416
|
* Where the callback route is reachable from the provider, without the `/callback/:provider`
|
|
@@ -11401,7 +11419,34 @@ export interface Options {
|
|
|
11401
11419
|
readonly callbackBaseUrl?: string;
|
|
11402
11420
|
/** Where interactive flows return when the callback carries no `returnTo`. */
|
|
11403
11421
|
readonly defaultReturnTo?: string;
|
|
11422
|
+
/**
|
|
11423
|
+
* Opt in to a same-origin destination, or return undefined to keep default behavior. Invoked
|
|
11424
|
+
* only for a verified live flow; no request, state, code, secrets, or storage rows reach this
|
|
11425
|
+
* policy. Close over acquired host services; its Effect requires no environment.
|
|
11426
|
+
* A policy failure after Connected cannot undo persistence: inspect before restarting.
|
|
11427
|
+
*/
|
|
11428
|
+
readonly callback?: (outcome: CallbackOutcome) => Effect.Effect<string | undefined, Errors.DomainKitError>;
|
|
11404
11429
|
}
|
|
11430
|
+
/** Offline registration requirements, not proof of provider console or grant readiness. */
|
|
11431
|
+
export declare const RegistrationSettings: Schema.Union<readonly [Schema.Struct<{
|
|
11432
|
+
readonly _tag: Schema.Literal<"OAuth">;
|
|
11433
|
+
readonly provider: Schema.String;
|
|
11434
|
+
readonly callbackUrl: Schema.String;
|
|
11435
|
+
readonly clientAuth: Schema.Literals<readonly ["none", "client_secret_basic", "client_secret_post"]>;
|
|
11436
|
+
readonly pkce: Schema.Literal<"S256">;
|
|
11437
|
+
readonly scopes: Schema.$Array<Schema.String>;
|
|
11438
|
+
}>, Schema.Struct<{
|
|
11439
|
+
readonly _tag: Schema.Literal<"Integration">;
|
|
11440
|
+
readonly provider: Schema.String;
|
|
11441
|
+
readonly callbackUrl: Schema.String;
|
|
11442
|
+
readonly clientAuth: Schema.Literal<"client_secret_post">;
|
|
11443
|
+
}>]>;
|
|
11444
|
+
export type RegistrationSettings = typeof RegistrationSettings.Type;
|
|
11445
|
+
/** Derive only public setup values; no credentials, identity, storage, or network are needed. */
|
|
11446
|
+
export declare const registrationSettings: (input: {
|
|
11447
|
+
readonly providers: ReadonlyArray<Provider.Definition>;
|
|
11448
|
+
readonly callbackBaseUrl: string;
|
|
11449
|
+
}) => Effect.Effect<ReadonlyArray<RegistrationSettings>, Errors.DomainKitError>;
|
|
11405
11450
|
/** Everything the handlers need: the lifecycle services, Storage, and the host's `Identity`. */
|
|
11406
11451
|
export type Services = Provision.Service | Cleanup.Service | Connect.Service | Verify.Service | Providers.Service | Storage.Service | Identity;
|
|
11407
11452
|
/**
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as Errors from "./error.ts";
|
|
2
|
+
/** A leaked flow id must reveal neither existence nor ownership, including read races. */
|
|
3
|
+
export declare const refuse: import("effect/Effect").Effect<never, Errors.DomainKitError, never>;
|
|
4
|
+
export declare const missing: (error: Errors.DomainKitError) => boolean;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { Config, Effect } from "effect";
|
|
1
|
+
import { Config, Effect, Redacted } from "effect";
|
|
2
2
|
import * as Errors from "./error.ts";
|
|
3
3
|
/** Accept a literal or a `Config`; config failures surface as `InvalidInput` on `field`. */
|
|
4
4
|
export declare const resolve: <A>(value: A | Config.Config<A>, field: string) => Effect.Effect<A, Errors.DomainKitError>;
|
|
5
|
+
/** Configuration diagnostics name the field, never the rejected value. */
|
|
6
|
+
export declare const requireValue: <A>(value: A, valid: (value: A) => boolean, field: string, message: string) => Effect.Effect<A, Errors.DomainKitError>;
|
|
7
|
+
export declare const nonempty: (value: string, field: string) => Effect.Effect<string, Errors.DomainKitError, never>;
|
|
8
|
+
export declare const secret: (value: Redacted.Redacted<string>, field: string) => Effect.Effect<Redacted.Redacted<string>, Errors.DomainKitError, never>;
|
|
9
|
+
/** Paths and split emulator origins are supported; URL suffixes must remain paths. */
|
|
10
|
+
export declare const endpoint: (value: string, field: string) => Effect.Effect<string, Errors.DomainKitError, never>;
|
|
11
|
+
export declare const scopes: (value: ReadonlyArray<string>, field: string) => Effect.Effect<readonly string[], Errors.DomainKitError, never>;
|
|
@@ -33,6 +33,7 @@ export interface AsyncTokenAuth {
|
|
|
33
33
|
readonly authenticate: (values: Readonly<Record<string, string | undefined>>) => Promise<AsyncIssuedCredential>;
|
|
34
34
|
}
|
|
35
35
|
export interface AsyncOAuthAuth {
|
|
36
|
+
readonly registration?: Provider.OAuthAuth["registration"];
|
|
36
37
|
readonly label: string;
|
|
37
38
|
readonly scopes: ReadonlyArray<string>;
|
|
38
39
|
readonly start: (input: {
|
|
@@ -49,6 +50,7 @@ export interface AsyncOAuthAuth {
|
|
|
49
50
|
readonly revoke?: (credential: AsyncCredential) => Promise<void>;
|
|
50
51
|
}
|
|
51
52
|
export interface AsyncIntegrationAuth {
|
|
53
|
+
readonly registration?: Provider.IntegrationAuth["registration"];
|
|
52
54
|
readonly label: string;
|
|
53
55
|
readonly start: (input: {
|
|
54
56
|
readonly state: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domainkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Build reviewable DNS plans for custom domains in TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"custom-domains",
|
|
@@ -139,18 +139,18 @@
|
|
|
139
139
|
},
|
|
140
140
|
"dependencies": {
|
|
141
141
|
"@leichtgewicht/dns-packet": "6.0.3",
|
|
142
|
-
"oauth4webapi": "^3.8.
|
|
143
|
-
"tldts": "^7.4.
|
|
142
|
+
"oauth4webapi": "^3.8.8",
|
|
143
|
+
"tldts": "^7.4.18"
|
|
144
144
|
},
|
|
145
145
|
"devDependencies": {
|
|
146
|
-
"@effect/vitest": "4.0.
|
|
147
|
-
"@types/bun": "1.4.
|
|
148
|
-
"effect": "4.0.
|
|
146
|
+
"@effect/vitest": "4.0.2",
|
|
147
|
+
"@types/bun": "1.4.2",
|
|
148
|
+
"effect": "4.0.2",
|
|
149
149
|
"miniflare": "3.20250718.3",
|
|
150
|
-
"tsdown": "0.
|
|
150
|
+
"tsdown": "0.23.0",
|
|
151
151
|
"typescript": "7.0.2",
|
|
152
|
-
"vite": "
|
|
153
|
-
"vitest": "5.0.
|
|
152
|
+
"vite": "8.3.4",
|
|
153
|
+
"vitest": "5.0.3"
|
|
154
154
|
},
|
|
155
155
|
"peerDependencies": {
|
|
156
156
|
"effect": ">=4.0.0 <5.0.0"
|